Merge "Revert "Mark LimitOffsetPagingSourceTest#load_initialEmptyLoad as flaky"" into androidx-main
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 3a84153..83942af 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -9,6 +9,9 @@
- name: Compose Compiler
url: https://issuetracker.google.com/issues/new?component=610764&template=1424126
about: File a bug or feature request for Compose Compiler
+ - name: DataStore
+ url: https://issuetracker.google.com/issues/new?component=907884&template=1466542
+ about: File a bug or feature request for DataStore
- name: Fragment
url: https://issuetracker.google.com/issues/new?component=460964&template=1182267
about: File a bug or feature request for Fragment
diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml
index 9e8c1e7..7880114 100644
--- a/.github/workflows/presubmit.yml
+++ b/.github/workflows/presubmit.yml
@@ -19,6 +19,7 @@
-Dorg.gradle.internal.http.socketTimeout=300000 \
-Dorg.gradle.internal.repository.max.retries=10 \
-Dorg.gradle.internal.repository.initial.backoff=500 \
+ -Dorg.gradle.jvmargs="-XX:MaxMetaspaceSize=512m" \
--stacktrace"
echo "::set-output name=gradlew_flags::$GRADLEW_FLAGS"
- name: "Compute actions/checkout arguments"
@@ -112,10 +113,12 @@
fail-fast: false
matrix:
os: [ubuntu-latest]
- project: ["activity", "biometric", "compose-compiler", "fragment", "lifecycle", "navigation", "paging", "room", "work"]
+ project: ["activity", "biometric", "compose-compiler", "datastore", "fragment", "lifecycle", "navigation", "paging", "room", "work", "compose-runtime"]
include:
- project: "compose-compiler"
project-root: "compose/compiler"
+ - project: "compose-runtime"
+ project-root: "compose/runtime"
- project: "navigation"
custom-os: "macos-latest" # run one of them on a mac to ensure mac setup works
runs-on: ${{ matrix.custom-os || matrix.os }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 82015f1..0e45536 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,6 +12,8 @@
- [Activity](https://developer.android.com/guide/components/activities/intro-activities)
- [Biometric](https://developer.android.com/training/sign-in/biometric-auth)
- [Compose Compiler](https://developer.android.com/jetpack/androidx/releases/compose-compiler)
+ - [Compose Runtime](https://developer.android.com/jetpack/androidx/releases/compose-runtime)
+ - [DataStore](https://developer.android.com/topic/libraries/architecture/datastore)
- [Fragment](https://developer.android.com/guide/components/fragments)
- [Lifecycle](https://developer.android.com/topic/libraries/architecture/lifecycle)
- [Navigation](https://developer.android.com/guide/navigation)
@@ -50,6 +52,8 @@
-- activity
-- biometric
-- compose/compiler
+ -- compose/runtime
+ -- datastore
-- fragment
-- lifecycle
-- navigation
diff --git a/README.md b/README.md
index fe3ff30..21a5938 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,8 @@
* [Activity](activity)
* [Biometric](biometric)
* [Compose Compiler](compose/compiler)
+* [Compose Runtime](compose/runtime)
+* [DataStore](datastore)
* [Fragment](fragment)
* [Lifecycle](lifecycle)
* [Navigation](navigation)
@@ -115,6 +117,8 @@
maven { url '/path/to/checkout/out/androidx/build/support_repo/' }
```
+**NOTE: In order to see your changes in the project, you might need to clean your build (`Build > Clean Project` in Android Studio or run `./gradlew clean`).**
+
### Continuous integration
[Our continuous integration system](https://ci.android.com/builds/branches/aosp-androidx-main/grid?) builds all in progress (and potentially unstable) libraries as new changes are merged. You can manually download these AARs and JARs for your experimentation.
diff --git a/activity/activity-ktx/src/androidTest/AndroidManifest.xml b/activity/activity-ktx/src/androidTest/AndroidManifest.xml
index ee97faf..1bee49c 100644
--- a/activity/activity-ktx/src/androidTest/AndroidManifest.xml
+++ b/activity/activity-ktx/src/androidTest/AndroidManifest.xml
@@ -14,9 +14,13 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.activity.ktx">
+ package="androidx.activity.ktx">
<application>
- <activity android:name="androidx.activity.ActivityViewModelLazyTest$TestActivity"/>
- <activity android:name="androidx.activity.result.EmptyContentActivity" />
+ <activity
+ android:name="androidx.activity.ActivityViewModelLazyTest$TestActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.result.EmptyContentActivity"
+ android:exported="true" />
</application>
</manifest>
diff --git a/activity/activity/src/androidTest/AndroidManifest.xml b/activity/activity/src/androidTest/AndroidManifest.xml
index dc15880..8079d84 100644
--- a/activity/activity/src/androidTest/AndroidManifest.xml
+++ b/activity/activity/src/androidTest/AndroidManifest.xml
@@ -15,26 +15,58 @@
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.activity.test">
+ package="androidx.activity.test">
<application android:name="androidx.activity.LeakCanaryApp">
- <activity android:name="androidx.activity.LeakingActivity"
- android:windowSoftInputMode="stateVisible"/>
- <activity android:name="androidx.activity.LifecycleComponentActivity"/>
- <activity android:name="androidx.activity.EagerOverrideLifecycleComponentActivity"/>
- <activity android:name="androidx.activity.LazyOverrideLifecycleComponentActivity"/>
- <activity android:name="androidx.activity.ReportFullyDrawnActivity"/>
- <activity android:name="androidx.activity.ViewModelActivity"/>
- <activity android:name="androidx.activity.SavedStateActivity"/>
- <activity android:name="androidx.activity.ContentViewActivity"/>
- <activity android:name="androidx.activity.EmptyContentActivity" />
- <activity android:name="androidx.activity.AutoRestarterActivity"/>
- <activity android:name="androidx.activity.ResultComponentActivity"/>
- <activity android:name="androidx.activity.ResumeViewModelActivity" />
- <activity android:name="androidx.activity.PassThroughActivity"/>
- <activity android:name="androidx.activity.RegisterInInitActivity"/>
- <activity android:name="androidx.activity.RegisterBeforeOnCreateActivity"/>
- <activity android:name="androidx.activity.FinishActivity"/>
+ <activity
+ android:name="androidx.activity.LeakingActivity"
+ android:exported="true"
+ android:windowSoftInputMode="stateVisible" />
+ <activity
+ android:name="androidx.activity.LifecycleComponentActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.EagerOverrideLifecycleComponentActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.LazyOverrideLifecycleComponentActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.ReportFullyDrawnActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.ViewModelActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.SavedStateActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.ContentViewActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.EmptyContentActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.AutoRestarterActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.ResultComponentActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.ResumeViewModelActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.PassThroughActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.RegisterInInitActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.RegisterBeforeOnCreateActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.activity.FinishActivity"
+ android:exported="true" />
</application>
</manifest>
diff --git a/activity/integration-tests/testapp/src/main/AndroidManifest.xml b/activity/integration-tests/testapp/src/main/AndroidManifest.xml
index b801794..118cd0e 100644
--- a/activity/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/activity/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -18,29 +18,33 @@
xmlns:tools="http://schemas.android.com/tools"
package="androidx.activity.integration.testapp">
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-
<application tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon">
- <activity android:name="androidx.activity.integration.testapp.MainActivity">
+ <activity
+ android:name="androidx.activity.integration.testapp.MainActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="androidx.activity.integration.testapp.PipActivity"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:exported="true"
- android:supportsPictureInPicture="true"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/>
+ android:supportsPictureInPicture="true" />
+
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="androidx.activity.integration.testapp"
android:exported="false"
android:grantUriPermissions="true">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/file_paths" />
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
</provider>
</application>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
</manifest>
diff --git a/ads/ads-identifier-common/src/test/resources/robolectric.properties b/ads/ads-identifier-common/src/test/resources/robolectric.properties
index 3f2e0d0..5fad9a0 100644
--- a/ads/ads-identifier-common/src/test/resources/robolectric.properties
+++ b/ads/ads-identifier-common/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
\ No newline at end of file
+sdk=30
\ No newline at end of file
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/AndroidManifest.xml b/ads/ads-identifier-provider/integration-tests/testapp/src/main/AndroidManifest.xml
index 259681e..a4a7d73 100644
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/ads/ads-identifier-provider/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -10,7 +10,8 @@
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon">
<activity
- android:name=".AdsIdentifierProviderActivity">
+ android:name=".AdsIdentifierProviderActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/ads/ads-identifier/integration-tests/testapp/src/main/AndroidManifest.xml b/ads/ads-identifier/integration-tests/testapp/src/main/AndroidManifest.xml
index b9efcc2..d46213b 100644
--- a/ads/ads-identifier/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/ads/ads-identifier/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -8,7 +8,8 @@
android:label="@string/app_name"
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon">
<activity
- android:name=".AdsIdentifierActivity">
+ android:name=".AdsIdentifierActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/androidx-plugin/build.gradle b/androidx-plugin/build.gradle
index 670809d..1b78748 100644
--- a/androidx-plugin/build.gradle
+++ b/androidx-plugin/build.gradle
@@ -3,6 +3,7 @@
buildscript {
repositories {
google()
+ mavenCentral()
maven {
url("https://androidx.dev/dokka/builds/7299536/artifacts/repository")
metadataSources {
@@ -23,15 +24,16 @@
repositories {
google()
mavenCentral()
+ gradlePluginPortal()
maven {
- url("https://androidx.dev/metalava/builds/7255182/artifacts/repo/m2repository")
+ url("https://androidx.dev/metalava/builds/7610917/artifacts/repo/m2repository")
metadataSources {
mavenPom()
artifact()
}
}
maven {
- url("https://androidx.dev/dokka/builds/7299536/artifacts/repository")
+ url("https://androidx.dev/dokka/builds/7472101/artifacts/repository")
metadataSources {
mavenPom()
artifact()
diff --git a/androidx-plugin/gradle-plugin/build.gradle b/androidx-plugin/gradle-plugin/build.gradle
index a6a274b..687e5c6 100644
--- a/androidx-plugin/gradle-plugin/build.gradle
+++ b/androidx-plugin/gradle-plugin/build.gradle
@@ -17,12 +17,12 @@
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${libs.versions.kotlin.get()}")
- implementation(libs.androidGradlePlugin)
+ implementation(libs.androidGradlePluginz)
implementation(libs.dexMemberList)
- implementation(libs.kotlinGradlePlugin)
+ implementation(libs.kotlinGradlePluginz)
implementation(libs.kotlinPoet)
- implementation(libs.dokkaGradlePlugin)
+ implementation(libs.dokkaGradlePluginz)
implementation(libs.gson)
implementation(libs.androidLint)
@@ -30,14 +30,17 @@
// Not really sure about these:
implementation("com.googlecode.json-simple:json-simple:1.1")
implementation("androidx.benchmark:benchmark-gradle-plugin:1.0.0")
- implementation(libs.protobufGradlePlugin)
+ implementation(libs.protobufGradlePluginz)
implementation(libs.shadow)
- implementation(libs.wireGradlePlugin)
+ implementation(libs.wireGradlePluginz)
testImplementation(libs.junit)
}
sourceSets {
- main.java.srcDirs += "${supportRootFolder}/buildSrc/src/main/kotlin"
+ ["public", "private", "plugins"].each { subdir ->
+ main.java.srcDirs += "${supportRootFolder}/buildSrc/${subdir}/src/main/kotlin"
+ }
+
main.java.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main/kotlin"
test.java.srcDirs += "${supportRootFolder}/buildSrc-tests/src/test/kotlin"
main.resources.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main/resources"
diff --git a/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml b/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml
index 6e79778..20510a5 100644
--- a/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml
+++ b/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha03" type="baseline" client="gradle" name="AGP (7.1.0-alpha03)" variant="all" version="7.1.0-alpha03">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
<issue
id="ExperimentalAnnotationRetention"
@@ -180,6 +180,17 @@
<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
+ errorLine1=" return experimentalObject.field;"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/sample/optin/UseJavaExperimentalClassFromJava.java"
+ line="32"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" AnnotatedJavaClass experimentalObject = new AnnotatedJavaClass();"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -202,6 +213,17 @@
<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
+ errorLine1=" return AnnotatedJavaClass.FIELD_STATIC;"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="src/main/java/sample/optin/UseJavaExperimentalClassFromJava.java"
+ line="47"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" return AnnotatedJavaClass.methodStatic();"
errorLine2=" ~~~~~~~~~~~~">
<location
@@ -278,6 +300,28 @@
<issue
id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
+ errorLine1=" return experimentalObject.field"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/sample/optin/UseJavaExperimentalFromKt.kt"
+ line="29"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.experimental.ExperimentalDateTime` or `@OptIn(markerClass = sample.experimental.ExperimentalDateTime.class)`"
+ errorLine1=" return dateProvider.date"
+ errorLine2=" ~~~~">
+ <location
+ file="src/main/java/sample/experimental/UseJavaExperimentalFromKt.kt"
+ line="30"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.experimental.ExperimentalDateTime` or `@OptIn(markerClass = sample.experimental.ExperimentalDateTime.class)`"
errorLine1=" return dateProvider.date"
errorLine2=" ~~~~">
@@ -312,6 +356,17 @@
<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
+ errorLine1=" return AnnotatedJavaClass.FIELD_STATIC"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="src/main/java/sample/optin/UseJavaExperimentalFromKt.kt"
+ line="44"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" return AnnotatedJavaClass.methodStatic()"
errorLine2=" ~~~~~~~~~~~~">
<location
@@ -344,6 +399,17 @@
<issue
id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.experimental.ExperimentalLocation` or `@OptIn(markerClass = sample.experimental.ExperimentalLocation.class)`"
+ errorLine1=" return dateProvider.date + locationProvider.location"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="src/main/java/sample/experimental/UseJavaExperimentalFromKt.kt"
+ line="58"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" return stableObject.field"
errorLine2=" ~~~~~">
@@ -388,6 +454,17 @@
<issue
id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation2` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation2.class)`"
+ errorLine1=" return experimentalObject.method() + AnnotatedJavaClass2.FIELD_STATIC"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="src/main/java/sample/optin/UseJavaExperimentalFromKt.kt"
+ line="108"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" return stableObject.field;"
errorLine2=" ~~~~~">
@@ -443,6 +520,17 @@
<issue
id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation2` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation2.class)`"
+ errorLine1=" return experimentalObject.method() + experimentalObject2.field;"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/sample/optin/UseJavaExperimentalMultipleMarkersFromJava.java"
+ line="34"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.experimental.foo.ExperimentalPackage` or `@OptIn(markerClass = sample.experimental.foo.ExperimentalPackage.class)`"
errorLine1=" callPackageExperimental();"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
@@ -553,6 +641,17 @@
<issue
id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalKotlinAnnotation2` or `@OptIn(markerClass = sample.optin.ExperimentalKotlinAnnotation2.class)`"
+ errorLine1=" return experimentalObject.method() + AnnotatedKotlinClass2.fieldStatic;"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="src/main/java/sample/optin/UseKtExperimentalFromJava.java"
+ line="56"
+ column="68"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.experimental.ExperimentalDateTimeKt` or `@OptIn(markerClass = sample.experimental.ExperimentalDateTimeKt.class)`"
errorLine1=" TimeProviderKt.getTimeStatically();"
errorLine2=" ~~~~~~~~~~~~~~~~~">
diff --git a/appcompat/appcompat/lint-baseline.xml b/appcompat/appcompat/lint-baseline.xml
index 7a93bc3..f904448 100644
--- a/appcompat/appcompat/lint-baseline.xml
+++ b/appcompat/appcompat/lint-baseline.xml
@@ -6160,7 +6160,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/appcompat/widget/AppCompatImageButton.java"
- line="103"
+ line="112"
column="32"/>
</issue>
@@ -6171,7 +6171,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/appcompat/widget/AppCompatImageHelper.java"
- line="51"
+ line="52"
column="36"/>
</issue>
@@ -6182,7 +6182,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/appcompat/widget/AppCompatImageView.java"
- line="113"
+ line="123"
column="32"/>
</issue>
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java
index b532d36..01565c0e 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java
@@ -469,8 +469,10 @@
// after the inserted content (if no space was already present). See
// https://cs.android.com/android/platform/superproject/+/android-4.4.4_r2:frameworks/base/core/java/android/widget/TextView.java;l=8526,8527,8528,8545,8546
assertTextAndCursorPosition("ab xz", 2);
- } else {
+ } else if (Build.VERSION.SDK_INT <= 30) {
assertTextAndCursorPosition("abxz", 2);
+ } else {
+ assertTextAndCursorPosition("a\nbxz", 3);
}
}
@@ -610,6 +612,13 @@
mExtraValue = extraValue;
}
+ @NonNull
+ @Override
+ public String toString() {
+ return "[" + "clip=" + mClip + ", source=" + mSource + ", flags=" + mFlags
+ + ", linkUri=" + mLinkUri + ", extraValue=" + mExtraValue + "]";
+ }
+
@Override
public boolean matches(ContentInfoCompat actual) {
ClipData.Item expectedItem = mClip.getItemAt(0);
@@ -623,11 +632,22 @@
}
private boolean extrasMatch(Bundle actualExtras) {
- if (mSource == SOURCE_INPUT_METHOD && Build.VERSION.SDK_INT >= 25) {
- assertThat(actualExtras).isNotNull();
+ if (mSource == SOURCE_INPUT_METHOD && Build.VERSION.SDK_INT >= 25
+ && Build.VERSION.SDK_INT <= 30) {
+ // On SDK >= 25 and <= 30, when inserting from the keyboard, the InputContentInfo
+ // object passed from the IME should be set in the extras. This is needed in order
+ // to prevent premature release of URI permissions. Passing this object via the
+ // extras is not needed on other SDKs: on SDK < 25, the IME code handles URI
+ // permissions differently (expects the IME to grant URI permissions), and on
+ // SDK > 30, this is handled by the platform implementation of the API.
+ if (actualExtras == null) {
+ return false;
+ }
Parcelable actualInputContentInfoExtra = actualExtras.getParcelable(
"androidx.core.view.extra.INPUT_CONTENT_INFO");
- assertThat(actualInputContentInfoExtra).isInstanceOf(InputContentInfo.class);
+ if (!(actualInputContentInfoExtra instanceof InputContentInfo)) {
+ return false;
+ }
} else if (mExtraValue == null) {
return actualExtras == null;
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEditText.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEditText.java
index 7a954d5..708c5ee 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEditText.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEditText.java
@@ -230,10 +230,15 @@
mTextHelper.populateSurroundingTextIfNeeded(this, ic, outAttrs);
ic = AppCompatHintHelper.onCreateInputConnection(ic, outAttrs, this);
- String[] mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this);
- if (ic != null && mimeTypes != null) {
- EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes);
- ic = InputConnectionCompat.createWrapper(this, ic, outAttrs);
+ // On SDK 30 and below, we manually configure the InputConnection here to use
+ // ViewCompat.performReceiveContent. On S and above, the platform's BaseInputConnection
+ // implementation calls View.performReceiveContent by default.
+ if (ic != null && Build.VERSION.SDK_INT <= 30) {
+ String[] mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this);
+ if (mimeTypes != null) {
+ EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes);
+ ic = InputConnectionCompat.createWrapper(this, ic, outAttrs);
+ }
}
return mAppCompatEmojiEditTextHelper.onCreateInputConnection(ic, outAttrs);
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java
index cc84b4b..62d2a49 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java
@@ -33,6 +33,7 @@
import android.view.View;
import android.widget.TextView;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
@@ -48,15 +49,16 @@
private static final String LOG_TAG = "ReceiveContent";
/**
- * If the menu action is either "Paste" or "Paste as plain text" and the view has a
- * {@link androidx.core.view.OnReceiveContentListener}, use the listener to handle the paste.
+ * If the SDK is <= 30 and the view has a {@link androidx.core.view.OnReceiveContentListener},
+ * use the listener to handle the "Paste" and "Paste as plain text" actions.
*
* @return true if the action was handled; false otherwise
*/
static boolean maybeHandleMenuActionViaPerformReceiveContent(@NonNull TextView view,
- int menuItemId) {
- if (!(menuItemId == android.R.id.paste || menuItemId == android.R.id.pasteAsPlainText)
- || ViewCompat.getOnReceiveContentMimeTypes(view) == null) {
+ int actionId) {
+ if (Build.VERSION.SDK_INT >= 31
+ || ViewCompat.getOnReceiveContentMimeTypes(view) == null
+ || !(actionId == android.R.id.paste || actionId == android.R.id.pasteAsPlainText)) {
return false;
}
ClipboardManager cm = (ClipboardManager) view.getContext().getSystemService(
@@ -64,7 +66,7 @@
ClipData clip = (cm == null) ? null : cm.getPrimaryClip();
if (clip != null && clip.getItemCount() > 0) {
ContentInfoCompat payload = new ContentInfoCompat.Builder(clip, SOURCE_CLIPBOARD)
- .setFlags((menuItemId == android.R.id.paste) ? 0 : FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setFlags((actionId == android.R.id.paste) ? 0 : FLAG_CONVERT_TO_PLAIN_TEXT)
.build();
ViewCompat.performReceiveContent(view, payload);
}
@@ -72,14 +74,16 @@
}
/**
- * If the given view has a {@link androidx.core.view.OnReceiveContentListener}, try to handle
- * drag-and-drop via the listener.
+ * If the SDK is <= 30 (but >= 24) and the view has a
+ * {@link androidx.core.view.OnReceiveContentListener}, try to handle drag-and-drop via the
+ * listener.
*
* @return true if the event was handled; false otherwise
*/
static boolean maybeHandleDragEventViaPerformReceiveContent(@NonNull View view,
@NonNull DragEvent event) {
- if (Build.VERSION.SDK_INT < 24
+ if (Build.VERSION.SDK_INT >= 31
+ || Build.VERSION.SDK_INT < 24
|| event.getLocalState() != null
|| ViewCompat.getOnReceiveContentMimeTypes(view) == null) {
return false;
@@ -113,6 +117,7 @@
private static final class OnDropApi24Impl {
private OnDropApi24Impl() {}
+ @DoNotInline
static boolean onDropForTextView(@NonNull DragEvent event, @NonNull TextView view,
@NonNull Activity activity) {
activity.requestDragAndDropPermissions(event);
@@ -129,6 +134,7 @@
return true;
}
+ @DoNotInline
static boolean onDropForView(@NonNull DragEvent event, @NonNull View view,
@NonNull Activity activity) {
activity.requestDragAndDropPermissions(event);
diff --git a/appcompat/integration-tests/receive-content-testapp/src/main/AndroidManifest.xml b/appcompat/integration-tests/receive-content-testapp/src/main/AndroidManifest.xml
index 003efa8..fba2308 100644
--- a/appcompat/integration-tests/receive-content-testapp/src/main/AndroidManifest.xml
+++ b/appcompat/integration-tests/receive-content-testapp/src/main/AndroidManifest.xml
@@ -22,7 +22,8 @@
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
- android:name="androidx.appcompat.demo.receivecontent.MainActivity">
+ android:name="androidx.appcompat.demo.receivecontent.MainActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/appsearch/appsearch-ktx/api/current.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to appsearch/appsearch-ktx/api/current.txt
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/appsearch/appsearch-ktx/api/public_plus_experimental_current.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to appsearch/appsearch-ktx/api/public_plus_experimental_current.txt
diff --git a/slice/slice-builders/ktx/api/res-current.txt b/appsearch/appsearch-ktx/api/res-current.txt
similarity index 100%
copy from slice/slice-builders/ktx/api/res-current.txt
copy to appsearch/appsearch-ktx/api/res-current.txt
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/appsearch/appsearch-ktx/api/restricted_current.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to appsearch/appsearch-ktx/api/restricted_current.txt
diff --git a/appsearch/appsearch-ktx/build.gradle b/appsearch/appsearch-ktx/build.gradle
new file mode 100644
index 0000000..9675672
--- /dev/null
+++ b/appsearch/appsearch-ktx/build.gradle
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+plugins {
+ id('AndroidXPlugin')
+ id('com.android.library')
+ id('org.jetbrains.kotlin.android')
+ id('org.jetbrains.kotlin.kapt')
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+
+ kaptAndroidTest project(':appsearch:appsearch-compiler')
+ androidTestImplementation project(':appsearch:appsearch')
+ androidTestImplementation project(':appsearch:appsearch-local-storage')
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
+}
+
+androidx {
+ name = 'AndroidX AppSearch - Kotlin Extensions'
+ publish = Publish.SNAPSHOT_AND_RELEASE
+ mavenGroup = LibraryGroups.APPSEARCH
+ mavenVersion = LibraryVersions.APPSEARCH
+ inceptionYear = '2021'
+ description = 'AndroidX AppSearch - Kotlin Extensions'
+}
diff --git a/appsearch/appsearch-ktx/src/androidTest/java/AnnotationProcessorKtTest.kt b/appsearch/appsearch-ktx/src/androidTest/java/AnnotationProcessorKtTest.kt
new file mode 100644
index 0000000..e5163dd
--- /dev/null
+++ b/appsearch/appsearch-ktx/src/androidTest/java/AnnotationProcessorKtTest.kt
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.ktx
+
+import android.content.Context
+import androidx.appsearch.annotation.Document
+import androidx.appsearch.app.AppSearchSchema
+import androidx.appsearch.app.AppSearchSession
+import androidx.appsearch.app.GenericDocument
+import androidx.appsearch.app.PutDocumentsRequest
+import androidx.appsearch.app.SearchResult
+import androidx.appsearch.app.SearchResults
+import androidx.appsearch.app.SearchSpec
+import androidx.appsearch.app.SetSchemaRequest
+import androidx.appsearch.localstorage.LocalStorage
+import androidx.test.core.app.ApplicationProvider
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+public class AnnotationProcessorKtTest {
+ private companion object {
+ private const val DB_NAME = ""
+ }
+
+ private lateinit var session: AppSearchSession
+
+ @Before
+ public fun setUp() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ session = LocalStorage.createSearchSession(
+ LocalStorage.SearchContext.Builder(context, DB_NAME).build()
+ ).get()
+
+ // Cleanup whatever documents may still exist in these databases. This is needed in
+ // addition to tearDown in case a test exited without completing properly.
+ cleanup()
+ }
+
+ @After
+ public fun tearDown() {
+ // Cleanup whatever documents may still exist in these databases.
+ cleanup()
+ }
+
+ private fun cleanup() {
+ session.setSchema(SetSchemaRequest.Builder().setForceOverride(true).build()).get()
+ }
+
+ @Document
+ internal data class Card(
+ @Document.Namespace
+ val namespace: String,
+
+ @Document.Id
+ val id: String,
+
+ @Document.CreationTimestampMillis
+ val creationTimestampMillis: Long = 0L,
+
+ @Document.StringProperty(
+ indexingType = AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES,
+ tokenizerType = AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN
+ )
+ val string: String? = null,
+ )
+
+ @Document
+ internal data class Gift(
+ @Document.Namespace
+ val namespace: String,
+
+ @Document.Id
+ val id: String,
+
+ @Document.CreationTimestampMillis
+ val creationTimestampMillis: Long = 0L,
+
+ // Collections
+ @Document.LongProperty
+ val collectLong: Collection<Long>,
+
+ @Document.LongProperty
+ val collectInteger: Collection<Int>,
+
+ @Document.DoubleProperty
+ val collectDouble: Collection<Double>,
+
+ @Document.DoubleProperty
+ val collectFloat: Collection<Float>,
+
+ @Document.BooleanProperty
+ val collectBoolean: Collection<Boolean>,
+
+ @Document.BytesProperty
+ val collectByteArr: Collection<ByteArray>,
+
+ @Document.StringProperty
+ val collectString: Collection<String>,
+
+ @Document.DocumentProperty
+ val collectCard: Collection<Card>,
+
+ // Arrays
+ @Document.LongProperty
+ val arrBoxLong: Array<Long>,
+
+ @Document.LongProperty
+ val arrUnboxLong: LongArray,
+
+ @Document.LongProperty
+ val arrBoxInteger: Array<Int>,
+
+ @Document.LongProperty
+ val arrUnboxInt: IntArray,
+
+ @Document.DoubleProperty
+ val arrBoxDouble: Array<Double>,
+
+ @Document.DoubleProperty
+ val arrUnboxDouble: DoubleArray,
+
+ @Document.DoubleProperty
+ val arrBoxFloat: Array<Float>,
+
+ @Document.DoubleProperty
+ val arrUnboxFloat: FloatArray,
+
+ @Document.BooleanProperty
+ val arrBoxBoolean: Array<Boolean>,
+
+ @Document.BooleanProperty
+ val arrUnboxBoolean: BooleanArray,
+
+ @Document.BytesProperty
+ val arrUnboxByteArr: Array<ByteArray>,
+
+ @Document.BytesProperty
+ val boxByteArr: Array<Byte>,
+
+ @Document.StringProperty
+ val arrString: Array<String>,
+
+ @Document.DocumentProperty
+ val arrCard: Array<Card>,
+
+ // Single values
+ @Document.StringProperty
+ val string: String,
+
+ @Document.LongProperty
+ val boxLong: Long,
+
+ @Document.LongProperty
+ val unboxLong: Long = 0,
+
+ @Document.LongProperty
+ val boxInteger: Int,
+
+ @Document.LongProperty
+ val unboxInt: Int = 0,
+
+ @Document.DoubleProperty
+ val boxDouble: Double,
+
+ @Document.DoubleProperty
+ val unboxDouble: Double = 0.0,
+
+ @Document.DoubleProperty
+ val boxFloat: Float,
+
+ @Document.DoubleProperty
+ val unboxFloat: Float = 0f,
+
+ @Document.BooleanProperty
+ val boxBoolean: Boolean,
+
+ @Document.BooleanProperty
+ val unboxBoolean: Boolean = false,
+
+ @Document.BytesProperty
+ val unboxByteArr: ByteArray,
+
+ @Document.DocumentProperty
+ val card: Card
+ ) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as Gift
+
+ if (namespace != other.namespace) return false
+ if (id != other.id) return false
+ if (collectLong != other.collectLong) return false
+ if (collectInteger != other.collectInteger) return false
+ if (collectDouble != other.collectDouble) return false
+ if (collectFloat != other.collectFloat) return false
+ if (collectBoolean != other.collectBoolean) return false
+ // It's complicated to do a deep comparison of this, so we skip it
+ // if (collectByteArr != other.collectByteArr) return false
+ if (collectString != other.collectString) return false
+ if (collectCard != other.collectCard) return false
+ if (!arrBoxLong.contentEquals(other.arrBoxLong)) return false
+ if (!arrUnboxLong.contentEquals(other.arrUnboxLong)) return false
+ if (!arrBoxInteger.contentEquals(other.arrBoxInteger)) return false
+ if (!arrUnboxInt.contentEquals(other.arrUnboxInt)) return false
+ if (!arrBoxDouble.contentEquals(other.arrBoxDouble)) return false
+ if (!arrUnboxDouble.contentEquals(other.arrUnboxDouble)) return false
+ if (!arrBoxFloat.contentEquals(other.arrBoxFloat)) return false
+ if (!arrUnboxFloat.contentEquals(other.arrUnboxFloat)) return false
+ if (!arrBoxBoolean.contentEquals(other.arrBoxBoolean)) return false
+ if (!arrUnboxBoolean.contentEquals(other.arrUnboxBoolean)) return false
+ if (!arrUnboxByteArr.contentDeepEquals(other.arrUnboxByteArr)) return false
+ if (!boxByteArr.contentEquals(other.boxByteArr)) return false
+ if (!arrString.contentEquals(other.arrString)) return false
+ if (!arrCard.contentEquals(other.arrCard)) return false
+ if (string != other.string) return false
+ if (boxLong != other.boxLong) return false
+ if (unboxLong != other.unboxLong) return false
+ if (boxInteger != other.boxInteger) return false
+ if (unboxInt != other.unboxInt) return false
+ if (boxDouble != other.boxDouble) return false
+ if (unboxDouble != other.unboxDouble) return false
+ if (boxFloat != other.boxFloat) return false
+ if (unboxFloat != other.unboxFloat) return false
+ if (boxBoolean != other.boxBoolean) return false
+ if (unboxBoolean != other.unboxBoolean) return false
+ if (!unboxByteArr.contentEquals(other.unboxByteArr)) return false
+ if (card != other.card) return false
+
+ return true
+ }
+ }
+
+ @Test
+ public fun testAnnotationProcessor() {
+ session.setSchema(
+ SetSchemaRequest.Builder()
+ .addDocumentClasses(Card::class.java, Gift::class.java).build()
+ ).get()
+
+ // Create a Gift object and assign values.
+ val inputDocument = createPopulatedGift()
+
+ // Index the Gift document and query it.
+ session.put(PutDocumentsRequest.Builder().addDocuments(inputDocument).build())
+ .get().checkSuccess()
+ val searchResults = session.search("", SearchSpec.Builder().build())
+ val documents = convertSearchResultsToDocuments(searchResults)
+ assertThat(documents).hasSize(1)
+
+ // Convert GenericDocument to Gift and check values.
+ val outputDocument = documents[0].toDocumentClass(Gift::class.java)
+ assertThat(outputDocument).isEqualTo(inputDocument)
+ }
+
+ @Test
+ public fun testGenericDocumentConversion() {
+ val inGift = createPopulatedGift()
+ val genericDocument1 = GenericDocument.fromDocumentClass(inGift)
+ val genericDocument2 = GenericDocument.fromDocumentClass(inGift)
+ val outGift = genericDocument2.toDocumentClass(Gift::class.java)
+ assertThat(inGift).isNotSameInstanceAs(outGift)
+ assertThat(inGift).isEqualTo(outGift)
+ assertThat(genericDocument1).isNotSameInstanceAs(genericDocument2)
+ assertThat(genericDocument1).isEqualTo(genericDocument2)
+ }
+
+ private fun createPopulatedGift(): Gift {
+ val card1 = Card("card.namespace", "card.id1")
+ val card2 = Card("card.namespace", "card.id2")
+ return Gift(
+ namespace = "gift.namespace",
+ id = "gift.id",
+ arrBoxBoolean = arrayOf(true, false),
+ arrBoxDouble = arrayOf(0.0, 1.0),
+ arrBoxFloat = arrayOf(2.0f, 3.0f),
+ arrBoxInteger = arrayOf(4, 5),
+ arrBoxLong = arrayOf(6L, 7L),
+ arrString = arrayOf("cat", "dog"),
+ boxByteArr = arrayOf(8, 9),
+ arrUnboxBoolean = booleanArrayOf(false, true),
+ arrUnboxByteArr = arrayOf(byteArrayOf(0, 1), byteArrayOf(2, 3)),
+ arrUnboxDouble = doubleArrayOf(1.0, 0.0),
+ arrUnboxFloat = floatArrayOf(3.0f, 2.0f),
+ arrUnboxInt = intArrayOf(5, 4),
+ arrUnboxLong = longArrayOf(7, 6),
+ arrCard = arrayOf(card2, card2),
+ collectLong = listOf(6L, 7L),
+ collectInteger = listOf(4, 5),
+ collectBoolean = listOf(false, true),
+ collectString = listOf("cat", "dog"),
+ collectDouble = listOf(0.0, 1.0),
+ collectFloat = listOf(2.0f, 3.0f),
+ collectByteArr = listOf(byteArrayOf(0, 1), byteArrayOf(2, 3)),
+ collectCard = listOf(card2, card2),
+ string = "String",
+ boxLong = 1L,
+ unboxLong = 2L,
+ boxInteger = 3,
+ unboxInt = 4,
+ boxDouble = 5.0,
+ unboxDouble = 6.0,
+ boxFloat = 7.0f,
+ unboxFloat = 8.0f,
+ boxBoolean = true,
+ unboxBoolean = false,
+ unboxByteArr = byteArrayOf(1, 2, 3),
+ card = card1
+ )
+ }
+
+ private fun convertSearchResultsToDocuments(
+ searchResults: SearchResults
+ ): List<GenericDocument> {
+ var page = searchResults.nextPage.get()
+ val results = mutableListOf<SearchResult>()
+ while (page.isNotEmpty()) {
+ results.addAll(page)
+ page = searchResults.nextPage.get()
+ }
+ return results.map { it.genericDocument }
+ }
+}
diff --git a/appsearch/appsearch-ktx/src/main/AndroidManifest.xml b/appsearch/appsearch-ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..1c35209
--- /dev/null
+++ b/appsearch/appsearch-ktx/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest package="androidx.appsearch.ktx"/>
diff --git a/appsearch/appsearch/api/current.txt b/appsearch/appsearch/api/current.txt
index de75467..b5282d0 100644
--- a/appsearch/appsearch/api/current.txt
+++ b/appsearch/appsearch/api/current.txt
@@ -1,30 +1,56 @@
// Signature format: 4.0
package androidx.appsearch.annotation {
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface AppSearchDocument {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface Document {
method public abstract String name() default "";
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.CreationTimestampMillis {
- }
-
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Namespace {
- }
-
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Property {
- method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BooleanProperty {
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Score {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BytesProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.TtlMillis {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.CreationTimestampMillis {
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Uri {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DocumentProperty {
+ method public abstract boolean indexNestedProperties() default false;
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DoubleProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Id {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.LongProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Namespace {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Score {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.StringProperty {
+ method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.TtlMillis {
}
}
@@ -32,16 +58,27 @@
package androidx.appsearch.app {
public final class AppSearchBatchResult<KeyType, ValueType> {
+ method public java.util.Map<KeyType!,androidx.appsearch.app.AppSearchResult<ValueType!>!> getAll();
method public java.util.Map<KeyType!,androidx.appsearch.app.AppSearchResult<ValueType!>!> getFailures();
method public java.util.Map<KeyType!,ValueType!> getSuccesses();
method public boolean isSuccess();
}
+ public static final class AppSearchBatchResult.Builder<KeyType, ValueType> {
+ ctor public AppSearchBatchResult.Builder();
+ method public androidx.appsearch.app.AppSearchBatchResult<KeyType!,ValueType!> build();
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setFailure(KeyType, int, String?);
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setResult(KeyType, androidx.appsearch.app.AppSearchResult<ValueType!>);
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setSuccess(KeyType, ValueType?);
+ }
+
public final class AppSearchResult<ValueType> {
method public String? getErrorMessage();
method public int getResultCode();
method public ValueType? getResultValue();
method public boolean isSuccess();
+ method public static <ValueType> androidx.appsearch.app.AppSearchResult<ValueType!> newFailedResult(int, String?);
+ method public static <ValueType> androidx.appsearch.app.AppSearchResult<ValueType!> newSuccessfulResult(ValueType?);
field public static final int RESULT_INTERNAL_ERROR = 2; // 0x2
field public static final int RESULT_INVALID_ARGUMENT = 3; // 0x3
field public static final int RESULT_INVALID_SCHEMA = 7; // 0x7
@@ -49,6 +86,7 @@
field public static final int RESULT_NOT_FOUND = 6; // 0x6
field public static final int RESULT_OK = 0; // 0x0
field public static final int RESULT_OUT_OF_SPACE = 5; // 0x5
+ field public static final int RESULT_SECURITY_ERROR = 8; // 0x8
field public static final int RESULT_UNKNOWN_ERROR = 1; // 0x1
}
@@ -57,28 +95,71 @@
method public String getSchemaType();
}
+ public static final class AppSearchSchema.BooleanPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BooleanPropertyConfig.Builder {
+ ctor public AppSearchSchema.BooleanPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.BooleanPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.BooleanPropertyConfig.Builder setCardinality(int);
+ }
+
public static final class AppSearchSchema.Builder {
ctor public AppSearchSchema.Builder(String);
method public androidx.appsearch.app.AppSearchSchema.Builder addProperty(androidx.appsearch.app.AppSearchSchema.PropertyConfig);
method public androidx.appsearch.app.AppSearchSchema build();
}
- public static final class AppSearchSchema.PropertyConfig {
+ public static final class AppSearchSchema.BytesPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BytesPropertyConfig.Builder {
+ ctor public AppSearchSchema.BytesPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.BytesPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.BytesPropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ method public String getSchemaType();
+ method public boolean shouldIndexNestedProperties();
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig.Builder {
+ ctor public AppSearchSchema.DocumentPropertyConfig.Builder(String, String);
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig.Builder setCardinality(int);
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig.Builder setShouldIndexNestedProperties(boolean);
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig.Builder {
+ ctor public AppSearchSchema.DoublePropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.DoublePropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.DoublePropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.LongPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.LongPropertyConfig.Builder {
+ ctor public AppSearchSchema.LongPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.LongPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.LongPropertyConfig.Builder setCardinality(int);
+ }
+
+ public abstract static class AppSearchSchema.PropertyConfig {
method public int getCardinality();
- method public int getDataType();
- method public int getIndexingType();
method public String getName();
- method public String? getSchemaType();
- method public int getTokenizerType();
field public static final int CARDINALITY_OPTIONAL = 2; // 0x2
field public static final int CARDINALITY_REPEATED = 1; // 0x1
field public static final int CARDINALITY_REQUIRED = 3; // 0x3
- field public static final int DATA_TYPE_BOOLEAN = 4; // 0x4
- field public static final int DATA_TYPE_BYTES = 5; // 0x5
- field public static final int DATA_TYPE_DOCUMENT = 6; // 0x6
- field public static final int DATA_TYPE_DOUBLE = 3; // 0x3
- field public static final int DATA_TYPE_INT64 = 2; // 0x2
- field public static final int DATA_TYPE_STRING = 1; // 0x1
+ }
+
+ public static final class AppSearchSchema.StringPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ method public int getIndexingType();
+ method public int getTokenizerType();
field public static final int INDEXING_TYPE_EXACT_TERMS = 1; // 0x1
field public static final int INDEXING_TYPE_NONE = 0; // 0x0
field public static final int INDEXING_TYPE_PREFIXES = 2; // 0x2
@@ -86,37 +167,41 @@
field public static final int TOKENIZER_TYPE_PLAIN = 1; // 0x1
}
- public static final class AppSearchSchema.PropertyConfig.Builder {
- ctor public AppSearchSchema.PropertyConfig.Builder(String);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig build();
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setCardinality(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setDataType(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setIndexingType(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setSchemaType(String);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setTokenizerType(int);
+ public static final class AppSearchSchema.StringPropertyConfig.Builder {
+ ctor public AppSearchSchema.StringPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setCardinality(int);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setIndexingType(int);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setTokenizerType(int);
}
public interface AppSearchSession extends java.io.Closeable {
method public void close();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,androidx.appsearch.app.GenericDocument!>!> getByUri(androidx.appsearch.app.GetByUriRequest);
- method public com.google.common.util.concurrent.ListenableFuture<java.util.Set<androidx.appsearch.app.AppSearchSchema!>!> getSchema();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> putDocuments(androidx.appsearch.app.PutDocumentsRequest);
- method public androidx.appsearch.app.SearchResults query(String, androidx.appsearch.app.SearchSpec);
- method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> removeByQuery(String, androidx.appsearch.app.SearchSpec);
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> removeByUri(androidx.appsearch.app.RemoveByUriRequest);
- method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setSchema(androidx.appsearch.app.SetSchemaRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,androidx.appsearch.app.GenericDocument!>!> getByDocumentId(androidx.appsearch.app.GetByDocumentIdRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.util.Set<java.lang.String!>!> getNamespaces();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.GetSchemaResponse!> getSchema();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.StorageInfo!> getStorageInfo();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> put(androidx.appsearch.app.PutDocumentsRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> remove(androidx.appsearch.app.RemoveByDocumentIdRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> remove(String, androidx.appsearch.app.SearchSpec);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> reportUsage(androidx.appsearch.app.ReportUsageRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> requestFlush();
+ method public androidx.appsearch.app.SearchResults search(String, androidx.appsearch.app.SearchSpec);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.SetSchemaResponse!> setSchema(androidx.appsearch.app.SetSchemaRequest);
}
- public interface DataClassFactory<T> {
+ public interface DocumentClassFactory<T> {
method public T fromGenericDocument(androidx.appsearch.app.GenericDocument) throws androidx.appsearch.exceptions.AppSearchException;
method public androidx.appsearch.app.AppSearchSchema getSchema() throws androidx.appsearch.exceptions.AppSearchException;
- method public String getSchemaType();
+ method public String getSchemaName();
method public androidx.appsearch.app.GenericDocument toGenericDocument(T) throws androidx.appsearch.exceptions.AppSearchException;
}
public class GenericDocument {
ctor protected GenericDocument(androidx.appsearch.app.GenericDocument);
+ method public static androidx.appsearch.app.GenericDocument fromDocumentClass(Object) throws androidx.appsearch.exceptions.AppSearchException;
method public long getCreationTimestampMillis();
+ method public String getId();
method public static int getMaxIndexedProperties();
method public String getNamespace();
method public Object? getProperty(String);
@@ -136,15 +221,16 @@
method public String getSchemaType();
method public int getScore();
method public long getTtlMillis();
- method public String getUri();
- method public <T> T toDataClass(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
- field public static final String DEFAULT_NAMESPACE = "";
+ method public androidx.appsearch.app.GenericDocument.Builder<androidx.appsearch.app.GenericDocument.Builder<?>!> toBuilder();
+ method public <T> T toDocumentClass(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
}
public static class GenericDocument.Builder<BuilderType extends androidx.appsearch.app.GenericDocument.Builder> {
- ctor public GenericDocument.Builder(String, String);
+ ctor public GenericDocument.Builder(String, String, String);
method public androidx.appsearch.app.GenericDocument build();
+ method public BuilderType clearProperty(String);
method public BuilderType setCreationTimestampMillis(long);
+ method public BuilderType setId(String);
method public BuilderType setNamespace(String);
method public BuilderType setPropertyBoolean(String, boolean...);
method public BuilderType setPropertyBytes(String, byte[]!...);
@@ -152,25 +238,49 @@
method public BuilderType setPropertyDouble(String, double...);
method public BuilderType setPropertyLong(String, long...);
method public BuilderType setPropertyString(String, java.lang.String!...);
+ method public BuilderType setSchemaType(String);
method public BuilderType setScore(@IntRange(from=0, to=java.lang.Integer.MAX_VALUE) int);
method public BuilderType setTtlMillis(long);
}
- public final class GetByUriRequest {
+ public final class GetByDocumentIdRequest {
+ method public java.util.Set<java.lang.String!> getIds();
method public String getNamespace();
- method public java.util.Set<java.lang.String!> getUris();
+ method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getProjections();
+ field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
}
- public static final class GetByUriRequest.Builder {
- ctor public GetByUriRequest.Builder();
- method public androidx.appsearch.app.GetByUriRequest.Builder addUri(java.lang.String!...);
- method public androidx.appsearch.app.GetByUriRequest.Builder addUri(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.GetByUriRequest build();
- method public androidx.appsearch.app.GetByUriRequest.Builder setNamespace(String);
+ public static final class GetByDocumentIdRequest.Builder {
+ ctor public GetByDocumentIdRequest.Builder(String);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addIds(java.lang.String!...);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addIds(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addProjection(String, java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.GetByDocumentIdRequest build();
}
- public interface GlobalSearchSession {
- method public androidx.appsearch.app.SearchResults query(String, androidx.appsearch.app.SearchSpec);
+ public final class GetSchemaResponse {
+ method public java.util.Set<androidx.appsearch.app.AppSearchSchema!> getSchemas();
+ method @IntRange(from=0) public int getVersion();
+ }
+
+ public static final class GetSchemaResponse.Builder {
+ ctor public GetSchemaResponse.Builder();
+ method public androidx.appsearch.app.GetSchemaResponse.Builder addSchema(androidx.appsearch.app.AppSearchSchema);
+ method public androidx.appsearch.app.GetSchemaResponse build();
+ method public androidx.appsearch.app.GetSchemaResponse.Builder setVersion(@IntRange(from=0) int);
+ }
+
+ public interface GlobalSearchSession extends java.io.Closeable {
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> reportSystemUsage(androidx.appsearch.app.ReportSystemUsageRequest);
+ method public androidx.appsearch.app.SearchResults search(String, androidx.appsearch.app.SearchSpec);
+ }
+
+ public abstract class Migrator {
+ ctor public Migrator();
+ method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onDowngrade(int, int, androidx.appsearch.app.GenericDocument);
+ method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onUpgrade(int, int, androidx.appsearch.app.GenericDocument);
+ method public abstract boolean shouldMigrate(int, int);
}
public class PackageIdentifier {
@@ -180,47 +290,92 @@
}
public final class PutDocumentsRequest {
- method public java.util.List<androidx.appsearch.app.GenericDocument!> getDocuments();
+ method public java.util.List<androidx.appsearch.app.GenericDocument!> getGenericDocuments();
}
public static final class PutDocumentsRequest.Builder {
ctor public PutDocumentsRequest.Builder();
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addDataClass(java.lang.Object!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addDataClass(java.util.Collection<?>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocument(androidx.appsearch.app.GenericDocument!...);
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocument(java.util.Collection<? extends androidx.appsearch.app.GenericDocument>);
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addDocuments(java.lang.Object!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addDocuments(java.util.Collection<?>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocuments(androidx.appsearch.app.GenericDocument!...);
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocuments(java.util.Collection<? extends androidx.appsearch.app.GenericDocument>);
method public androidx.appsearch.app.PutDocumentsRequest build();
}
- public final class RemoveByUriRequest {
+ public final class RemoveByDocumentIdRequest {
+ method public java.util.Set<java.lang.String!> getIds();
method public String getNamespace();
- method public java.util.Set<java.lang.String!> getUris();
}
- public static final class RemoveByUriRequest.Builder {
- ctor public RemoveByUriRequest.Builder();
- method public androidx.appsearch.app.RemoveByUriRequest.Builder addUri(java.lang.String!...);
- method public androidx.appsearch.app.RemoveByUriRequest.Builder addUri(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.RemoveByUriRequest build();
- method public androidx.appsearch.app.RemoveByUriRequest.Builder setNamespace(String);
+ public static final class RemoveByDocumentIdRequest.Builder {
+ ctor public RemoveByDocumentIdRequest.Builder(String);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest.Builder addIds(java.lang.String!...);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest.Builder addIds(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest build();
+ }
+
+ public final class ReportSystemUsageRequest {
+ method public String getDatabaseName();
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public String getPackageName();
+ method public long getUsageTimestampMillis();
+ }
+
+ public static final class ReportSystemUsageRequest.Builder {
+ ctor public ReportSystemUsageRequest.Builder(String, String, String, String);
+ method public androidx.appsearch.app.ReportSystemUsageRequest build();
+ method public androidx.appsearch.app.ReportSystemUsageRequest.Builder setUsageTimestampMillis(long);
+ }
+
+ public final class ReportUsageRequest {
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public long getUsageTimestampMillis();
+ }
+
+ public static final class ReportUsageRequest.Builder {
+ ctor public ReportUsageRequest.Builder(String, String);
+ method public androidx.appsearch.app.ReportUsageRequest build();
+ method public androidx.appsearch.app.ReportUsageRequest.Builder setUsageTimestampMillis(long);
}
public final class SearchResult {
- method public androidx.appsearch.app.GenericDocument getDocument();
- method public java.util.List<androidx.appsearch.app.SearchResult.MatchInfo!> getMatches();
+ method public String getDatabaseName();
+ method public <T> T getDocument(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.GenericDocument getGenericDocument();
+ method public java.util.List<androidx.appsearch.app.SearchResult.MatchInfo!> getMatchInfos();
method public String getPackageName();
+ method public double getRankingSignal();
+ }
+
+ public static final class SearchResult.Builder {
+ ctor public SearchResult.Builder(String, String);
+ method public androidx.appsearch.app.SearchResult.Builder addMatchInfo(androidx.appsearch.app.SearchResult.MatchInfo);
+ method public androidx.appsearch.app.SearchResult build();
+ method public androidx.appsearch.app.SearchResult.Builder setDocument(Object) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchResult.Builder setGenericDocument(androidx.appsearch.app.GenericDocument);
+ method public androidx.appsearch.app.SearchResult.Builder setRankingSignal(double);
}
public static final class SearchResult.MatchInfo {
method public CharSequence getExactMatch();
- method public androidx.appsearch.app.SearchResult.MatchRange getExactMatchPosition();
+ method public androidx.appsearch.app.SearchResult.MatchRange getExactMatchRange();
method public String getFullText();
method public String getPropertyPath();
method public CharSequence getSnippet();
- method public androidx.appsearch.app.SearchResult.MatchRange getSnippetPosition();
+ method public androidx.appsearch.app.SearchResult.MatchRange getSnippetRange();
+ }
+
+ public static final class SearchResult.MatchInfo.Builder {
+ ctor public SearchResult.MatchInfo.Builder(String);
+ method public androidx.appsearch.app.SearchResult.MatchInfo build();
+ method public androidx.appsearch.app.SearchResult.MatchInfo.Builder setExactMatchRange(androidx.appsearch.app.SearchResult.MatchRange);
+ method public androidx.appsearch.app.SearchResult.MatchInfo.Builder setSnippetRange(androidx.appsearch.app.SearchResult.MatchRange);
}
public static final class SearchResult.MatchRange {
+ ctor public SearchResult.MatchRange(int, int);
method public int getEnd();
method public int getStart();
}
@@ -231,16 +386,21 @@
}
public final class SearchSpec {
+ method public java.util.List<java.lang.String!> getFilterNamespaces();
+ method public java.util.List<java.lang.String!> getFilterPackageNames();
+ method public java.util.List<java.lang.String!> getFilterSchemas();
method public int getMaxSnippetSize();
- method public java.util.List<java.lang.String!> getNamespaces();
method public int getOrder();
method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getProjections();
method public int getRankingStrategy();
method public int getResultCountPerPage();
- method public java.util.List<java.lang.String!> getSchemaTypes();
+ method public int getResultGroupingLimit();
+ method public int getResultGroupingTypeFlags();
method public int getSnippetCount();
method public int getSnippetCountPerProperty();
method public int getTermMatch();
+ field public static final int GROUPING_TYPE_PER_NAMESPACE = 2; // 0x2
+ field public static final int GROUPING_TYPE_PER_PACKAGE = 1; // 0x1
field public static final int ORDER_ASCENDING = 1; // 0x1
field public static final int ORDER_DESCENDING = 0; // 0x0
field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
@@ -248,49 +408,102 @@
field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
field public static final int RANKING_STRATEGY_RELEVANCE_SCORE = 3; // 0x3
+ field public static final int RANKING_STRATEGY_SYSTEM_USAGE_COUNT = 6; // 0x6
+ field public static final int RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP = 7; // 0x7
+ field public static final int RANKING_STRATEGY_USAGE_COUNT = 4; // 0x4
+ field public static final int RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP = 5; // 0x5
field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
field public static final int TERM_MATCH_PREFIX = 2; // 0x2
}
public static final class SearchSpec.Builder {
ctor public SearchSpec.Builder();
- method public androidx.appsearch.app.SearchSpec.Builder addNamespace(java.lang.String!...);
- method public androidx.appsearch.app.SearchSpec.Builder addNamespace(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.SearchSpec.Builder addProjection(String, java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterDocumentClasses(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterDocumentClasses(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterNamespaces(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterNamespaces(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterPackageNames(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterPackageNames(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterSchemas(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterSchemas(java.util.Collection<java.lang.String!>);
method public androidx.appsearch.app.SearchSpec.Builder addProjection(String, java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaByDataClass(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaByDataClass(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaType(java.lang.String!...);
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaType(java.util.Collection<java.lang.String!>);
method public androidx.appsearch.app.SearchSpec build();
method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
method public androidx.appsearch.app.SearchSpec.Builder setResultCountPerPage(@IntRange(from=0, to=0x2710) int);
+ method public androidx.appsearch.app.SearchSpec.Builder setResultGrouping(int, int);
method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
}
public final class SetSchemaRequest {
+ method public java.util.Map<java.lang.String!,androidx.appsearch.app.Migrator!> getMigrators();
method public java.util.Set<androidx.appsearch.app.AppSearchSchema!> getSchemas();
- method public java.util.Set<java.lang.String!> getSchemasNotVisibleToSystemUi();
+ method public java.util.Set<java.lang.String!> getSchemasNotDisplayedBySystem();
method public java.util.Map<java.lang.String!,java.util.Set<androidx.appsearch.app.PackageIdentifier!>!> getSchemasVisibleToPackages();
+ method @IntRange(from=1) public int getVersion();
method public boolean isForceOverride();
}
public static final class SetSchemaRequest.Builder {
ctor public SetSchemaRequest.Builder();
- method public androidx.appsearch.app.SetSchemaRequest.Builder addDataClass(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder addDataClass(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder addSchema(androidx.appsearch.app.AppSearchSchema!...);
- method public androidx.appsearch.app.SetSchemaRequest.Builder addSchema(java.util.Collection<androidx.appsearch.app.AppSearchSchema!>);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addDocumentClasses(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addDocumentClasses(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addSchemas(androidx.appsearch.app.AppSearchSchema!...);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addSchemas(java.util.Collection<androidx.appsearch.app.AppSearchSchema!>);
method public androidx.appsearch.app.SetSchemaRequest build();
- method public androidx.appsearch.app.SetSchemaRequest.Builder setDataClassVisibilityForPackage(Class<?>, boolean, androidx.appsearch.app.PackageIdentifier) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder setDataClassVisibilityForSystemUi(Class<?>, boolean) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setDocumentClassDisplayedBySystem(Class<?>, boolean) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setDocumentClassVisibilityForPackage(Class<?>, boolean, androidx.appsearch.app.PackageIdentifier) throws androidx.appsearch.exceptions.AppSearchException;
method public androidx.appsearch.app.SetSchemaRequest.Builder setForceOverride(boolean);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setMigrator(String, androidx.appsearch.app.Migrator);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setMigrators(java.util.Map<java.lang.String!,androidx.appsearch.app.Migrator!>);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeDisplayedBySystem(String, boolean);
method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(String, boolean, androidx.appsearch.app.PackageIdentifier);
- method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(String, boolean);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setVersion(@IntRange(from=1) int);
+ }
+
+ public class SetSchemaResponse {
+ method public java.util.Set<java.lang.String!> getDeletedTypes();
+ method public java.util.Set<java.lang.String!> getIncompatibleTypes();
+ method public java.util.Set<java.lang.String!> getMigratedTypes();
+ method public java.util.List<androidx.appsearch.app.SetSchemaResponse.MigrationFailure!> getMigrationFailures();
+ }
+
+ public static final class SetSchemaResponse.Builder {
+ ctor public SetSchemaResponse.Builder();
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addDeletedType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addDeletedTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addIncompatibleType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addIncompatibleTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigratedType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigratedTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigrationFailure(androidx.appsearch.app.SetSchemaResponse.MigrationFailure);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigrationFailures(java.util.Collection<androidx.appsearch.app.SetSchemaResponse.MigrationFailure!>);
+ method public androidx.appsearch.app.SetSchemaResponse build();
+ }
+
+ public static class SetSchemaResponse.MigrationFailure {
+ ctor public SetSchemaResponse.MigrationFailure(String, String, String, androidx.appsearch.app.AppSearchResult<?>);
+ method public androidx.appsearch.app.AppSearchResult<java.lang.Void!> getAppSearchResult();
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public String getSchemaType();
+ }
+
+ public class StorageInfo {
+ method public int getAliveDocumentsCount();
+ method public int getAliveNamespacesCount();
+ method public long getSizeBytes();
+ }
+
+ public static final class StorageInfo.Builder {
+ ctor public StorageInfo.Builder();
+ method public androidx.appsearch.app.StorageInfo build();
+ method public androidx.appsearch.app.StorageInfo.Builder setAliveDocumentsCount(int);
+ method public androidx.appsearch.app.StorageInfo.Builder setAliveNamespacesCount(int);
+ method public androidx.appsearch.app.StorageInfo.Builder setSizeBytes(long);
}
}
@@ -298,6 +511,9 @@
package androidx.appsearch.exceptions {
public class AppSearchException extends java.lang.Exception {
+ ctor public AppSearchException(int);
+ ctor public AppSearchException(int, String?);
+ ctor public AppSearchException(int, String?, Throwable?);
method public int getResultCode();
method public <T> androidx.appsearch.app.AppSearchResult<T!> toAppSearchResult();
}
diff --git a/appsearch/appsearch/api/public_plus_experimental_current.txt b/appsearch/appsearch/api/public_plus_experimental_current.txt
index de75467..b5282d0 100644
--- a/appsearch/appsearch/api/public_plus_experimental_current.txt
+++ b/appsearch/appsearch/api/public_plus_experimental_current.txt
@@ -1,30 +1,56 @@
// Signature format: 4.0
package androidx.appsearch.annotation {
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface AppSearchDocument {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface Document {
method public abstract String name() default "";
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.CreationTimestampMillis {
- }
-
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Namespace {
- }
-
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Property {
- method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BooleanProperty {
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Score {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BytesProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.TtlMillis {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.CreationTimestampMillis {
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Uri {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DocumentProperty {
+ method public abstract boolean indexNestedProperties() default false;
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DoubleProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Id {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.LongProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Namespace {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Score {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.StringProperty {
+ method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.TtlMillis {
}
}
@@ -32,16 +58,27 @@
package androidx.appsearch.app {
public final class AppSearchBatchResult<KeyType, ValueType> {
+ method public java.util.Map<KeyType!,androidx.appsearch.app.AppSearchResult<ValueType!>!> getAll();
method public java.util.Map<KeyType!,androidx.appsearch.app.AppSearchResult<ValueType!>!> getFailures();
method public java.util.Map<KeyType!,ValueType!> getSuccesses();
method public boolean isSuccess();
}
+ public static final class AppSearchBatchResult.Builder<KeyType, ValueType> {
+ ctor public AppSearchBatchResult.Builder();
+ method public androidx.appsearch.app.AppSearchBatchResult<KeyType!,ValueType!> build();
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setFailure(KeyType, int, String?);
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setResult(KeyType, androidx.appsearch.app.AppSearchResult<ValueType!>);
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setSuccess(KeyType, ValueType?);
+ }
+
public final class AppSearchResult<ValueType> {
method public String? getErrorMessage();
method public int getResultCode();
method public ValueType? getResultValue();
method public boolean isSuccess();
+ method public static <ValueType> androidx.appsearch.app.AppSearchResult<ValueType!> newFailedResult(int, String?);
+ method public static <ValueType> androidx.appsearch.app.AppSearchResult<ValueType!> newSuccessfulResult(ValueType?);
field public static final int RESULT_INTERNAL_ERROR = 2; // 0x2
field public static final int RESULT_INVALID_ARGUMENT = 3; // 0x3
field public static final int RESULT_INVALID_SCHEMA = 7; // 0x7
@@ -49,6 +86,7 @@
field public static final int RESULT_NOT_FOUND = 6; // 0x6
field public static final int RESULT_OK = 0; // 0x0
field public static final int RESULT_OUT_OF_SPACE = 5; // 0x5
+ field public static final int RESULT_SECURITY_ERROR = 8; // 0x8
field public static final int RESULT_UNKNOWN_ERROR = 1; // 0x1
}
@@ -57,28 +95,71 @@
method public String getSchemaType();
}
+ public static final class AppSearchSchema.BooleanPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BooleanPropertyConfig.Builder {
+ ctor public AppSearchSchema.BooleanPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.BooleanPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.BooleanPropertyConfig.Builder setCardinality(int);
+ }
+
public static final class AppSearchSchema.Builder {
ctor public AppSearchSchema.Builder(String);
method public androidx.appsearch.app.AppSearchSchema.Builder addProperty(androidx.appsearch.app.AppSearchSchema.PropertyConfig);
method public androidx.appsearch.app.AppSearchSchema build();
}
- public static final class AppSearchSchema.PropertyConfig {
+ public static final class AppSearchSchema.BytesPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BytesPropertyConfig.Builder {
+ ctor public AppSearchSchema.BytesPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.BytesPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.BytesPropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ method public String getSchemaType();
+ method public boolean shouldIndexNestedProperties();
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig.Builder {
+ ctor public AppSearchSchema.DocumentPropertyConfig.Builder(String, String);
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig.Builder setCardinality(int);
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig.Builder setShouldIndexNestedProperties(boolean);
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig.Builder {
+ ctor public AppSearchSchema.DoublePropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.DoublePropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.DoublePropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.LongPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.LongPropertyConfig.Builder {
+ ctor public AppSearchSchema.LongPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.LongPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.LongPropertyConfig.Builder setCardinality(int);
+ }
+
+ public abstract static class AppSearchSchema.PropertyConfig {
method public int getCardinality();
- method public int getDataType();
- method public int getIndexingType();
method public String getName();
- method public String? getSchemaType();
- method public int getTokenizerType();
field public static final int CARDINALITY_OPTIONAL = 2; // 0x2
field public static final int CARDINALITY_REPEATED = 1; // 0x1
field public static final int CARDINALITY_REQUIRED = 3; // 0x3
- field public static final int DATA_TYPE_BOOLEAN = 4; // 0x4
- field public static final int DATA_TYPE_BYTES = 5; // 0x5
- field public static final int DATA_TYPE_DOCUMENT = 6; // 0x6
- field public static final int DATA_TYPE_DOUBLE = 3; // 0x3
- field public static final int DATA_TYPE_INT64 = 2; // 0x2
- field public static final int DATA_TYPE_STRING = 1; // 0x1
+ }
+
+ public static final class AppSearchSchema.StringPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ method public int getIndexingType();
+ method public int getTokenizerType();
field public static final int INDEXING_TYPE_EXACT_TERMS = 1; // 0x1
field public static final int INDEXING_TYPE_NONE = 0; // 0x0
field public static final int INDEXING_TYPE_PREFIXES = 2; // 0x2
@@ -86,37 +167,41 @@
field public static final int TOKENIZER_TYPE_PLAIN = 1; // 0x1
}
- public static final class AppSearchSchema.PropertyConfig.Builder {
- ctor public AppSearchSchema.PropertyConfig.Builder(String);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig build();
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setCardinality(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setDataType(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setIndexingType(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setSchemaType(String);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setTokenizerType(int);
+ public static final class AppSearchSchema.StringPropertyConfig.Builder {
+ ctor public AppSearchSchema.StringPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setCardinality(int);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setIndexingType(int);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setTokenizerType(int);
}
public interface AppSearchSession extends java.io.Closeable {
method public void close();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,androidx.appsearch.app.GenericDocument!>!> getByUri(androidx.appsearch.app.GetByUriRequest);
- method public com.google.common.util.concurrent.ListenableFuture<java.util.Set<androidx.appsearch.app.AppSearchSchema!>!> getSchema();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> putDocuments(androidx.appsearch.app.PutDocumentsRequest);
- method public androidx.appsearch.app.SearchResults query(String, androidx.appsearch.app.SearchSpec);
- method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> removeByQuery(String, androidx.appsearch.app.SearchSpec);
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> removeByUri(androidx.appsearch.app.RemoveByUriRequest);
- method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setSchema(androidx.appsearch.app.SetSchemaRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,androidx.appsearch.app.GenericDocument!>!> getByDocumentId(androidx.appsearch.app.GetByDocumentIdRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.util.Set<java.lang.String!>!> getNamespaces();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.GetSchemaResponse!> getSchema();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.StorageInfo!> getStorageInfo();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> put(androidx.appsearch.app.PutDocumentsRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> remove(androidx.appsearch.app.RemoveByDocumentIdRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> remove(String, androidx.appsearch.app.SearchSpec);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> reportUsage(androidx.appsearch.app.ReportUsageRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> requestFlush();
+ method public androidx.appsearch.app.SearchResults search(String, androidx.appsearch.app.SearchSpec);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.SetSchemaResponse!> setSchema(androidx.appsearch.app.SetSchemaRequest);
}
- public interface DataClassFactory<T> {
+ public interface DocumentClassFactory<T> {
method public T fromGenericDocument(androidx.appsearch.app.GenericDocument) throws androidx.appsearch.exceptions.AppSearchException;
method public androidx.appsearch.app.AppSearchSchema getSchema() throws androidx.appsearch.exceptions.AppSearchException;
- method public String getSchemaType();
+ method public String getSchemaName();
method public androidx.appsearch.app.GenericDocument toGenericDocument(T) throws androidx.appsearch.exceptions.AppSearchException;
}
public class GenericDocument {
ctor protected GenericDocument(androidx.appsearch.app.GenericDocument);
+ method public static androidx.appsearch.app.GenericDocument fromDocumentClass(Object) throws androidx.appsearch.exceptions.AppSearchException;
method public long getCreationTimestampMillis();
+ method public String getId();
method public static int getMaxIndexedProperties();
method public String getNamespace();
method public Object? getProperty(String);
@@ -136,15 +221,16 @@
method public String getSchemaType();
method public int getScore();
method public long getTtlMillis();
- method public String getUri();
- method public <T> T toDataClass(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
- field public static final String DEFAULT_NAMESPACE = "";
+ method public androidx.appsearch.app.GenericDocument.Builder<androidx.appsearch.app.GenericDocument.Builder<?>!> toBuilder();
+ method public <T> T toDocumentClass(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
}
public static class GenericDocument.Builder<BuilderType extends androidx.appsearch.app.GenericDocument.Builder> {
- ctor public GenericDocument.Builder(String, String);
+ ctor public GenericDocument.Builder(String, String, String);
method public androidx.appsearch.app.GenericDocument build();
+ method public BuilderType clearProperty(String);
method public BuilderType setCreationTimestampMillis(long);
+ method public BuilderType setId(String);
method public BuilderType setNamespace(String);
method public BuilderType setPropertyBoolean(String, boolean...);
method public BuilderType setPropertyBytes(String, byte[]!...);
@@ -152,25 +238,49 @@
method public BuilderType setPropertyDouble(String, double...);
method public BuilderType setPropertyLong(String, long...);
method public BuilderType setPropertyString(String, java.lang.String!...);
+ method public BuilderType setSchemaType(String);
method public BuilderType setScore(@IntRange(from=0, to=java.lang.Integer.MAX_VALUE) int);
method public BuilderType setTtlMillis(long);
}
- public final class GetByUriRequest {
+ public final class GetByDocumentIdRequest {
+ method public java.util.Set<java.lang.String!> getIds();
method public String getNamespace();
- method public java.util.Set<java.lang.String!> getUris();
+ method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getProjections();
+ field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
}
- public static final class GetByUriRequest.Builder {
- ctor public GetByUriRequest.Builder();
- method public androidx.appsearch.app.GetByUriRequest.Builder addUri(java.lang.String!...);
- method public androidx.appsearch.app.GetByUriRequest.Builder addUri(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.GetByUriRequest build();
- method public androidx.appsearch.app.GetByUriRequest.Builder setNamespace(String);
+ public static final class GetByDocumentIdRequest.Builder {
+ ctor public GetByDocumentIdRequest.Builder(String);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addIds(java.lang.String!...);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addIds(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addProjection(String, java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.GetByDocumentIdRequest build();
}
- public interface GlobalSearchSession {
- method public androidx.appsearch.app.SearchResults query(String, androidx.appsearch.app.SearchSpec);
+ public final class GetSchemaResponse {
+ method public java.util.Set<androidx.appsearch.app.AppSearchSchema!> getSchemas();
+ method @IntRange(from=0) public int getVersion();
+ }
+
+ public static final class GetSchemaResponse.Builder {
+ ctor public GetSchemaResponse.Builder();
+ method public androidx.appsearch.app.GetSchemaResponse.Builder addSchema(androidx.appsearch.app.AppSearchSchema);
+ method public androidx.appsearch.app.GetSchemaResponse build();
+ method public androidx.appsearch.app.GetSchemaResponse.Builder setVersion(@IntRange(from=0) int);
+ }
+
+ public interface GlobalSearchSession extends java.io.Closeable {
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> reportSystemUsage(androidx.appsearch.app.ReportSystemUsageRequest);
+ method public androidx.appsearch.app.SearchResults search(String, androidx.appsearch.app.SearchSpec);
+ }
+
+ public abstract class Migrator {
+ ctor public Migrator();
+ method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onDowngrade(int, int, androidx.appsearch.app.GenericDocument);
+ method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onUpgrade(int, int, androidx.appsearch.app.GenericDocument);
+ method public abstract boolean shouldMigrate(int, int);
}
public class PackageIdentifier {
@@ -180,47 +290,92 @@
}
public final class PutDocumentsRequest {
- method public java.util.List<androidx.appsearch.app.GenericDocument!> getDocuments();
+ method public java.util.List<androidx.appsearch.app.GenericDocument!> getGenericDocuments();
}
public static final class PutDocumentsRequest.Builder {
ctor public PutDocumentsRequest.Builder();
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addDataClass(java.lang.Object!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addDataClass(java.util.Collection<?>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocument(androidx.appsearch.app.GenericDocument!...);
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocument(java.util.Collection<? extends androidx.appsearch.app.GenericDocument>);
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addDocuments(java.lang.Object!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addDocuments(java.util.Collection<?>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocuments(androidx.appsearch.app.GenericDocument!...);
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocuments(java.util.Collection<? extends androidx.appsearch.app.GenericDocument>);
method public androidx.appsearch.app.PutDocumentsRequest build();
}
- public final class RemoveByUriRequest {
+ public final class RemoveByDocumentIdRequest {
+ method public java.util.Set<java.lang.String!> getIds();
method public String getNamespace();
- method public java.util.Set<java.lang.String!> getUris();
}
- public static final class RemoveByUriRequest.Builder {
- ctor public RemoveByUriRequest.Builder();
- method public androidx.appsearch.app.RemoveByUriRequest.Builder addUri(java.lang.String!...);
- method public androidx.appsearch.app.RemoveByUriRequest.Builder addUri(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.RemoveByUriRequest build();
- method public androidx.appsearch.app.RemoveByUriRequest.Builder setNamespace(String);
+ public static final class RemoveByDocumentIdRequest.Builder {
+ ctor public RemoveByDocumentIdRequest.Builder(String);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest.Builder addIds(java.lang.String!...);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest.Builder addIds(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest build();
+ }
+
+ public final class ReportSystemUsageRequest {
+ method public String getDatabaseName();
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public String getPackageName();
+ method public long getUsageTimestampMillis();
+ }
+
+ public static final class ReportSystemUsageRequest.Builder {
+ ctor public ReportSystemUsageRequest.Builder(String, String, String, String);
+ method public androidx.appsearch.app.ReportSystemUsageRequest build();
+ method public androidx.appsearch.app.ReportSystemUsageRequest.Builder setUsageTimestampMillis(long);
+ }
+
+ public final class ReportUsageRequest {
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public long getUsageTimestampMillis();
+ }
+
+ public static final class ReportUsageRequest.Builder {
+ ctor public ReportUsageRequest.Builder(String, String);
+ method public androidx.appsearch.app.ReportUsageRequest build();
+ method public androidx.appsearch.app.ReportUsageRequest.Builder setUsageTimestampMillis(long);
}
public final class SearchResult {
- method public androidx.appsearch.app.GenericDocument getDocument();
- method public java.util.List<androidx.appsearch.app.SearchResult.MatchInfo!> getMatches();
+ method public String getDatabaseName();
+ method public <T> T getDocument(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.GenericDocument getGenericDocument();
+ method public java.util.List<androidx.appsearch.app.SearchResult.MatchInfo!> getMatchInfos();
method public String getPackageName();
+ method public double getRankingSignal();
+ }
+
+ public static final class SearchResult.Builder {
+ ctor public SearchResult.Builder(String, String);
+ method public androidx.appsearch.app.SearchResult.Builder addMatchInfo(androidx.appsearch.app.SearchResult.MatchInfo);
+ method public androidx.appsearch.app.SearchResult build();
+ method public androidx.appsearch.app.SearchResult.Builder setDocument(Object) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchResult.Builder setGenericDocument(androidx.appsearch.app.GenericDocument);
+ method public androidx.appsearch.app.SearchResult.Builder setRankingSignal(double);
}
public static final class SearchResult.MatchInfo {
method public CharSequence getExactMatch();
- method public androidx.appsearch.app.SearchResult.MatchRange getExactMatchPosition();
+ method public androidx.appsearch.app.SearchResult.MatchRange getExactMatchRange();
method public String getFullText();
method public String getPropertyPath();
method public CharSequence getSnippet();
- method public androidx.appsearch.app.SearchResult.MatchRange getSnippetPosition();
+ method public androidx.appsearch.app.SearchResult.MatchRange getSnippetRange();
+ }
+
+ public static final class SearchResult.MatchInfo.Builder {
+ ctor public SearchResult.MatchInfo.Builder(String);
+ method public androidx.appsearch.app.SearchResult.MatchInfo build();
+ method public androidx.appsearch.app.SearchResult.MatchInfo.Builder setExactMatchRange(androidx.appsearch.app.SearchResult.MatchRange);
+ method public androidx.appsearch.app.SearchResult.MatchInfo.Builder setSnippetRange(androidx.appsearch.app.SearchResult.MatchRange);
}
public static final class SearchResult.MatchRange {
+ ctor public SearchResult.MatchRange(int, int);
method public int getEnd();
method public int getStart();
}
@@ -231,16 +386,21 @@
}
public final class SearchSpec {
+ method public java.util.List<java.lang.String!> getFilterNamespaces();
+ method public java.util.List<java.lang.String!> getFilterPackageNames();
+ method public java.util.List<java.lang.String!> getFilterSchemas();
method public int getMaxSnippetSize();
- method public java.util.List<java.lang.String!> getNamespaces();
method public int getOrder();
method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getProjections();
method public int getRankingStrategy();
method public int getResultCountPerPage();
- method public java.util.List<java.lang.String!> getSchemaTypes();
+ method public int getResultGroupingLimit();
+ method public int getResultGroupingTypeFlags();
method public int getSnippetCount();
method public int getSnippetCountPerProperty();
method public int getTermMatch();
+ field public static final int GROUPING_TYPE_PER_NAMESPACE = 2; // 0x2
+ field public static final int GROUPING_TYPE_PER_PACKAGE = 1; // 0x1
field public static final int ORDER_ASCENDING = 1; // 0x1
field public static final int ORDER_DESCENDING = 0; // 0x0
field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
@@ -248,49 +408,102 @@
field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
field public static final int RANKING_STRATEGY_RELEVANCE_SCORE = 3; // 0x3
+ field public static final int RANKING_STRATEGY_SYSTEM_USAGE_COUNT = 6; // 0x6
+ field public static final int RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP = 7; // 0x7
+ field public static final int RANKING_STRATEGY_USAGE_COUNT = 4; // 0x4
+ field public static final int RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP = 5; // 0x5
field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
field public static final int TERM_MATCH_PREFIX = 2; // 0x2
}
public static final class SearchSpec.Builder {
ctor public SearchSpec.Builder();
- method public androidx.appsearch.app.SearchSpec.Builder addNamespace(java.lang.String!...);
- method public androidx.appsearch.app.SearchSpec.Builder addNamespace(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.SearchSpec.Builder addProjection(String, java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterDocumentClasses(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterDocumentClasses(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterNamespaces(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterNamespaces(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterPackageNames(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterPackageNames(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterSchemas(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterSchemas(java.util.Collection<java.lang.String!>);
method public androidx.appsearch.app.SearchSpec.Builder addProjection(String, java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaByDataClass(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaByDataClass(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaType(java.lang.String!...);
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaType(java.util.Collection<java.lang.String!>);
method public androidx.appsearch.app.SearchSpec build();
method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
method public androidx.appsearch.app.SearchSpec.Builder setResultCountPerPage(@IntRange(from=0, to=0x2710) int);
+ method public androidx.appsearch.app.SearchSpec.Builder setResultGrouping(int, int);
method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
}
public final class SetSchemaRequest {
+ method public java.util.Map<java.lang.String!,androidx.appsearch.app.Migrator!> getMigrators();
method public java.util.Set<androidx.appsearch.app.AppSearchSchema!> getSchemas();
- method public java.util.Set<java.lang.String!> getSchemasNotVisibleToSystemUi();
+ method public java.util.Set<java.lang.String!> getSchemasNotDisplayedBySystem();
method public java.util.Map<java.lang.String!,java.util.Set<androidx.appsearch.app.PackageIdentifier!>!> getSchemasVisibleToPackages();
+ method @IntRange(from=1) public int getVersion();
method public boolean isForceOverride();
}
public static final class SetSchemaRequest.Builder {
ctor public SetSchemaRequest.Builder();
- method public androidx.appsearch.app.SetSchemaRequest.Builder addDataClass(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder addDataClass(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder addSchema(androidx.appsearch.app.AppSearchSchema!...);
- method public androidx.appsearch.app.SetSchemaRequest.Builder addSchema(java.util.Collection<androidx.appsearch.app.AppSearchSchema!>);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addDocumentClasses(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addDocumentClasses(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addSchemas(androidx.appsearch.app.AppSearchSchema!...);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addSchemas(java.util.Collection<androidx.appsearch.app.AppSearchSchema!>);
method public androidx.appsearch.app.SetSchemaRequest build();
- method public androidx.appsearch.app.SetSchemaRequest.Builder setDataClassVisibilityForPackage(Class<?>, boolean, androidx.appsearch.app.PackageIdentifier) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder setDataClassVisibilityForSystemUi(Class<?>, boolean) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setDocumentClassDisplayedBySystem(Class<?>, boolean) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setDocumentClassVisibilityForPackage(Class<?>, boolean, androidx.appsearch.app.PackageIdentifier) throws androidx.appsearch.exceptions.AppSearchException;
method public androidx.appsearch.app.SetSchemaRequest.Builder setForceOverride(boolean);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setMigrator(String, androidx.appsearch.app.Migrator);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setMigrators(java.util.Map<java.lang.String!,androidx.appsearch.app.Migrator!>);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeDisplayedBySystem(String, boolean);
method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(String, boolean, androidx.appsearch.app.PackageIdentifier);
- method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(String, boolean);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setVersion(@IntRange(from=1) int);
+ }
+
+ public class SetSchemaResponse {
+ method public java.util.Set<java.lang.String!> getDeletedTypes();
+ method public java.util.Set<java.lang.String!> getIncompatibleTypes();
+ method public java.util.Set<java.lang.String!> getMigratedTypes();
+ method public java.util.List<androidx.appsearch.app.SetSchemaResponse.MigrationFailure!> getMigrationFailures();
+ }
+
+ public static final class SetSchemaResponse.Builder {
+ ctor public SetSchemaResponse.Builder();
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addDeletedType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addDeletedTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addIncompatibleType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addIncompatibleTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigratedType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigratedTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigrationFailure(androidx.appsearch.app.SetSchemaResponse.MigrationFailure);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigrationFailures(java.util.Collection<androidx.appsearch.app.SetSchemaResponse.MigrationFailure!>);
+ method public androidx.appsearch.app.SetSchemaResponse build();
+ }
+
+ public static class SetSchemaResponse.MigrationFailure {
+ ctor public SetSchemaResponse.MigrationFailure(String, String, String, androidx.appsearch.app.AppSearchResult<?>);
+ method public androidx.appsearch.app.AppSearchResult<java.lang.Void!> getAppSearchResult();
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public String getSchemaType();
+ }
+
+ public class StorageInfo {
+ method public int getAliveDocumentsCount();
+ method public int getAliveNamespacesCount();
+ method public long getSizeBytes();
+ }
+
+ public static final class StorageInfo.Builder {
+ ctor public StorageInfo.Builder();
+ method public androidx.appsearch.app.StorageInfo build();
+ method public androidx.appsearch.app.StorageInfo.Builder setAliveDocumentsCount(int);
+ method public androidx.appsearch.app.StorageInfo.Builder setAliveNamespacesCount(int);
+ method public androidx.appsearch.app.StorageInfo.Builder setSizeBytes(long);
}
}
@@ -298,6 +511,9 @@
package androidx.appsearch.exceptions {
public class AppSearchException extends java.lang.Exception {
+ ctor public AppSearchException(int);
+ ctor public AppSearchException(int, String?);
+ ctor public AppSearchException(int, String?, Throwable?);
method public int getResultCode();
method public <T> androidx.appsearch.app.AppSearchResult<T!> toAppSearchResult();
}
diff --git a/appsearch/appsearch/api/restricted_current.txt b/appsearch/appsearch/api/restricted_current.txt
index de75467..b5282d0 100644
--- a/appsearch/appsearch/api/restricted_current.txt
+++ b/appsearch/appsearch/api/restricted_current.txt
@@ -1,30 +1,56 @@
// Signature format: 4.0
package androidx.appsearch.annotation {
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface AppSearchDocument {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface Document {
method public abstract String name() default "";
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.CreationTimestampMillis {
- }
-
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Namespace {
- }
-
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Property {
- method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BooleanProperty {
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Score {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BytesProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.TtlMillis {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.CreationTimestampMillis {
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public static @interface AppSearchDocument.Uri {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DocumentProperty {
+ method public abstract boolean indexNestedProperties() default false;
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DoubleProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Id {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.LongProperty {
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Namespace {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Score {
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.StringProperty {
+ method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
+ method public abstract String name() default "";
+ method public abstract boolean required() default false;
+ method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
+ }
+
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.TtlMillis {
}
}
@@ -32,16 +58,27 @@
package androidx.appsearch.app {
public final class AppSearchBatchResult<KeyType, ValueType> {
+ method public java.util.Map<KeyType!,androidx.appsearch.app.AppSearchResult<ValueType!>!> getAll();
method public java.util.Map<KeyType!,androidx.appsearch.app.AppSearchResult<ValueType!>!> getFailures();
method public java.util.Map<KeyType!,ValueType!> getSuccesses();
method public boolean isSuccess();
}
+ public static final class AppSearchBatchResult.Builder<KeyType, ValueType> {
+ ctor public AppSearchBatchResult.Builder();
+ method public androidx.appsearch.app.AppSearchBatchResult<KeyType!,ValueType!> build();
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setFailure(KeyType, int, String?);
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setResult(KeyType, androidx.appsearch.app.AppSearchResult<ValueType!>);
+ method public androidx.appsearch.app.AppSearchBatchResult.Builder<KeyType!,ValueType!> setSuccess(KeyType, ValueType?);
+ }
+
public final class AppSearchResult<ValueType> {
method public String? getErrorMessage();
method public int getResultCode();
method public ValueType? getResultValue();
method public boolean isSuccess();
+ method public static <ValueType> androidx.appsearch.app.AppSearchResult<ValueType!> newFailedResult(int, String?);
+ method public static <ValueType> androidx.appsearch.app.AppSearchResult<ValueType!> newSuccessfulResult(ValueType?);
field public static final int RESULT_INTERNAL_ERROR = 2; // 0x2
field public static final int RESULT_INVALID_ARGUMENT = 3; // 0x3
field public static final int RESULT_INVALID_SCHEMA = 7; // 0x7
@@ -49,6 +86,7 @@
field public static final int RESULT_NOT_FOUND = 6; // 0x6
field public static final int RESULT_OK = 0; // 0x0
field public static final int RESULT_OUT_OF_SPACE = 5; // 0x5
+ field public static final int RESULT_SECURITY_ERROR = 8; // 0x8
field public static final int RESULT_UNKNOWN_ERROR = 1; // 0x1
}
@@ -57,28 +95,71 @@
method public String getSchemaType();
}
+ public static final class AppSearchSchema.BooleanPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BooleanPropertyConfig.Builder {
+ ctor public AppSearchSchema.BooleanPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.BooleanPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.BooleanPropertyConfig.Builder setCardinality(int);
+ }
+
public static final class AppSearchSchema.Builder {
ctor public AppSearchSchema.Builder(String);
method public androidx.appsearch.app.AppSearchSchema.Builder addProperty(androidx.appsearch.app.AppSearchSchema.PropertyConfig);
method public androidx.appsearch.app.AppSearchSchema build();
}
- public static final class AppSearchSchema.PropertyConfig {
+ public static final class AppSearchSchema.BytesPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BytesPropertyConfig.Builder {
+ ctor public AppSearchSchema.BytesPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.BytesPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.BytesPropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ method public String getSchemaType();
+ method public boolean shouldIndexNestedProperties();
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig.Builder {
+ ctor public AppSearchSchema.DocumentPropertyConfig.Builder(String, String);
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig.Builder setCardinality(int);
+ method public androidx.appsearch.app.AppSearchSchema.DocumentPropertyConfig.Builder setShouldIndexNestedProperties(boolean);
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig.Builder {
+ ctor public AppSearchSchema.DoublePropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.DoublePropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.DoublePropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.LongPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.LongPropertyConfig.Builder {
+ ctor public AppSearchSchema.LongPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.LongPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.LongPropertyConfig.Builder setCardinality(int);
+ }
+
+ public abstract static class AppSearchSchema.PropertyConfig {
method public int getCardinality();
- method public int getDataType();
- method public int getIndexingType();
method public String getName();
- method public String? getSchemaType();
- method public int getTokenizerType();
field public static final int CARDINALITY_OPTIONAL = 2; // 0x2
field public static final int CARDINALITY_REPEATED = 1; // 0x1
field public static final int CARDINALITY_REQUIRED = 3; // 0x3
- field public static final int DATA_TYPE_BOOLEAN = 4; // 0x4
- field public static final int DATA_TYPE_BYTES = 5; // 0x5
- field public static final int DATA_TYPE_DOCUMENT = 6; // 0x6
- field public static final int DATA_TYPE_DOUBLE = 3; // 0x3
- field public static final int DATA_TYPE_INT64 = 2; // 0x2
- field public static final int DATA_TYPE_STRING = 1; // 0x1
+ }
+
+ public static final class AppSearchSchema.StringPropertyConfig extends androidx.appsearch.app.AppSearchSchema.PropertyConfig {
+ method public int getIndexingType();
+ method public int getTokenizerType();
field public static final int INDEXING_TYPE_EXACT_TERMS = 1; // 0x1
field public static final int INDEXING_TYPE_NONE = 0; // 0x0
field public static final int INDEXING_TYPE_PREFIXES = 2; // 0x2
@@ -86,37 +167,41 @@
field public static final int TOKENIZER_TYPE_PLAIN = 1; // 0x1
}
- public static final class AppSearchSchema.PropertyConfig.Builder {
- ctor public AppSearchSchema.PropertyConfig.Builder(String);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig build();
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setCardinality(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setDataType(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setIndexingType(int);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setSchemaType(String);
- method public androidx.appsearch.app.AppSearchSchema.PropertyConfig.Builder setTokenizerType(int);
+ public static final class AppSearchSchema.StringPropertyConfig.Builder {
+ ctor public AppSearchSchema.StringPropertyConfig.Builder(String);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig build();
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setCardinality(int);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setIndexingType(int);
+ method public androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.Builder setTokenizerType(int);
}
public interface AppSearchSession extends java.io.Closeable {
method public void close();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,androidx.appsearch.app.GenericDocument!>!> getByUri(androidx.appsearch.app.GetByUriRequest);
- method public com.google.common.util.concurrent.ListenableFuture<java.util.Set<androidx.appsearch.app.AppSearchSchema!>!> getSchema();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> putDocuments(androidx.appsearch.app.PutDocumentsRequest);
- method public androidx.appsearch.app.SearchResults query(String, androidx.appsearch.app.SearchSpec);
- method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> removeByQuery(String, androidx.appsearch.app.SearchSpec);
- method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> removeByUri(androidx.appsearch.app.RemoveByUriRequest);
- method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setSchema(androidx.appsearch.app.SetSchemaRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,androidx.appsearch.app.GenericDocument!>!> getByDocumentId(androidx.appsearch.app.GetByDocumentIdRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.util.Set<java.lang.String!>!> getNamespaces();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.GetSchemaResponse!> getSchema();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.StorageInfo!> getStorageInfo();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> put(androidx.appsearch.app.PutDocumentsRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchBatchResult<java.lang.String!,java.lang.Void!>!> remove(androidx.appsearch.app.RemoveByDocumentIdRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> remove(String, androidx.appsearch.app.SearchSpec);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> reportUsage(androidx.appsearch.app.ReportUsageRequest);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> requestFlush();
+ method public androidx.appsearch.app.SearchResults search(String, androidx.appsearch.app.SearchSpec);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.SetSchemaResponse!> setSchema(androidx.appsearch.app.SetSchemaRequest);
}
- public interface DataClassFactory<T> {
+ public interface DocumentClassFactory<T> {
method public T fromGenericDocument(androidx.appsearch.app.GenericDocument) throws androidx.appsearch.exceptions.AppSearchException;
method public androidx.appsearch.app.AppSearchSchema getSchema() throws androidx.appsearch.exceptions.AppSearchException;
- method public String getSchemaType();
+ method public String getSchemaName();
method public androidx.appsearch.app.GenericDocument toGenericDocument(T) throws androidx.appsearch.exceptions.AppSearchException;
}
public class GenericDocument {
ctor protected GenericDocument(androidx.appsearch.app.GenericDocument);
+ method public static androidx.appsearch.app.GenericDocument fromDocumentClass(Object) throws androidx.appsearch.exceptions.AppSearchException;
method public long getCreationTimestampMillis();
+ method public String getId();
method public static int getMaxIndexedProperties();
method public String getNamespace();
method public Object? getProperty(String);
@@ -136,15 +221,16 @@
method public String getSchemaType();
method public int getScore();
method public long getTtlMillis();
- method public String getUri();
- method public <T> T toDataClass(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
- field public static final String DEFAULT_NAMESPACE = "";
+ method public androidx.appsearch.app.GenericDocument.Builder<androidx.appsearch.app.GenericDocument.Builder<?>!> toBuilder();
+ method public <T> T toDocumentClass(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
}
public static class GenericDocument.Builder<BuilderType extends androidx.appsearch.app.GenericDocument.Builder> {
- ctor public GenericDocument.Builder(String, String);
+ ctor public GenericDocument.Builder(String, String, String);
method public androidx.appsearch.app.GenericDocument build();
+ method public BuilderType clearProperty(String);
method public BuilderType setCreationTimestampMillis(long);
+ method public BuilderType setId(String);
method public BuilderType setNamespace(String);
method public BuilderType setPropertyBoolean(String, boolean...);
method public BuilderType setPropertyBytes(String, byte[]!...);
@@ -152,25 +238,49 @@
method public BuilderType setPropertyDouble(String, double...);
method public BuilderType setPropertyLong(String, long...);
method public BuilderType setPropertyString(String, java.lang.String!...);
+ method public BuilderType setSchemaType(String);
method public BuilderType setScore(@IntRange(from=0, to=java.lang.Integer.MAX_VALUE) int);
method public BuilderType setTtlMillis(long);
}
- public final class GetByUriRequest {
+ public final class GetByDocumentIdRequest {
+ method public java.util.Set<java.lang.String!> getIds();
method public String getNamespace();
- method public java.util.Set<java.lang.String!> getUris();
+ method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getProjections();
+ field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
}
- public static final class GetByUriRequest.Builder {
- ctor public GetByUriRequest.Builder();
- method public androidx.appsearch.app.GetByUriRequest.Builder addUri(java.lang.String!...);
- method public androidx.appsearch.app.GetByUriRequest.Builder addUri(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.GetByUriRequest build();
- method public androidx.appsearch.app.GetByUriRequest.Builder setNamespace(String);
+ public static final class GetByDocumentIdRequest.Builder {
+ ctor public GetByDocumentIdRequest.Builder(String);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addIds(java.lang.String!...);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addIds(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.GetByDocumentIdRequest.Builder addProjection(String, java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.GetByDocumentIdRequest build();
}
- public interface GlobalSearchSession {
- method public androidx.appsearch.app.SearchResults query(String, androidx.appsearch.app.SearchSpec);
+ public final class GetSchemaResponse {
+ method public java.util.Set<androidx.appsearch.app.AppSearchSchema!> getSchemas();
+ method @IntRange(from=0) public int getVersion();
+ }
+
+ public static final class GetSchemaResponse.Builder {
+ ctor public GetSchemaResponse.Builder();
+ method public androidx.appsearch.app.GetSchemaResponse.Builder addSchema(androidx.appsearch.app.AppSearchSchema);
+ method public androidx.appsearch.app.GetSchemaResponse build();
+ method public androidx.appsearch.app.GetSchemaResponse.Builder setVersion(@IntRange(from=0) int);
+ }
+
+ public interface GlobalSearchSession extends java.io.Closeable {
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> reportSystemUsage(androidx.appsearch.app.ReportSystemUsageRequest);
+ method public androidx.appsearch.app.SearchResults search(String, androidx.appsearch.app.SearchSpec);
+ }
+
+ public abstract class Migrator {
+ ctor public Migrator();
+ method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onDowngrade(int, int, androidx.appsearch.app.GenericDocument);
+ method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onUpgrade(int, int, androidx.appsearch.app.GenericDocument);
+ method public abstract boolean shouldMigrate(int, int);
}
public class PackageIdentifier {
@@ -180,47 +290,92 @@
}
public final class PutDocumentsRequest {
- method public java.util.List<androidx.appsearch.app.GenericDocument!> getDocuments();
+ method public java.util.List<androidx.appsearch.app.GenericDocument!> getGenericDocuments();
}
public static final class PutDocumentsRequest.Builder {
ctor public PutDocumentsRequest.Builder();
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addDataClass(java.lang.Object!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addDataClass(java.util.Collection<?>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocument(androidx.appsearch.app.GenericDocument!...);
- method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocument(java.util.Collection<? extends androidx.appsearch.app.GenericDocument>);
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addDocuments(java.lang.Object!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addDocuments(java.util.Collection<?>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocuments(androidx.appsearch.app.GenericDocument!...);
+ method public androidx.appsearch.app.PutDocumentsRequest.Builder addGenericDocuments(java.util.Collection<? extends androidx.appsearch.app.GenericDocument>);
method public androidx.appsearch.app.PutDocumentsRequest build();
}
- public final class RemoveByUriRequest {
+ public final class RemoveByDocumentIdRequest {
+ method public java.util.Set<java.lang.String!> getIds();
method public String getNamespace();
- method public java.util.Set<java.lang.String!> getUris();
}
- public static final class RemoveByUriRequest.Builder {
- ctor public RemoveByUriRequest.Builder();
- method public androidx.appsearch.app.RemoveByUriRequest.Builder addUri(java.lang.String!...);
- method public androidx.appsearch.app.RemoveByUriRequest.Builder addUri(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.RemoveByUriRequest build();
- method public androidx.appsearch.app.RemoveByUriRequest.Builder setNamespace(String);
+ public static final class RemoveByDocumentIdRequest.Builder {
+ ctor public RemoveByDocumentIdRequest.Builder(String);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest.Builder addIds(java.lang.String!...);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest.Builder addIds(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.RemoveByDocumentIdRequest build();
+ }
+
+ public final class ReportSystemUsageRequest {
+ method public String getDatabaseName();
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public String getPackageName();
+ method public long getUsageTimestampMillis();
+ }
+
+ public static final class ReportSystemUsageRequest.Builder {
+ ctor public ReportSystemUsageRequest.Builder(String, String, String, String);
+ method public androidx.appsearch.app.ReportSystemUsageRequest build();
+ method public androidx.appsearch.app.ReportSystemUsageRequest.Builder setUsageTimestampMillis(long);
+ }
+
+ public final class ReportUsageRequest {
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public long getUsageTimestampMillis();
+ }
+
+ public static final class ReportUsageRequest.Builder {
+ ctor public ReportUsageRequest.Builder(String, String);
+ method public androidx.appsearch.app.ReportUsageRequest build();
+ method public androidx.appsearch.app.ReportUsageRequest.Builder setUsageTimestampMillis(long);
}
public final class SearchResult {
- method public androidx.appsearch.app.GenericDocument getDocument();
- method public java.util.List<androidx.appsearch.app.SearchResult.MatchInfo!> getMatches();
+ method public String getDatabaseName();
+ method public <T> T getDocument(Class<T!>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.GenericDocument getGenericDocument();
+ method public java.util.List<androidx.appsearch.app.SearchResult.MatchInfo!> getMatchInfos();
method public String getPackageName();
+ method public double getRankingSignal();
+ }
+
+ public static final class SearchResult.Builder {
+ ctor public SearchResult.Builder(String, String);
+ method public androidx.appsearch.app.SearchResult.Builder addMatchInfo(androidx.appsearch.app.SearchResult.MatchInfo);
+ method public androidx.appsearch.app.SearchResult build();
+ method public androidx.appsearch.app.SearchResult.Builder setDocument(Object) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchResult.Builder setGenericDocument(androidx.appsearch.app.GenericDocument);
+ method public androidx.appsearch.app.SearchResult.Builder setRankingSignal(double);
}
public static final class SearchResult.MatchInfo {
method public CharSequence getExactMatch();
- method public androidx.appsearch.app.SearchResult.MatchRange getExactMatchPosition();
+ method public androidx.appsearch.app.SearchResult.MatchRange getExactMatchRange();
method public String getFullText();
method public String getPropertyPath();
method public CharSequence getSnippet();
- method public androidx.appsearch.app.SearchResult.MatchRange getSnippetPosition();
+ method public androidx.appsearch.app.SearchResult.MatchRange getSnippetRange();
+ }
+
+ public static final class SearchResult.MatchInfo.Builder {
+ ctor public SearchResult.MatchInfo.Builder(String);
+ method public androidx.appsearch.app.SearchResult.MatchInfo build();
+ method public androidx.appsearch.app.SearchResult.MatchInfo.Builder setExactMatchRange(androidx.appsearch.app.SearchResult.MatchRange);
+ method public androidx.appsearch.app.SearchResult.MatchInfo.Builder setSnippetRange(androidx.appsearch.app.SearchResult.MatchRange);
}
public static final class SearchResult.MatchRange {
+ ctor public SearchResult.MatchRange(int, int);
method public int getEnd();
method public int getStart();
}
@@ -231,16 +386,21 @@
}
public final class SearchSpec {
+ method public java.util.List<java.lang.String!> getFilterNamespaces();
+ method public java.util.List<java.lang.String!> getFilterPackageNames();
+ method public java.util.List<java.lang.String!> getFilterSchemas();
method public int getMaxSnippetSize();
- method public java.util.List<java.lang.String!> getNamespaces();
method public int getOrder();
method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getProjections();
method public int getRankingStrategy();
method public int getResultCountPerPage();
- method public java.util.List<java.lang.String!> getSchemaTypes();
+ method public int getResultGroupingLimit();
+ method public int getResultGroupingTypeFlags();
method public int getSnippetCount();
method public int getSnippetCountPerProperty();
method public int getTermMatch();
+ field public static final int GROUPING_TYPE_PER_NAMESPACE = 2; // 0x2
+ field public static final int GROUPING_TYPE_PER_PACKAGE = 1; // 0x1
field public static final int ORDER_ASCENDING = 1; // 0x1
field public static final int ORDER_DESCENDING = 0; // 0x0
field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
@@ -248,49 +408,102 @@
field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
field public static final int RANKING_STRATEGY_RELEVANCE_SCORE = 3; // 0x3
+ field public static final int RANKING_STRATEGY_SYSTEM_USAGE_COUNT = 6; // 0x6
+ field public static final int RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP = 7; // 0x7
+ field public static final int RANKING_STRATEGY_USAGE_COUNT = 4; // 0x4
+ field public static final int RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP = 5; // 0x5
field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
field public static final int TERM_MATCH_PREFIX = 2; // 0x2
}
public static final class SearchSpec.Builder {
ctor public SearchSpec.Builder();
- method public androidx.appsearch.app.SearchSpec.Builder addNamespace(java.lang.String!...);
- method public androidx.appsearch.app.SearchSpec.Builder addNamespace(java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.SearchSpec.Builder addProjection(String, java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterDocumentClasses(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterDocumentClasses(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterNamespaces(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterNamespaces(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterPackageNames(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterPackageNames(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterSchemas(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder addFilterSchemas(java.util.Collection<java.lang.String!>);
method public androidx.appsearch.app.SearchSpec.Builder addProjection(String, java.util.Collection<java.lang.String!>);
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaByDataClass(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaByDataClass(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaType(java.lang.String!...);
- method public androidx.appsearch.app.SearchSpec.Builder addSchemaType(java.util.Collection<java.lang.String!>);
method public androidx.appsearch.app.SearchSpec build();
method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
method public androidx.appsearch.app.SearchSpec.Builder setResultCountPerPage(@IntRange(from=0, to=0x2710) int);
+ method public androidx.appsearch.app.SearchSpec.Builder setResultGrouping(int, int);
method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(@IntRange(from=0, to=0x2710) int);
method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
}
public final class SetSchemaRequest {
+ method public java.util.Map<java.lang.String!,androidx.appsearch.app.Migrator!> getMigrators();
method public java.util.Set<androidx.appsearch.app.AppSearchSchema!> getSchemas();
- method public java.util.Set<java.lang.String!> getSchemasNotVisibleToSystemUi();
+ method public java.util.Set<java.lang.String!> getSchemasNotDisplayedBySystem();
method public java.util.Map<java.lang.String!,java.util.Set<androidx.appsearch.app.PackageIdentifier!>!> getSchemasVisibleToPackages();
+ method @IntRange(from=1) public int getVersion();
method public boolean isForceOverride();
}
public static final class SetSchemaRequest.Builder {
ctor public SetSchemaRequest.Builder();
- method public androidx.appsearch.app.SetSchemaRequest.Builder addDataClass(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder addDataClass(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder addSchema(androidx.appsearch.app.AppSearchSchema!...);
- method public androidx.appsearch.app.SetSchemaRequest.Builder addSchema(java.util.Collection<androidx.appsearch.app.AppSearchSchema!>);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addDocumentClasses(Class<?>!...) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addDocumentClasses(java.util.Collection<? extends java.lang.Class<?>>) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addSchemas(androidx.appsearch.app.AppSearchSchema!...);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder addSchemas(java.util.Collection<androidx.appsearch.app.AppSearchSchema!>);
method public androidx.appsearch.app.SetSchemaRequest build();
- method public androidx.appsearch.app.SetSchemaRequest.Builder setDataClassVisibilityForPackage(Class<?>, boolean, androidx.appsearch.app.PackageIdentifier) throws androidx.appsearch.exceptions.AppSearchException;
- method public androidx.appsearch.app.SetSchemaRequest.Builder setDataClassVisibilityForSystemUi(Class<?>, boolean) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setDocumentClassDisplayedBySystem(Class<?>, boolean) throws androidx.appsearch.exceptions.AppSearchException;
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setDocumentClassVisibilityForPackage(Class<?>, boolean, androidx.appsearch.app.PackageIdentifier) throws androidx.appsearch.exceptions.AppSearchException;
method public androidx.appsearch.app.SetSchemaRequest.Builder setForceOverride(boolean);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setMigrator(String, androidx.appsearch.app.Migrator);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setMigrators(java.util.Map<java.lang.String!,androidx.appsearch.app.Migrator!>);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeDisplayedBySystem(String, boolean);
method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(String, boolean, androidx.appsearch.app.PackageIdentifier);
- method public androidx.appsearch.app.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(String, boolean);
+ method public androidx.appsearch.app.SetSchemaRequest.Builder setVersion(@IntRange(from=1) int);
+ }
+
+ public class SetSchemaResponse {
+ method public java.util.Set<java.lang.String!> getDeletedTypes();
+ method public java.util.Set<java.lang.String!> getIncompatibleTypes();
+ method public java.util.Set<java.lang.String!> getMigratedTypes();
+ method public java.util.List<androidx.appsearch.app.SetSchemaResponse.MigrationFailure!> getMigrationFailures();
+ }
+
+ public static final class SetSchemaResponse.Builder {
+ ctor public SetSchemaResponse.Builder();
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addDeletedType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addDeletedTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addIncompatibleType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addIncompatibleTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigratedType(String);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigratedTypes(java.util.Collection<java.lang.String!>);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigrationFailure(androidx.appsearch.app.SetSchemaResponse.MigrationFailure);
+ method public androidx.appsearch.app.SetSchemaResponse.Builder addMigrationFailures(java.util.Collection<androidx.appsearch.app.SetSchemaResponse.MigrationFailure!>);
+ method public androidx.appsearch.app.SetSchemaResponse build();
+ }
+
+ public static class SetSchemaResponse.MigrationFailure {
+ ctor public SetSchemaResponse.MigrationFailure(String, String, String, androidx.appsearch.app.AppSearchResult<?>);
+ method public androidx.appsearch.app.AppSearchResult<java.lang.Void!> getAppSearchResult();
+ method public String getDocumentId();
+ method public String getNamespace();
+ method public String getSchemaType();
+ }
+
+ public class StorageInfo {
+ method public int getAliveDocumentsCount();
+ method public int getAliveNamespacesCount();
+ method public long getSizeBytes();
+ }
+
+ public static final class StorageInfo.Builder {
+ ctor public StorageInfo.Builder();
+ method public androidx.appsearch.app.StorageInfo build();
+ method public androidx.appsearch.app.StorageInfo.Builder setAliveDocumentsCount(int);
+ method public androidx.appsearch.app.StorageInfo.Builder setAliveNamespacesCount(int);
+ method public androidx.appsearch.app.StorageInfo.Builder setSizeBytes(long);
}
}
@@ -298,6 +511,9 @@
package androidx.appsearch.exceptions {
public class AppSearchException extends java.lang.Exception {
+ ctor public AppSearchException(int);
+ ctor public AppSearchException(int, String?);
+ ctor public AppSearchException(int, String?, Throwable?);
method public int getResultCode();
method public <T> androidx.appsearch.app.AppSearchResult<T!> toAppSearchResult();
}
diff --git a/appsearch/appsearch/build.gradle b/appsearch/appsearch/build.gradle
index 5760570..05033bec 100644
--- a/appsearch/appsearch/build.gradle
+++ b/appsearch/appsearch/build.gradle
@@ -24,9 +24,8 @@
}
android {
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ buildTypes.all {
+ consumerProguardFiles "proguard-rules.pro"
}
}
@@ -38,6 +37,7 @@
androidTestAnnotationProcessor project(':appsearch:appsearch-compiler')
androidTestImplementation project(':appsearch:appsearch-local-storage')
+ androidTestImplementation project(':appsearch:appsearch-platform-storage')
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRules)
androidTestImplementation(libs.truth)
diff --git a/appsearch/appsearch/proguard-rules.pro b/appsearch/appsearch/proguard-rules.pro
new file mode 100644
index 0000000..a7af3cc
--- /dev/null
+++ b/appsearch/appsearch/proguard-rules.pro
@@ -0,0 +1,16 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+-keep class ** implements androidx.appsearch.app.DocumentClassFactory { *; }
+
+-keep @androidx.appsearch.annotation.Document class *
diff --git a/appsearch/appsearch/src/androidTest/AndroidManifest.xml b/appsearch/appsearch/src/androidTest/AndroidManifest.xml
index 563502a..c2e7297 100644
--- a/appsearch/appsearch/src/androidTest/AndroidManifest.xml
+++ b/appsearch/appsearch/src/androidTest/AndroidManifest.xml
@@ -16,4 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.appsearch.test">
+ <!-- Required for junit TemporaryFolder rule on older API levels -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorLocalTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorLocalTest.java
index 808d90e..b22f8d8 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorLocalTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorLocalTest.java
@@ -29,6 +29,6 @@
protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
Context context = ApplicationProvider.getApplicationContext();
return LocalStorage.createSearchSession(
- new LocalStorage.SearchContext.Builder(context).setDatabaseName(dbName).build());
+ new LocalStorage.SearchContext.Builder(context, dbName).build());
}
}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorPlatformTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorPlatformTest.java
new file mode 100644
index 0000000..5dbb8a2
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorPlatformTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.app;
+
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.platformstorage.PlatformStorage;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+public class AnnotationProcessorPlatformTest extends AnnotationProcessorTestBase {
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return PlatformStorage.createSearchSession(
+ new PlatformStorage.SearchContext.Builder(context, dbName).build());
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
index 58b80b0..012565b 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
@@ -16,16 +16,16 @@
// @exportToFramework:skipFile()
package androidx.appsearch.app;
-import static androidx.appsearch.app.AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
-import static androidx.appsearch.app.AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN;
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
import static androidx.appsearch.app.util.AppSearchTestUtils.convertSearchResultsToDocuments;
import static com.google.common.truth.Truth.assertThat;
import androidx.annotation.NonNull;
-import androidx.appsearch.annotation.AppSearchDocument;
-import androidx.appsearch.localstorage.LocalStorage;
+import androidx.appsearch.annotation.Document;
+import androidx.appsearch.app.util.AppSearchEmail;
import com.google.common.util.concurrent.ListenableFuture;
@@ -39,7 +39,7 @@
public abstract class AnnotationProcessorTestBase {
private AppSearchSession mSession;
- private static final String DB_NAME_1 = LocalStorage.DEFAULT_DATABASE_NAME;
+ private static final String DB_NAME_1 = "";
protected abstract ListenableFuture<AppSearchSession> createSearchSession(
@NonNull String dbName);
@@ -63,11 +63,18 @@
mSession.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
}
- @AppSearchDocument
+ @Document
static class Card {
- @AppSearchDocument.Uri
- String mUri;
- @AppSearchDocument.Property
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.Id
+ String mId;
+
+ @Document.CreationTimestampMillis
+ long mCreationTimestampMillis;
+
+ @Document.StringProperty
(indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
String mString; // 3a
@@ -80,90 +87,96 @@
return false;
}
Card otherCard = (Card) other;
- assertThat(otherCard.mUri).isEqualTo(this.mUri);
+ assertThat(otherCard.mId).isEqualTo(this.mId);
return true;
}
}
- @AppSearchDocument
+ @Document
static class Gift {
- @AppSearchDocument.Uri
- String mUri;
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.Id
+ String mId;
+
+ @Document.CreationTimestampMillis
+ long mCreationTimestampMillis;
// Collections
- @AppSearchDocument.Property
+ @Document.LongProperty
Collection<Long> mCollectLong; // 1a
- @AppSearchDocument.Property
+ @Document.LongProperty
Collection<Integer> mCollectInteger; // 1a
- @AppSearchDocument.Property
+ @Document.DoubleProperty
Collection<Double> mCollectDouble; // 1a
- @AppSearchDocument.Property
+ @Document.DoubleProperty
Collection<Float> mCollectFloat; // 1a
- @AppSearchDocument.Property
+ @Document.BooleanProperty
Collection<Boolean> mCollectBoolean; // 1a
- @AppSearchDocument.Property
+ @Document.BytesProperty
Collection<byte[]> mCollectByteArr; // 1a
- @AppSearchDocument.Property
+ @Document.StringProperty
Collection<String> mCollectString; // 1b
- @AppSearchDocument.Property
+ @Document.DocumentProperty
Collection<Card> mCollectCard; // 1c
// Arrays
- @AppSearchDocument.Property
+ @Document.LongProperty
Long[] mArrBoxLong; // 2a
- @AppSearchDocument.Property
+ @Document.LongProperty
long[] mArrUnboxLong; // 2b
- @AppSearchDocument.Property
+ @Document.LongProperty
Integer[] mArrBoxInteger; // 2a
- @AppSearchDocument.Property
+ @Document.LongProperty
int[] mArrUnboxInt; // 2a
- @AppSearchDocument.Property
+ @Document.DoubleProperty
Double[] mArrBoxDouble; // 2a
- @AppSearchDocument.Property
+ @Document.DoubleProperty
double[] mArrUnboxDouble; // 2b
- @AppSearchDocument.Property
+ @Document.DoubleProperty
Float[] mArrBoxFloat; // 2a
- @AppSearchDocument.Property
+ @Document.DoubleProperty
float[] mArrUnboxFloat; // 2a
- @AppSearchDocument.Property
+ @Document.BooleanProperty
Boolean[] mArrBoxBoolean; // 2a
- @AppSearchDocument.Property
+ @Document.BooleanProperty
boolean[] mArrUnboxBoolean; // 2b
- @AppSearchDocument.Property
+ @Document.BytesProperty
byte[][] mArrUnboxByteArr; // 2b
- @AppSearchDocument.Property
+ @Document.BytesProperty
Byte[] mBoxByteArr; // 2a
- @AppSearchDocument.Property
+ @Document.StringProperty
String[] mArrString; // 2b
- @AppSearchDocument.Property
+ @Document.DocumentProperty
Card[] mArrCard; // 2c
// Single values
- @AppSearchDocument.Property
+ @Document.StringProperty
String mString; // 3a
- @AppSearchDocument.Property
+ @Document.LongProperty
Long mBoxLong; // 3a
- @AppSearchDocument.Property
+ @Document.LongProperty
long mUnboxLong; // 3b
- @AppSearchDocument.Property
+ @Document.LongProperty
Integer mBoxInteger; // 3a
- @AppSearchDocument.Property
+ @Document.LongProperty
int mUnboxInt; // 3b
- @AppSearchDocument.Property
+ @Document.DoubleProperty
Double mBoxDouble; // 3a
- @AppSearchDocument.Property
+ @Document.DoubleProperty
double mUnboxDouble; // 3b
- @AppSearchDocument.Property
+ @Document.DoubleProperty
Float mBoxFloat; // 3a
- @AppSearchDocument.Property
+ @Document.DoubleProperty
float mUnboxFloat; // 3b
- @AppSearchDocument.Property
+ @Document.BooleanProperty
Boolean mBoxBoolean; // 3a
- @AppSearchDocument.Property
+ @Document.BooleanProperty
boolean mUnboxBoolean; // 3b
- @AppSearchDocument.Property
+ @Document.BytesProperty
byte[] mUnboxByteArr; // 3a
- @AppSearchDocument.Property
+ @Document.DocumentProperty
Card mCard; // 3c
@Override
@@ -175,7 +188,8 @@
return false;
}
Gift otherGift = (Gift) other;
- assertThat(otherGift.mUri).isEqualTo(this.mUri);
+ assertThat(otherGift.mNamespace).isEqualTo(this.mNamespace);
+ assertThat(otherGift.mId).isEqualTo(this.mId);
assertThat(otherGift.mArrBoxBoolean).isEqualTo(this.mArrBoxBoolean);
assertThat(otherGift.mArrBoxDouble).isEqualTo(this.mArrBoxDouble);
assertThat(otherGift.mArrBoxFloat).isEqualTo(this.mArrBoxFloat);
@@ -224,132 +238,152 @@
assertThat(second).isNotNull();
assertThat(first.toArray()).isEqualTo(second.toArray());
}
+
+ public static Gift createPopulatedGift() {
+ Gift gift = new Gift();
+ gift.mNamespace = "gift.namespace";
+ gift.mId = "gift.id";
+
+ gift.mArrBoxBoolean = new Boolean[]{true, false};
+ gift.mArrBoxDouble = new Double[]{0.0, 1.0};
+ gift.mArrBoxFloat = new Float[]{2.0F, 3.0F};
+ gift.mArrBoxInteger = new Integer[]{4, 5};
+ gift.mArrBoxLong = new Long[]{6L, 7L};
+ gift.mArrString = new String[]{"cat", "dog"};
+ gift.mBoxByteArr = new Byte[]{8, 9};
+ gift.mArrUnboxBoolean = new boolean[]{false, true};
+ gift.mArrUnboxByteArr = new byte[][]{{0, 1}, {2, 3}};
+ gift.mArrUnboxDouble = new double[]{1.0, 0.0};
+ gift.mArrUnboxFloat = new float[]{3.0f, 2.0f};
+ gift.mArrUnboxInt = new int[]{5, 4};
+ gift.mArrUnboxLong = new long[]{7, 6};
+
+ Card card1 = new Card();
+ card1.mNamespace = "card.namespace";
+ card1.mId = "card.id1";
+ Card card2 = new Card();
+ card2.mNamespace = "card.namespace";
+ card2.mId = "card.id2";
+ gift.mArrCard = new Card[]{card2, card2};
+
+ gift.mCollectLong = Arrays.asList(gift.mArrBoxLong);
+ gift.mCollectInteger = Arrays.asList(gift.mArrBoxInteger);
+ gift.mCollectBoolean = Arrays.asList(gift.mArrBoxBoolean);
+ gift.mCollectString = Arrays.asList(gift.mArrString);
+ gift.mCollectDouble = Arrays.asList(gift.mArrBoxDouble);
+ gift.mCollectFloat = Arrays.asList(gift.mArrBoxFloat);
+ gift.mCollectByteArr = Arrays.asList(gift.mArrUnboxByteArr);
+ gift.mCollectCard = Arrays.asList(card2, card2);
+
+ gift.mString = "String";
+ gift.mBoxLong = 1L;
+ gift.mUnboxLong = 2L;
+ gift.mBoxInteger = 3;
+ gift.mUnboxInt = 4;
+ gift.mBoxDouble = 5.0;
+ gift.mUnboxDouble = 6.0;
+ gift.mBoxFloat = 7.0F;
+ gift.mUnboxFloat = 8.0f;
+ gift.mBoxBoolean = true;
+ gift.mUnboxBoolean = false;
+ gift.mUnboxByteArr = new byte[]{1, 2, 3};
+ gift.mCard = card1;
+
+ return gift;
+ }
}
@Test
public void testAnnotationProcessor() throws Exception {
//TODO(b/156296904) add test for int, float, GenericDocument, and class with
- // @AppSearchDocument annotation
+ // @Document annotation
mSession.setSchema(
- new SetSchemaRequest.Builder().addDataClass(Card.class, Gift.class).build()).get();
+ new SetSchemaRequest.Builder().addDocumentClasses(Card.class, Gift.class).build())
+ .get();
// Create a Gift object and assign values.
- Gift inputDataClass = new Gift();
- inputDataClass.mUri = "gift.uri";
-
- inputDataClass.mArrBoxBoolean = new Boolean[]{true, false};
- inputDataClass.mArrBoxDouble = new Double[]{0.0, 1.0};
- inputDataClass.mArrBoxFloat = new Float[]{2.0F, 3.0F};
- inputDataClass.mArrBoxInteger = new Integer[]{4, 5};
- inputDataClass.mArrBoxLong = new Long[]{6L, 7L};
- inputDataClass.mArrString = new String[]{"cat", "dog"};
- inputDataClass.mBoxByteArr = new Byte[]{8, 9};
- inputDataClass.mArrUnboxBoolean = new boolean[]{false, true};
- inputDataClass.mArrUnboxByteArr = new byte[][]{{0, 1}, {2, 3}};
- inputDataClass.mArrUnboxDouble = new double[]{1.0, 0.0};
- inputDataClass.mArrUnboxFloat = new float[]{3.0f, 2.0f};
- inputDataClass.mArrUnboxInt = new int[]{5, 4};
- inputDataClass.mArrUnboxLong = new long[]{7, 6};
-
- Card card1 = new Card();
- card1.mUri = "card.uri1";
- Card card2 = new Card();
- card2.mUri = "card.uri2";
- inputDataClass.mArrCard = new Card[]{card2, card2};
-
- inputDataClass.mCollectLong = Arrays.asList(inputDataClass.mArrBoxLong);
- inputDataClass.mCollectInteger = Arrays.asList(inputDataClass.mArrBoxInteger);
- inputDataClass.mCollectBoolean = Arrays.asList(inputDataClass.mArrBoxBoolean);
- inputDataClass.mCollectString = Arrays.asList(inputDataClass.mArrString);
- inputDataClass.mCollectDouble = Arrays.asList(inputDataClass.mArrBoxDouble);
- inputDataClass.mCollectFloat = Arrays.asList(inputDataClass.mArrBoxFloat);
- inputDataClass.mCollectByteArr = Arrays.asList(inputDataClass.mArrUnboxByteArr);
- inputDataClass.mCollectCard = Arrays.asList(card2, card2);
-
- inputDataClass.mString = "String";
- inputDataClass.mBoxLong = 1L;
- inputDataClass.mUnboxLong = 2L;
- inputDataClass.mBoxInteger = 3;
- inputDataClass.mUnboxInt = 4;
- inputDataClass.mBoxDouble = 5.0;
- inputDataClass.mUnboxDouble = 6.0;
- inputDataClass.mBoxFloat = 7.0F;
- inputDataClass.mUnboxFloat = 8.0f;
- inputDataClass.mBoxBoolean = true;
- inputDataClass.mUnboxBoolean = false;
- inputDataClass.mUnboxByteArr = new byte[]{1, 2, 3};
- inputDataClass.mCard = card1;
+ Gift inputDocument = Gift.createPopulatedGift();
// Index the Gift document and query it.
- checkIsBatchResultSuccess(mSession.putDocuments(
- new PutDocumentsRequest.Builder().addDataClass(inputDataClass).build()));
- SearchResults searchResults = mSession.query("", new SearchSpec.Builder()
+ checkIsBatchResultSuccess(mSession.put(
+ new PutDocumentsRequest.Builder().addDocuments(inputDocument).build()));
+ SearchResults searchResults = mSession.search("", new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
.build());
List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
assertThat(documents).hasSize(1);
- // Create DataClassFactory for Gift.
- DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
- DataClassFactory<Gift> factory = registry.getOrCreateFactory(Gift.class);
-
// Convert GenericDocument to Gift and check values.
- Gift outputDataClass = factory.fromGenericDocument(documents.get((0)));
- assertThat(outputDataClass).isEqualTo(inputDataClass);
+ Gift outputDocument = documents.get(0).toDocumentClass(Gift.class);
+ assertThat(outputDocument).isEqualTo(inputDocument);
}
@Test
public void testAnnotationProcessor_queryByType() throws Exception {
mSession.setSchema(
new SetSchemaRequest.Builder()
- .addDataClass(Card.class, Gift.class)
- .addSchema(AppSearchEmail.SCHEMA).build())
+ .addDocumentClasses(Card.class, Gift.class)
+ .addSchemas(AppSearchEmail.SCHEMA).build())
.get();
// Create documents and index them
- Gift inputDataClass1 = new Gift();
- inputDataClass1.mUri = "gift.uri1";
- Gift inputDataClass2 = new Gift();
- inputDataClass2.mUri = "gift.uri2";
+ Gift inputDocument1 = new Gift();
+ inputDocument1.mNamespace = "gift.namespace";
+ inputDocument1.mId = "gift.id1";
+ Gift inputDocument2 = new Gift();
+ inputDocument2.mNamespace = "gift.namespace";
+ inputDocument2.mId = "gift.id2";
AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri3")
- .setNamespace("namespace")
+ new AppSearchEmail.Builder("namespace", "id3")
.setFrom("from@example.com")
.setTo("to1@example.com", "to2@example.com")
.setSubject("testPut example")
.setBody("This is the body of the testPut email")
.build();
- checkIsBatchResultSuccess(mSession.putDocuments(
+ checkIsBatchResultSuccess(mSession.put(
new PutDocumentsRequest.Builder()
- .addDataClass(inputDataClass1, inputDataClass2)
- .addGenericDocument(email1).build()));
+ .addDocuments(inputDocument1, inputDocument2)
+ .addGenericDocuments(email1).build()));
// Query the documents by it's schema type.
- SearchResults searchResults = mSession.query("",
+ SearchResults searchResults = mSession.search("",
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addSchemaType("Gift", AppSearchEmail.SCHEMA_TYPE)
+ .addFilterSchemas("Gift", AppSearchEmail.SCHEMA_TYPE)
.build());
List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
assertThat(documents).hasSize(3);
// Query the documents by it's class.
- searchResults = mSession.query("",
+ searchResults = mSession.search("",
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addSchemaByDataClass(Gift.class)
+ .addFilterDocumentClasses(Gift.class)
.build());
documents = convertSearchResultsToDocuments(searchResults);
assertThat(documents).hasSize(2);
// Query the documents by schema type and class mix.
- searchResults = mSession.query("",
+ searchResults = mSession.search("",
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addSchemaType(AppSearchEmail.SCHEMA_TYPE)
- .addSchemaByDataClass(Gift.class)
+ .addFilterSchemas(AppSearchEmail.SCHEMA_TYPE)
+ .addFilterDocumentClasses(Gift.class)
.build());
documents = convertSearchResultsToDocuments(searchResults);
assertThat(documents).hasSize(3);
}
+
+ @Test
+ public void testGenericDocumentConversion() throws Exception {
+ Gift inGift = Gift.createPopulatedGift();
+ GenericDocument genericDocument1 = GenericDocument.fromDocumentClass(inGift);
+ GenericDocument genericDocument2 = GenericDocument.fromDocumentClass(inGift);
+ Gift outGift = genericDocument2.toDocumentClass(Gift.class);
+
+ assertThat(inGift).isNotSameInstanceAs(outGift);
+ assertThat(inGift).isEqualTo(outGift);
+ assertThat(genericDocument1).isNotSameInstanceAs(genericDocument2);
+ assertThat(genericDocument1).isEqualTo(genericDocument2);
+ }
}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchEmailTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchEmailTest.java
index ee68c88..ef88e46 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchEmailTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchEmailTest.java
@@ -18,13 +18,15 @@
import static com.google.common.truth.Truth.assertThat;
+import androidx.appsearch.app.util.AppSearchEmail;
+
import org.junit.Test;
public class AppSearchEmailTest {
@Test
public void testBuildEmailAndGetValue() {
- AppSearchEmail email = new AppSearchEmail.Builder("uri")
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace", "id")
.setFrom("FakeFromAddress")
.setCc("CC1", "CC2")
// Score and Property are mixed into the middle to make sure DocumentBuilder's
@@ -35,7 +37,8 @@
.setBody("EmailBody")
.build();
- assertThat(email.getUri()).isEqualTo("uri");
+ assertThat(email.getNamespace()).isEqualTo("namespace");
+ assertThat(email.getId()).isEqualTo("id");
assertThat(email.getFrom()).isEqualTo("FakeFromAddress");
assertThat(email.getTo()).isNull();
assertThat(email.getCc()).asList().containsExactly("CC1", "CC2");
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchResultTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchResultTest.java
new file mode 100644
index 0000000..125e55f
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchResultTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Test;
+
+public class AppSearchResultTest {
+ @Test
+ public void testMapNullPointerException() {
+ NullPointerException e = assertThrows(NullPointerException.class, () -> {
+ Object o = null;
+ o.toString();
+ });
+ AppSearchResult<?> result = AppSearchResult.throwableToFailedResult(e);
+ assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
+ // Makes sure the exception name is included in the string. Some exceptions have terse or
+ // missing strings so it's confusing to read the output without the exception name.
+ assertThat(result.getErrorMessage()).startsWith("NullPointerException");
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
new file mode 100644
index 0000000..c15f290
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+public class GenericDocumentTest {
+ @Test
+ public void testRecreateFromParcel() {
+ GenericDocument inDoc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyString("propString", "Hello")
+ .setPropertyBytes("propBytes", new byte[][]{{1, 2}})
+ .setPropertyDocument(
+ "propDocument",
+ new GenericDocument.Builder<>("namespace", "id2", "schema2")
+ .setPropertyString("propString", "Goodbye")
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build())
+ .build();
+
+ // Serialize the document
+ Parcel inParcel = Parcel.obtain();
+ inParcel.writeBundle(inDoc.getBundle());
+ byte[] data = inParcel.marshall();
+ inParcel.recycle();
+
+ // Deserialize the document
+ Parcel outParcel = Parcel.obtain();
+ outParcel.unmarshall(data, 0, data.length);
+ outParcel.setDataPosition(0);
+ Bundle outBundle = outParcel.readBundle();
+ outParcel.recycle();
+
+ // Compare results
+ GenericDocument outDoc = new GenericDocument(outBundle);
+ assertThat(inDoc).isEqualTo(outDoc);
+ assertThat(outDoc.getPropertyString("propString")).isEqualTo("Hello");
+ assertThat(outDoc.getPropertyBytesArray("propBytes")).isEqualTo(new byte[][]{{1, 2}});
+ assertThat(outDoc.getPropertyDocument("propDocument").getPropertyString("propString"))
+ .isEqualTo("Goodbye");
+ assertThat(outDoc.getPropertyDocument("propDocument").getPropertyBytesArray("propBytes"))
+ .isEqualTo(new byte[][]{{3, 4}});
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/PutDocumentsRequestTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/PutDocumentsRequestTest.java
deleted file mode 100644
index bd61231..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/PutDocumentsRequestTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app;
-
-import static androidx.appsearch.app.AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-
-import androidx.appsearch.annotation.AppSearchDocument;
-import androidx.appsearch.localstorage.LocalStorage;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Test;
-
-import java.util.Set;
-
-public class PutDocumentsRequestTest {
-
- @Test
- public void addGenericDocument_byCollection() {
- Set<AppSearchEmail> emails = ImmutableSet.of(new AppSearchEmail.Builder("test1").build(),
- new AppSearchEmail.Builder("test2").build());
- PutDocumentsRequest request = new PutDocumentsRequest.Builder().addGenericDocument(emails)
- .build();
-
- assertThat(request.getDocuments().get(0).getUri()).isEqualTo("test1");
- assertThat(request.getDocuments().get(1).getUri()).isEqualTo("test2");
- }
-
-// @exportToFramework:startStrip()
- @AppSearchDocument
- static class Card {
- @AppSearchDocument.Uri
- String mUri;
-
- @AppSearchDocument.Property(indexingType = INDEXING_TYPE_PREFIXES)
- String mString;
-
- Card(String mUri, String mString) {
- this.mUri = mUri;
- this.mString = mString;
- }
- }
-
- @Test
- public void addDataClass_byCollection() throws Exception {
- // A schema with Card must be set in order to be able to add a Card instance to
- // PutDocumentsRequest.
- Context context = ApplicationProvider.getApplicationContext();
- AppSearchSession session = LocalStorage.createSearchSession(
- new LocalStorage.SearchContext.Builder(context)
- .setDatabaseName(LocalStorage.DEFAULT_DATABASE_NAME)
- .build()
- ).get();
- session.setSchema(new SetSchemaRequest.Builder().addDataClass(Card.class).build()).get();
-
- Set<Card> cards = ImmutableSet.of(new Card("cardUri", "cardProperty"));
- PutDocumentsRequest request = new PutDocumentsRequest.Builder().addDataClass(cards)
- .build();
-
- assertThat(request.getDocuments().get(0).getUri()).isEqualTo("cardUri");
- }
-// @exportToFramework:endStrip()
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SearchSpecTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SearchSpecTest.java
index 5d98ead..19ccc63 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SearchSpecTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SearchSpecTest.java
@@ -16,31 +16,21 @@
package androidx.appsearch.app;
-import static androidx.appsearch.app.AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
-import static androidx.appsearch.app.AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN;
-
import static com.google.common.truth.Truth.assertThat;
import android.os.Bundle;
-import androidx.appsearch.annotation.AppSearchDocument;
-
-import com.google.common.collect.ImmutableSet;
-
import org.junit.Test;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
public class SearchSpecTest {
@Test
public void testGetBundle() {
SearchSpec searchSpec = new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addNamespace("namespace1", "namespace2")
- .addSchemaType("schemaTypes1", "schemaTypes2")
+ .addFilterNamespaces("namespace1", "namespace2")
+ .addFilterSchemas("schemaTypes1", "schemaTypes2")
+ .addFilterPackageNames("package1", "package2")
.setSnippetCount(5)
.setSnippetCountPerProperty(10)
.setMaxSnippetSize(15)
@@ -54,8 +44,10 @@
.isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
assertThat(bundle.getStringArrayList(SearchSpec.NAMESPACE_FIELD)).containsExactly(
"namespace1", "namespace2");
- assertThat(bundle.getStringArrayList(SearchSpec.SCHEMA_TYPE_FIELD)).containsExactly(
+ assertThat(bundle.getStringArrayList(SearchSpec.SCHEMA_FIELD)).containsExactly(
"schemaTypes1", "schemaTypes2");
+ assertThat(bundle.getStringArrayList(SearchSpec.PACKAGE_NAME_FIELD)).containsExactly(
+ "package1", "package2");
assertThat(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD)).isEqualTo(5);
assertThat(bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD)).isEqualTo(10);
assertThat(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD)).isEqualTo(15);
@@ -64,58 +56,4 @@
assertThat(bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD))
.isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
}
-
- @Test
- public void testGetProjectionTypePropertyMasks() {
- SearchSpec searchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addProjection("TypeA", "field1", "field2.subfield2")
- .addProjection("TypeB", "field7")
- .addProjection("TypeC")
- .build();
-
- Map<String, List<String>> typePropertyPathMap = searchSpec.getProjections();
- assertThat(typePropertyPathMap.keySet())
- .containsExactly("TypeA", "TypeB", "TypeC");
- assertThat(typePropertyPathMap.get("TypeA")).containsExactly("field1", "field2.subfield2");
- assertThat(typePropertyPathMap.get("TypeB")).containsExactly("field7");
- assertThat(typePropertyPathMap.get("TypeC")).isEmpty();
- }
-
- @Test
- public void testGetRankingStrategy() {
- SearchSpec searchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
- .build();
- assertThat(searchSpec.getRankingStrategy()).isEqualTo(
- SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE);
- }
-
-// @exportToFramework:startStrip()
- @AppSearchDocument
- static class King extends Card {
- @AppSearchDocument.Uri
- String mUri;
-
- @AppSearchDocument.Property
- (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
- String mString;
- }
-
- static class Card {}
-
- @Test
- public void testAddSchemaByDataClass_byCollection() throws Exception {
- Set<Class<King>> cardClassSet = ImmutableSet.of(King.class);
- SearchSpec searchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addSchemaByDataClass(cardClassSet)
- .build();
-
- Bundle bundle = searchSpec.getBundle();
- assertThat(bundle.getStringArrayList(SearchSpec.SCHEMA_TYPE_FIELD)).containsExactly(
- "King");
- }
-// @exportToFramework:endStrip()
}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SetSchemaRequestTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SetSchemaRequestTest.java
deleted file mode 100644
index 4b8b21d..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SetSchemaRequestTest.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app;
-
-import static androidx.appsearch.app.AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
-import static androidx.appsearch.app.AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-import androidx.appsearch.annotation.AppSearchDocument;
-import androidx.collection.ArrayMap;
-
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Test;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class SetSchemaRequestTest {
-// @exportToFramework:startStrip()
- @AppSearchDocument
- static class Card {
- @AppSearchDocument.Uri
- String mUri;
-
- @AppSearchDocument.Property
- (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
- String mString;
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof AnnotationProcessorTestBase.Card)) {
- return false;
- }
- AnnotationProcessorTestBase.Card otherCard = (AnnotationProcessorTestBase.Card) other;
- assertThat(otherCard.mUri).isEqualTo(this.mUri);
- return true;
- }
- }
-
- static class Spade {}
-
- @AppSearchDocument
- static class King extends Spade {
- @AppSearchDocument.Uri
- String mUri;
-
- @AppSearchDocument.Property
- (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
- String mString;
- }
-
- @AppSearchDocument
- static class Queen extends Spade {
- @AppSearchDocument.Uri
- String mUri;
-
- @AppSearchDocument.Property
- (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
- String mString;
- }
-// @exportToFramework:endStrip()
-
- private static Collection<String> getSchemaTypesFromSetSchemaRequest(SetSchemaRequest request) {
- HashSet<String> schemaTypes = new HashSet<>();
- for (AppSearchSchema schema : request.getSchemas()) {
- schemaTypes.add(schema.getSchemaType());
- }
- return schemaTypes;
- }
-
- @Test
- public void testInvalidSchemaReferences_fromSystemUiVisibility() {
- IllegalArgumentException expected = assertThrows(IllegalArgumentException.class,
- () -> new SetSchemaRequest.Builder().setSchemaTypeVisibilityForSystemUi(
- "InvalidSchema", false).build());
- assertThat(expected).hasMessageThat().contains("referenced, but were not added");
- }
-
- @Test
- public void testInvalidSchemaReferences_fromPackageVisibility() {
- IllegalArgumentException expected = assertThrows(IllegalArgumentException.class,
- () -> new SetSchemaRequest.Builder().setSchemaTypeVisibilityForPackage(
- "InvalidSchema", /*visible=*/ true, new PackageIdentifier(
- "com.foo.package", /*sha256Certificate=*/ new byte[]{})).build());
- assertThat(expected).hasMessageThat().contains("referenced, but were not added");
- }
-
- @Test
- public void testSchemaTypeVisibilityForSystemUi_visible() {
- AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
-
- // By default, the schema is visible.
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addSchema(schema).build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty();
-
- request =
- new SetSchemaRequest.Builder().addSchema(schema).setSchemaTypeVisibilityForSystemUi(
- "Schema", true).build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty();
- }
-
- @Test
- public void testSchemaTypeVisibilityForSystemUi_notVisible() {
- AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addSchema(schema).setSchemaTypeVisibilityForSystemUi(
- "Schema", false).build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).containsExactly("Schema");
- }
-
-// @exportToFramework:startStrip()
- @Test
- public void testDataClassVisibilityForSystemUi_visible() throws Exception {
- // By default, the schema is visible.
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(Card.class).build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty();
-
- request =
- new SetSchemaRequest.Builder().addDataClass(
- Card.class).setDataClassVisibilityForSystemUi(
- Card.class, true).build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty();
- }
-
- @Test
- public void testDataClassVisibilityForSystemUi_notVisible() throws Exception {
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(
- Card.class).setDataClassVisibilityForSystemUi(
- Card.class, false).build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).containsExactly("Card");
- }
-// @exportToFramework:endStrip()
-
- @Test
- public void testSchemaTypeVisibilityForPackage_visible() {
- AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
-
- // By default, the schema is not visible.
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addSchema(schema).build();
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
-
- PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
- new byte[]{100});
- Map<String, Set<PackageIdentifier>> expectedVisibleToPackagesMap = new ArrayMap<>();
- expectedVisibleToPackagesMap.put("Schema", Collections.singleton(packageIdentifier));
-
- request =
- new SetSchemaRequest.Builder().addSchema(schema).setSchemaTypeVisibilityForPackage(
- "Schema", /*visible=*/ true, packageIdentifier).build();
- assertThat(request.getSchemasVisibleToPackages()).containsExactlyEntriesIn(
- expectedVisibleToPackagesMap);
- }
-
- @Test
- public void testSchemaTypeVisibilityForPackage_notVisible() {
- AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
-
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addSchema(schema).setSchemaTypeVisibilityForPackage(
- "Schema", /*visible=*/ false, new PackageIdentifier("com.package.foo",
- /*sha256Certificate=*/ new byte[]{})).build();
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
- }
-
- @Test
- public void testSchemaTypeVisibilityForPackage_deduped() throws Exception {
- AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
-
- PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
- new byte[]{100});
- Map<String, Set<PackageIdentifier>> expectedVisibleToPackagesMap = new ArrayMap<>();
- expectedVisibleToPackagesMap.put("Schema", Collections.singleton(packageIdentifier));
-
- SetSchemaRequest request =
- new SetSchemaRequest.Builder()
- .addSchema(schema)
- // Set it visible for "Schema"
- .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
- true, packageIdentifier)
- // Set it visible for "Schema" again, which should be a no-op
- .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
- true, packageIdentifier)
- .build();
- assertThat(request.getSchemasVisibleToPackages()).containsExactlyEntriesIn(
- expectedVisibleToPackagesMap);
- }
-
- @Test
- public void testSchemaTypeVisibilityForPackage_removed() throws Exception {
- AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
-
- SetSchemaRequest request =
- new SetSchemaRequest.Builder()
- .addSchema(schema)
- // First set it as visible
- .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
- true, new PackageIdentifier("com.package.foo",
- /*sha256Certificate=*/ new byte[]{100}))
- // Then make it not visible
- .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
- false, new PackageIdentifier("com.package.foo",
- /*sha256Certificate=*/ new byte[]{100}))
- .build();
-
- // Nothing should be visible.
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
- }
-
-// @exportToFramework:startStrip()
- @Test
- public void testDataClassVisibilityForPackage_visible() throws Exception {
- // By default, the schema is not visible.
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(Card.class).build();
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
-
- PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
- new byte[]{100});
- Map<String, Set<PackageIdentifier>> expectedVisibleToPackagesMap = new ArrayMap<>();
- expectedVisibleToPackagesMap.put("Card", Collections.singleton(packageIdentifier));
-
- request =
- new SetSchemaRequest.Builder().addDataClass(
- Card.class).setDataClassVisibilityForPackage(
- Card.class, /*visible=*/ true, packageIdentifier).build();
- assertThat(request.getSchemasVisibleToPackages()).containsExactlyEntriesIn(
- expectedVisibleToPackagesMap);
- }
-
- @Test
- public void testDataClassVisibilityForPackage_notVisible() throws Exception {
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(
- Card.class).setDataClassVisibilityForPackage(
- Card.class, /*visible=*/ false,
- new PackageIdentifier("com.package.foo", /*sha256Certificate=*/
- new byte[]{})).build();
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
- }
-
- @Test
- public void testDataClassVisibilityForPackage_deduped() throws Exception {
- // By default, the schema is not visible.
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(Card.class).build();
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
-
- PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
- new byte[]{100});
- Map<String, Set<PackageIdentifier>> expectedVisibleToPackagesMap = new ArrayMap<>();
- expectedVisibleToPackagesMap.put("Card", Collections.singleton(packageIdentifier));
-
- request =
- new SetSchemaRequest.Builder()
- .addDataClass(Card.class)
- .setDataClassVisibilityForPackage(Card.class, /*visible=*/
- true, packageIdentifier)
- .setDataClassVisibilityForPackage(Card.class, /*visible=*/
- true, packageIdentifier)
- .build();
- assertThat(request.getSchemasVisibleToPackages()).containsExactlyEntriesIn(
- expectedVisibleToPackagesMap);
- }
-
- @Test
- public void testDataClassVisibilityForPackage_removed() throws Exception {
- // By default, the schema is not visible.
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(Card.class).build();
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
-
- request =
- new SetSchemaRequest.Builder()
- .addDataClass(Card.class)
- // First set it as visible
- .setDataClassVisibilityForPackage(Card.class, /*visible=*/
- true, new PackageIdentifier("com.package.foo",
- /*sha256Certificate=*/ new byte[]{100}))
- // Then make it not visible
- .setDataClassVisibilityForPackage(Card.class, /*visible=*/
- false, new PackageIdentifier("com.package.foo",
- /*sha256Certificate=*/ new byte[]{100}))
- .build();
-
- // Nothing should be visible.
- assertThat(request.getSchemasVisibleToPackages()).isEmpty();
- }
-
- @Test
- public void testAddDataClass_byCollection() throws Exception {
- Set<Class<? extends Spade>> cardClasses = ImmutableSet.of(Queen.class, King.class);
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(cardClasses)
- .build();
- assertThat(getSchemaTypesFromSetSchemaRequest(request)).containsExactly("Queen",
- "King");
- }
-
- @Test
- public void testAddDataClass_byCollectionWithSeparateCalls() throws
- Exception {
- SetSchemaRequest request =
- new SetSchemaRequest.Builder().addDataClass(ImmutableSet.of(Queen.class))
- .addDataClass(ImmutableSet.of(King.class)).build();
- assertThat(getSchemaTypesFromSetSchemaRequest(request)).containsExactly("Queen",
- "King");
- }
-// @exportToFramework:endStrip()
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SetSchemaResponseTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SetSchemaResponseTest.java
new file mode 100644
index 0000000..8aa6148
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/SetSchemaResponseTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class SetSchemaResponseTest {
+ @Test
+ public void testRebuild() {
+ SetSchemaResponse.MigrationFailure failure1 = new SetSchemaResponse.MigrationFailure(
+ "namespace",
+ "failure1",
+ "schemaType",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+ SetSchemaResponse.MigrationFailure failure2 = new SetSchemaResponse.MigrationFailure(
+ "namespace",
+ "failure2",
+ "schemaType",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+
+ SetSchemaResponse original = new SetSchemaResponse.Builder()
+ .addDeletedType("delete1")
+ .addIncompatibleType("incompatible1")
+ .addMigratedType("migrated1")
+ .addMigrationFailure(failure1)
+ .build();
+ assertThat(original.getDeletedTypes()).containsExactly("delete1");
+ assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+ assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+ assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+ SetSchemaResponse rebuild = original.toBuilder()
+ .addDeletedType("delete2")
+ .addIncompatibleType("incompatible2")
+ .addMigratedType("migrated2")
+ .addMigrationFailure(failure2)
+ .build();
+
+ // rebuild won't effect the original object
+ assertThat(original.getDeletedTypes()).containsExactly("delete1");
+ assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+ assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+ assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+ assertThat(rebuild.getDeletedTypes()).containsExactly("delete1", "delete2");
+ assertThat(rebuild.getIncompatibleTypes()).containsExactly("incompatible1",
+ "incompatible2");
+ assertThat(rebuild.getMigratedTypes()).containsExactly("migrated1", "migrated2");
+ assertThat(rebuild.getMigrationFailures()).containsExactly(failure1, failure2);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchResultCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchResultCtsTest.java
deleted file mode 100644
index 5899068..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchResultCtsTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appsearch.app.AppSearchResult;
-
-import org.junit.Test;
-
-public class AppSearchResultCtsTest {
-
- @Test
- public void testResultEquals_identical() {
- AppSearchResult<String> result1 = AppSearchResult.newSuccessfulResult("String");
- AppSearchResult<String> result2 = AppSearchResult.newSuccessfulResult("String");
-
- assertThat(result1).isEqualTo(result2);
- assertThat(result1.hashCode()).isEqualTo(result2.hashCode());
-
- AppSearchResult<String> result3 =
- AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
- "errorMessage");
- AppSearchResult<String> result4 =
- AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
- "errorMessage");
-
- assertThat(result3).isEqualTo(result4);
- assertThat(result3.hashCode()).isEqualTo(result4.hashCode());
- }
-
- @Test
- public void testResultEquals_failure() {
- AppSearchResult<String> result1 = AppSearchResult.newSuccessfulResult("String");
- AppSearchResult<String> result2 = AppSearchResult.newSuccessfulResult("Wrong");
- AppSearchResult<String> resultNull = AppSearchResult.newSuccessfulResult(/*value=*/null);
-
- assertThat(result1).isNotEqualTo(result2);
- assertThat(result1.hashCode()).isNotEqualTo(result2.hashCode());
- assertThat(result1).isNotEqualTo(resultNull);
- assertThat(result1.hashCode()).isNotEqualTo(resultNull.hashCode());
-
- AppSearchResult<String> result3 =
- AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
- "errorMessage");
- AppSearchResult<String> result4 =
- AppSearchResult.newFailedResult(AppSearchResult.RESULT_IO_ERROR,
- "errorMessage");
-
- assertThat(result3).isNotEqualTo(result4);
- assertThat(result3.hashCode()).isNotEqualTo(result4.hashCode());
-
-
- AppSearchResult<String> result5 =
- AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
- "Wrong");
-
- assertThat(result3).isNotEqualTo(result5);
- assertThat(result3.hashCode()).isNotEqualTo(result5.hashCode());
-
- AppSearchResult<String> result6 =
- AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
- /*errorMessage=*/null);
-
- assertThat(result3).isNotEqualTo(result6);
- assertThat(result3.hashCode()).isNotEqualTo(result6.hashCode());
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSchemaCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSchemaCtsTest.java
deleted file mode 100644
index 7a646b0..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSchemaCtsTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app.cts;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
-import androidx.appsearch.exceptions.IllegalSchemaException;
-
-import org.junit.Test;
-
-public class AppSearchSchemaCtsTest {
- @Test
- public void testInvalidEnums() {
- PropertyConfig.Builder builder = new PropertyConfig.Builder("test");
- assertThrows(IllegalArgumentException.class, () -> builder.setDataType(99));
- assertThrows(IllegalArgumentException.class, () -> builder.setCardinality(99));
- }
-
- @Test
- public void testMissingFields() {
- PropertyConfig.Builder builder = new PropertyConfig.Builder("test");
- IllegalSchemaException e = assertThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: dataType");
-
- builder.setDataType(PropertyConfig.DATA_TYPE_DOCUMENT);
- e = assertThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: schemaType");
-
- builder.setSchemaType("TestType");
- e = assertThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: cardinality");
-
- builder.setCardinality(PropertyConfig.CARDINALITY_REPEATED);
- builder.build();
- }
-
- @Test
- public void testDuplicateProperties() {
- AppSearchSchema.Builder builder = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- );
- IllegalSchemaException e = assertThrows(IllegalSchemaException.class,
- () -> builder.addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()));
- assertThat(e).hasMessageThat().contains("Property defined more than once: subject");
- }
-
- @Test
- public void testEquals_identical() {
- AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- assertThat(schema1).isEqualTo(schema2);
- assertThat(schema1.hashCode()).isEqualTo(schema2.hashCode());
- }
-
- @Test
- public void testEquals_differentOrder() {
- AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .build()
- ).build();
- assertThat(schema1).isEqualTo(schema2);
- assertThat(schema1.hashCode()).isEqualTo(schema2.hashCode());
- }
-
- @Test
- public void testEquals_failure() {
- AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS) // Different
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- assertThat(schema1).isNotEqualTo(schema2);
- assertThat(schema1.hashCode()).isNotEqualTo(schema2.hashCode());
- }
-
- @Test
- public void testEquals_failure_differentOrder() {
- AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- // Order of 'body' and 'subject' has been switched
- AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- assertThat(schema1).isNotEqualTo(schema2);
- assertThat(schema1.hashCode()).isNotEqualTo(schema2.hashCode());
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSessionCtsTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSessionCtsTestBase.java
deleted file mode 100644
index b23a2a17..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSessionCtsTestBase.java
+++ /dev/null
@@ -1,1851 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app.cts;
-
-import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
-import static androidx.appsearch.app.util.AppSearchTestUtils.convertSearchResultsToDocuments;
-import static androidx.appsearch.app.util.AppSearchTestUtils.doGet;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.appsearch.app.AppSearchBatchResult;
-import androidx.appsearch.app.AppSearchEmail;
-import androidx.appsearch.app.AppSearchResult;
-import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
-import androidx.appsearch.app.AppSearchSession;
-import androidx.appsearch.app.GenericDocument;
-import androidx.appsearch.app.GetByUriRequest;
-import androidx.appsearch.app.PutDocumentsRequest;
-import androidx.appsearch.app.RemoveByUriRequest;
-import androidx.appsearch.app.SearchResult;
-import androidx.appsearch.app.SearchResults;
-import androidx.appsearch.app.SearchSpec;
-import androidx.appsearch.app.SetSchemaRequest;
-import androidx.appsearch.app.cts.customer.EmailDataClass;
-import androidx.appsearch.exceptions.AppSearchException;
-import androidx.appsearch.localstorage.LocalStorage;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-public abstract class AppSearchSessionCtsTestBase {
- private AppSearchSession mDb1;
- private static final String DB_NAME_1 = LocalStorage.DEFAULT_DATABASE_NAME;
- private AppSearchSession mDb2;
- private static final String DB_NAME_2 = "testDb2";
-
- protected abstract ListenableFuture<AppSearchSession> createSearchSession(
- @NonNull String dbName);
-
- protected abstract ListenableFuture<AppSearchSession> createSearchSession(
- @NonNull String dbName, @NonNull ExecutorService executor);
-
- @Before
- public void setUp() throws Exception {
- Context context = ApplicationProvider.getApplicationContext();
-
- mDb1 = createSearchSession(DB_NAME_1).get();
- mDb2 = createSearchSession(DB_NAME_2).get();
-
- // Cleanup whatever documents may still exist in these databases. This is needed in
- // addition to tearDown in case a test exited without completing properly.
- cleanup();
- }
-
- @After
- public void tearDown() throws Exception {
- // Cleanup whatever documents may still exist in these databases.
- cleanup();
- }
-
- private void cleanup() throws Exception {
- mDb1.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
- }
-
- @Test
- public void testSetSchema() throws Exception {
- AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(emailSchema).build()).get();
- }
-
-// @exportToFramework:startStrip()
-
- @Test
- public void testSetSchema_dataClass() throws Exception {
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addDataClass(EmailDataClass.class).build()).get();
- }
-// @exportToFramework:endStrip()
-
-// @exportToFramework:startStrip()
-
- @Test
- public void testGetSchema() throws Exception {
- AppSearchSchema emailSchema1 = new AppSearchSchema.Builder("Email1")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
- AppSearchSchema emailSchema2 = new AppSearchSchema.Builder("Email2")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS) // Different
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS) // Different
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
-
- SetSchemaRequest request1 = new SetSchemaRequest.Builder()
- .addSchema(emailSchema1).addDataClass(EmailDataClass.class).build();
- SetSchemaRequest request2 = new SetSchemaRequest.Builder()
- .addSchema(emailSchema2).addDataClass(EmailDataClass.class).build();
-
- mDb1.setSchema(request1).get();
- mDb2.setSchema(request2).get();
-
- Set<AppSearchSchema> actual1 = mDb1.getSchema().get();
- Set<AppSearchSchema> actual2 = mDb2.getSchema().get();
-
- assertThat(actual1).isEqualTo(request1.getSchemas());
- assertThat(actual2).isEqualTo(request2.getSchemas());
- }
-// @exportToFramework:endStrip()
-
- @Test
- public void testPutDocuments() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index a document
- AppSearchEmail email = new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
-
- AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email).build()));
- assertThat(result.getSuccesses()).containsExactly("uri1", null);
- assertThat(result.getFailures()).isEmpty();
- }
-
-// @exportToFramework:startStrip()
-
- @Test
- public void testPutDocuments_dataClass() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addDataClass(EmailDataClass.class).build()).get();
-
- // Index a document
- EmailDataClass email = new EmailDataClass();
- email.uri = "uri1";
- email.subject = "testPut example";
- email.body = "This is the body of the testPut email";
-
- AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addDataClass(email).build()));
- assertThat(result.getSuccesses()).containsExactly("uri1", null);
- assertThat(result.getFailures()).isEmpty();
- }
-// @exportToFramework:endStrip()
-
- @Test
- public void testUpdateSchema() throws Exception {
- // Schema registration
- AppSearchSchema oldEmailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build())
- .build();
- AppSearchSchema newEmailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build())
- .build();
- AppSearchSchema giftSchema = new AppSearchSchema.Builder("Gift")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_NONE)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_NONE)
- .build())
- .build();
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(oldEmailSchema).build()).get();
-
- // Try to index a gift. This should fail as it's not in the schema.
- GenericDocument gift =
- new GenericDocument.Builder<>("gift1", "Gift").setPropertyLong("price", 5).build();
- AppSearchBatchResult<String, Void> result =
- mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(gift).build()).get();
- assertThat(result.isSuccess()).isFalse();
- assertThat(result.getFailures().get("gift1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Update the schema to include the gift and update email with a new field
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(newEmailSchema, giftSchema).build()).get();
-
- // Try to index the document again, which should now work
- checkIsBatchResultSuccess(
- mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(gift).build()));
-
- // Indexing an email with a body should also work
- AppSearchEmail email = new AppSearchEmail.Builder("email1")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(
- mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email).build()));
- }
-
- @Test
- public void testRemoveSchema() throws Exception {
- // Schema registration
- AppSearchSchema emailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build())
- .build();
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(emailSchema).build()).get();
-
- // Index an email and check it present.
- AppSearchEmail email = new AppSearchEmail.Builder("email1")
- .setSubject("testPut example")
- .build();
- checkIsBatchResultSuccess(
- mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email).build()));
- List<GenericDocument> outDocuments =
- doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "email1");
- assertThat(outDocuments).hasSize(1);
- AppSearchEmail outEmail = new AppSearchEmail(outDocuments.get(0));
- assertThat(outEmail).isEqualTo(email);
-
- // Try to remove the email schema. This should fail as it's an incompatible change.
- Throwable failResult1 = assertThrows(
- ExecutionException.class,
- () -> mDb1.setSchema(new SetSchemaRequest.Builder().build()).get()).getCause();
- assertThat(failResult1).isInstanceOf(AppSearchException.class);
- assertThat(failResult1).hasMessageThat().contains("Schema is incompatible");
- assertThat(failResult1).hasMessageThat().contains(
- "Deleted types: [androidx.appsearch.test$" + DB_NAME_1 + "/builtin:Email]");
-
- // Try to remove the email schema again, which should now work as we set forceOverride to
- // be true.
- mDb1.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
-
- // Make sure the indexed email is gone.
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder()
- .setNamespace(GenericDocument.DEFAULT_NAMESPACE)
- .addUri("email1")
- .build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("email1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Try to index an email again. This should fail as the schema has been removed.
- AppSearchEmail email2 = new AppSearchEmail.Builder("email2")
- .setSubject("testPut example")
- .build();
- AppSearchBatchResult<String, Void> failResult2 = mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email2).build()).get();
- assertThat(failResult2.isSuccess()).isFalse();
- assertThat(failResult2.getFailures().get("email2").getErrorMessage())
- .isEqualTo("Schema type config 'androidx.appsearch.test$" + DB_NAME_1
- + "/builtin:Email' not found");
- }
-
- @Test
- public void testRemoveSchema_twoDatabases() throws Exception {
- // Schema registration in mDb1 and mDb2
- AppSearchSchema emailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build())
- .build();
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(emailSchema).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(emailSchema).build()).get();
-
- // Index an email and check it present in database1.
- AppSearchEmail email1 = new AppSearchEmail.Builder("email1")
- .setSubject("testPut example")
- .build();
- checkIsBatchResultSuccess(
- mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
- List<GenericDocument> outDocuments =
- doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "email1");
- assertThat(outDocuments).hasSize(1);
- AppSearchEmail outEmail = new AppSearchEmail(outDocuments.get(0));
- assertThat(outEmail).isEqualTo(email1);
-
- // Index an email and check it present in database2.
- AppSearchEmail email2 = new AppSearchEmail.Builder("email2")
- .setSubject("testPut example")
- .build();
- checkIsBatchResultSuccess(
- mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
- outDocuments = doGet(mDb2, GenericDocument.DEFAULT_NAMESPACE, "email2");
- assertThat(outDocuments).hasSize(1);
- outEmail = new AppSearchEmail(outDocuments.get(0));
- assertThat(outEmail).isEqualTo(email2);
-
- // Try to remove the email schema in database1. This should fail as it's an incompatible
- // change.
- Throwable failResult1 = assertThrows(
- ExecutionException.class,
- () -> mDb1.setSchema(new SetSchemaRequest.Builder().build()).get()).getCause();
- assertThat(failResult1).isInstanceOf(AppSearchException.class);
- assertThat(failResult1).hasMessageThat().contains("Schema is incompatible");
- assertThat(failResult1).hasMessageThat().contains(
- "Deleted types: [androidx.appsearch.test$" + DB_NAME_1 + "/builtin:Email]");
-
- // Try to remove the email schema again, which should now work as we set forceOverride to
- // be true.
- mDb1.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
-
- // Make sure the indexed email is gone in database 1.
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().setNamespace(GenericDocument.DEFAULT_NAMESPACE)
- .addUri("email1").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("email1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Try to index an email again. This should fail as the schema has been removed.
- AppSearchEmail email3 = new AppSearchEmail.Builder("email3")
- .setSubject("testPut example")
- .build();
- AppSearchBatchResult<String, Void> failResult2 = mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email3).build()).get();
- assertThat(failResult2.isSuccess()).isFalse();
- assertThat(failResult2.getFailures().get("email3").getErrorMessage())
- .isEqualTo("Schema type config 'androidx.appsearch.test$" + DB_NAME_1
- + "/builtin:Email' not found");
-
- // Make sure email in database 2 still present.
- outDocuments = doGet(mDb2, GenericDocument.DEFAULT_NAMESPACE, "email2");
- assertThat(outDocuments).hasSize(1);
- outEmail = new AppSearchEmail(outDocuments.get(0));
- assertThat(outEmail).isEqualTo(email2);
-
- // Make sure email could still be indexed in database 2.
- checkIsBatchResultSuccess(
- mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
- }
-
- @Test
- public void testGetDocuments() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index a document
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail).build()));
-
- // Get the document
- List<GenericDocument> outDocuments = doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1");
- assertThat(outDocuments).hasSize(1);
- AppSearchEmail outEmail = new AppSearchEmail(outDocuments.get(0));
- assertThat(outEmail).isEqualTo(inEmail);
-
- // Can't get the document in the other instance.
- AppSearchBatchResult<String, GenericDocument> failResult = mDb2.getByUri(
- new GetByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(failResult.isSuccess()).isFalse();
- assertThat(failResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- }
-
-// @exportToFramework:startStrip()
-
- @Test
- public void testGetDocuments_dataClass() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addDataClass(EmailDataClass.class).build()).get();
-
- // Index a document
- EmailDataClass inEmail = new EmailDataClass();
- inEmail.uri = "uri1";
- inEmail.subject = "testPut example";
- inEmail.body = "This is the body of the testPut inEmail";
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addDataClass(inEmail).build()));
-
- // Get the document
- List<GenericDocument> outDocuments = doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1");
- assertThat(outDocuments).hasSize(1);
- EmailDataClass outEmail = outDocuments.get(0).toDataClass(EmailDataClass.class);
- assertThat(inEmail.uri).isEqualTo(outEmail.uri);
- assertThat(inEmail.subject).isEqualTo(outEmail.subject);
- assertThat(inEmail.body).isEqualTo(outEmail.body);
- }
-// @exportToFramework:endStrip()
-
- @Test
- public void testQuery() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index a document
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail).build()));
-
- // Query for the document
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(1);
- assertThat(documents.get(0)).isEqualTo(inEmail);
-
- // Multi-term query
- searchResults = mDb1.query("body email", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(1);
- assertThat(documents.get(0)).isEqualTo(inEmail);
- }
-
- @Test
- public void testQuery_getNextPage() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
- Set<AppSearchEmail> emailSet = new HashSet<>();
- PutDocumentsRequest.Builder putDocumentsRequestBuilder = new PutDocumentsRequest.Builder();
- // Index 31 documents
- for (int i = 0; i < 31; i++) {
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri" + i)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- emailSet.add(inEmail);
- putDocumentsRequestBuilder.addGenericDocument(inEmail);
- }
- checkIsBatchResultSuccess(mDb1.putDocuments(putDocumentsRequestBuilder.build()));
-
- // Set number of results per page is 7.
- SearchResults searchResults = mDb1.query("body",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .setResultCountPerPage(7)
- .build());
- List<GenericDocument> documents = new ArrayList<>();
-
- int pageNumber = 0;
- List<SearchResult> results;
-
- // keep loading next page until it's empty.
- do {
- results = searchResults.getNextPage().get();
- ++pageNumber;
- for (SearchResult result : results) {
- documents.add(result.getDocument());
- }
- } while (results.size() > 0);
-
- // check all document presents
- assertThat(documents).containsExactlyElementsIn(emailSet);
- assertThat(pageNumber).isEqualTo(6); // 5 (upper(31/7)) + 1 (final empty page)
- }
-
- @Test
- public void testQuery_relevanceScoring() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .build()).get();
-
- // Index two documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("Mary had a little lamb")
- .setBody("A little lamb, little lamb")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("I'm a little teapot")
- .setBody("short and stout. Here is my handle, here is my spout.")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email1, email2).build()));
-
- // Query for "little". It should match both emails.
- SearchResults searchResults = mDb1.query("little", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
-
- // The email1 should be ranked higher because 'little' appears three times in email1 and
- // only once in email2.
- assertThat(documents).containsExactly(email1, email2).inOrder();
-
- // Query for "little OR stout". It should match both emails.
- searchResults = mDb1.query("little OR stout", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
-
- // The email2 should be ranked higher because 'little' appears once and "stout", which is a
- // rarer term, appears once. email1 only has the three 'little' appearances.
- assertThat(documents).containsExactly(email2, email1).inOrder();
- }
-
- @Test
- public void testQuery_typeFilter() throws Exception {
- // Schema registration
- AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
- .addProperty(new PropertyConfig.Builder("foo")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
- ).build();
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .addSchema(genericSchema)
- .build()).get();
-
- // Index a document
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument inDoc = new GenericDocument.Builder<>("uri2", "Generic")
- .setPropertyString("foo", "body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail, inDoc).build()));
-
- // Query for the documents
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(2);
- assertThat(documents).containsExactly(inEmail, inDoc);
-
- // Query only for Document
- searchResults = mDb1.query("body", new SearchSpec.Builder()
- .addSchemaType("Generic", "Generic") // duplicate type in filter won't matter.
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(1);
- assertThat(documents).containsExactly(inDoc);
- }
-
- @Test
- public void testQuery_namespaceFilter() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
-
- // Index two documents
- AppSearchEmail expectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("expectedNamespace")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail unexpectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("unexpectedNamespace")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(expectedEmail, unexpectedEmail).build()));
-
- // Query for all namespaces
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(2);
- assertThat(documents).containsExactly(expectedEmail, unexpectedEmail);
-
- // Query only for expectedNamespace
- searchResults = mDb1.query("body",
- new SearchSpec.Builder()
- .addNamespace("expectedNamespace")
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(1);
- assertThat(documents).containsExactly(expectedEmail);
- }
-
- @Test
- public void testQuery_getPackageName() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index a document
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail).build()));
-
- // Query for the document
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
-
- List<SearchResult> results;
- List<GenericDocument> documents = new ArrayList<>();
- // keep loading next page until it's empty.
- do {
- results = searchResults.getNextPage().get();
- for (SearchResult result : results) {
- assertThat(result.getDocument()).isEqualTo(inEmail);
- assertThat(result.getPackageName()).isEqualTo(
- ApplicationProvider.getApplicationContext().getPackageName());
- documents.add(result.getDocument());
- }
- } while (results.size() > 0);
- assertThat(documents).hasSize(1);
- }
-
- @Test
- public void testQuery_projection() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .addSchema(new AppSearchSchema.Builder("Note")
- .addProperty(new PropertyConfig.Builder("title")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .addProperty(new PropertyConfig.Builder("body")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .build()).build()).get();
-
- // Index two documents
- AppSearchEmail email =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument note =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email, note).build()));
-
- // Query with type property paths {"Email", ["body", "to"]}
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection(AppSearchEmail.SCHEMA_TYPE, "body", "to")
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
-
- // The email document should have been returned with only the "body" and "to"
- // properties. The note document should have been returned with all of its properties.
- AppSearchEmail expectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument expectedNote =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- assertThat(documents).containsExactly(expectedNote, expectedEmail);
- }
-
- @Test
- public void testQuery_projectionEmpty() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .addSchema(new AppSearchSchema.Builder("Note")
- .addProperty(new PropertyConfig.Builder("title")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .addProperty(new PropertyConfig.Builder("body")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .build()).build()).get();
-
- // Index two documents
- AppSearchEmail email =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument note =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email, note).build()));
-
- // Query with type property paths {"Email", []}
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection(AppSearchEmail.SCHEMA_TYPE, Collections.emptyList())
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
-
- // The email document should have been returned without any properties. The note document
- // should have been returned with all of its properties.
- AppSearchEmail expectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .build();
- GenericDocument expectedNote =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- assertThat(documents).containsExactly(expectedNote, expectedEmail);
- }
-
- @Test
- public void testQuery_projectionNonExistentType() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .addSchema(new AppSearchSchema.Builder("Note")
- .addProperty(new PropertyConfig.Builder("title")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .addProperty(new PropertyConfig.Builder("body")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .build()).build()).get();
-
- // Index two documents
- AppSearchEmail email =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument note =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email, note).build()));
-
- // Query with type property paths {"NonExistentType", []}, {"Email", ["body", "to"]}
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection("NonExistentType", Collections.emptyList())
- .addProjection(AppSearchEmail.SCHEMA_TYPE, "body", "to")
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
-
- // The email document should have been returned with only the "body" and "to" properties.
- // The note document should have been returned with all of its properties.
- AppSearchEmail expectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument expectedNote =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- assertThat(documents).containsExactly(expectedNote, expectedEmail);
- }
-
- @Test
- public void testQuery_wildcardProjection() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .addSchema(new AppSearchSchema.Builder("Note")
- .addProperty(new PropertyConfig.Builder("title")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .addProperty(new PropertyConfig.Builder("body")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .build()).build()).get();
-
- // Index two documents
- AppSearchEmail email =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument note =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email, note).build()));
-
- // Query with type property paths {"*", ["body", "to"]}
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection(SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD, "body", "to")
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
-
- // The email document should have been returned with only the "body" and "to"
- // properties. The note document should have been returned with only the "body" property.
- AppSearchEmail expectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument expectedNote =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("body", "Note body").build();
- assertThat(documents).containsExactly(expectedNote, expectedEmail);
- }
-
- @Test
- public void testQuery_wildcardProjectionEmpty() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .addSchema(new AppSearchSchema.Builder("Note")
- .addProperty(new PropertyConfig.Builder("title")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .addProperty(new PropertyConfig.Builder("body")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .build()).build()).get();
-
- // Index two documents
- AppSearchEmail email =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument note =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email, note).build()));
-
- // Query with type property paths {"*", []}
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection(SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD, Collections.emptyList())
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
-
- // The email and note documents should have been returned without any properties.
- AppSearchEmail expectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .build();
- GenericDocument expectedNote =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000).build();
- assertThat(documents).containsExactly(expectedNote, expectedEmail);
- }
-
- @Test
- public void testQuery_wildcardProjectionNonExistentType() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .addSchema(new AppSearchSchema.Builder("Note")
- .addProperty(new PropertyConfig.Builder("title")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .addProperty(new PropertyConfig.Builder("body")
- .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .setTokenizerType(
- PropertyConfig.TOKENIZER_TYPE_PLAIN).build())
- .build()).build()).get();
-
- // Index two documents
- AppSearchEmail email =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument note =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("title", "Note title")
- .setPropertyString("body", "Note body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email, note).build()));
-
- // Query with type property paths {"NonExistentType", []}, {"*", ["body", "to"]}
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection("NonExistentType", Collections.emptyList())
- .addProjection(SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD, "body", "to")
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
-
- // The email document should have been returned with only the "body" and "to"
- // properties. The note document should have been returned with only the "body" property.
- AppSearchEmail expectedEmail =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setBody("This is the body of the testPut email")
- .build();
- GenericDocument expectedNote =
- new GenericDocument.Builder<>("uri2", "Note")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setPropertyString("body", "Note body").build();
- assertThat(documents).containsExactly(expectedNote, expectedEmail);
- }
-
- @Test
- public void testQuery_twoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index a document to instance 1.
- AppSearchEmail inEmail1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail1).build()));
-
- // Index a document to instance 2.
- AppSearchEmail inEmail2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail2).build()));
-
- // Query for instance 1.
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(1);
- assertThat(documents).containsExactly(inEmail1);
-
- // Query for instance 2.
- searchResults = mDb2.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(1);
- assertThat(documents).containsExactly(inEmail2);
- }
-
- @Test
- public void testSnippet() throws Exception {
- // Schema registration
- // TODO(tytytyww) add property for long and double.
- AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
- ).build();
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(genericSchema).build()).get();
-
- // Index a document
- GenericDocument document =
- new GenericDocument.Builder<>("uri", "Generic")
- .setNamespace("document")
- .setPropertyString("subject", "A commonly used fake word is foo. "
- + "Another nonsense word that’s used a lot is bar")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(document).build()));
-
- // Query for the document
- SearchResults searchResults = mDb1.query("foo",
- new SearchSpec.Builder()
- .addSchemaType("Generic")
- .setSnippetCount(1)
- .setSnippetCountPerProperty(1)
- .setMaxSnippetSize(10)
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .build());
- List<SearchResult> results = searchResults.getNextPage().get();
- assertThat(results).hasSize(1);
-
- List<SearchResult.MatchInfo> matchInfos = results.get(0).getMatches();
- assertThat(matchInfos).isNotNull();
- assertThat(matchInfos).hasSize(1);
- SearchResult.MatchInfo matchInfo = matchInfos.get(0);
- assertThat(matchInfo.getFullText()).isEqualTo("A commonly used fake word is foo. "
- + "Another nonsense word that’s used a lot is bar");
- assertThat(matchInfo.getExactMatchPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/29, /*upper=*/32));
- assertThat(matchInfo.getExactMatch()).isEqualTo("foo");
- assertThat(matchInfo.getSnippetPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/26, /*upper=*/33));
- assertThat(matchInfo.getSnippet()).isEqualTo("is foo.");
- }
-
- @Test
- public void testRemove() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 2")
- .setBody("This is the body of the testPut second email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1, email2).build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri2")).hasSize(1);
-
- // Delete the document
- checkIsBatchResultSuccess(mDb1.removeByUri(
- new RemoveByUriRequest.Builder().addUri("uri1").build()));
-
- // Make sure it's really gone
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1", "uri2").build())
- .get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- assertThat(getResult.getSuccesses().get("uri2")).isEqualTo(email2);
-
- // Test if we delete a nonexistent URI.
- AppSearchBatchResult<String, Void> deleteResult = mDb1.removeByUri(
- new RemoveByUriRequest.Builder().addUri("uri1").build()).get();
-
- assertThat(deleteResult.getFailures().get("uri1").getResultCode()).isEqualTo(
- AppSearchResult.RESULT_NOT_FOUND);
- }
-
- @Test
- public void testRemoveByQuery() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("foo")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("bar")
- .setBody("This is the body of the testPut second email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1, email2).build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri2")).hasSize(1);
-
- // Delete the email 1 by query "foo"
- mDb1.removeByQuery("foo",
- new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_PREFIX).build()).get();
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1", "uri2").build())
- .get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- assertThat(getResult.getSuccesses().get("uri2")).isEqualTo(email2);
-
- // Delete the email 2 by query "bar"
- mDb1.removeByQuery("bar",
- new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_PREFIX).build()).get();
- getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri2").build())
- .get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri2").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- }
-
- @Test
- public void testRemove_twoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
-
- // Can't delete in the other instance.
- AppSearchBatchResult<String, Void> deleteResult = mDb2.removeByUri(
- new RemoveByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(deleteResult.getFailures().get("uri1").getResultCode()).isEqualTo(
- AppSearchResult.RESULT_NOT_FOUND);
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
-
- // Delete the document
- checkIsBatchResultSuccess(mDb1.removeByUri(
- new RemoveByUriRequest.Builder().addUri("uri1").build()));
-
- // Make sure it's really gone
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Test if we delete a nonexistent URI.
- deleteResult = mDb1.removeByUri(
- new RemoveByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(deleteResult.getFailures().get("uri1").getResultCode()).isEqualTo(
- AppSearchResult.RESULT_NOT_FOUND);
- }
-
- @Test
- public void testRemoveByTypes() throws Exception {
- // Schema registration
- AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic").build();
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).addSchema(
- genericSchema).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 2")
- .setBody("This is the body of the testPut second email")
- .build();
- GenericDocument document1 =
- new GenericDocument.Builder<>("uri3", "Generic").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1, email2, document1)
- .build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1", "uri2",
- "uri3")).hasSize(3);
-
- // Delete the email type
- mDb1.removeByQuery("",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addSchemaType(AppSearchEmail.SCHEMA_TYPE)
- .build())
- .get();
-
- // Make sure it's really gone
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1", "uri2", "uri3").build())
- .get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- assertThat(getResult.getFailures().get("uri2").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- assertThat(getResult.getSuccesses().get("uri3")).isEqualTo(document1);
- }
-
- @Test
- public void testRemoveByTypes_twoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 2")
- .setBody("This is the body of the testPut second email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
- assertThat(doGet(mDb2, GenericDocument.DEFAULT_NAMESPACE, "uri2")).hasSize(1);
-
- // Delete the email type in instance 1
- mDb1.removeByQuery("",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addSchemaType(AppSearchEmail.SCHEMA_TYPE)
- .build())
- .get();
-
- // Make sure it's really gone in instance 1
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Make sure it's still in instance 2.
- getResult = mDb2.getByUri(
- new GetByUriRequest.Builder().addUri("uri2").build()).get();
- assertThat(getResult.isSuccess()).isTrue();
- assertThat(getResult.getSuccesses().get("uri2")).isEqualTo(email2);
- }
-
- @Test
- public void testRemoveByNamespace() throws Exception {
- // Schema registration
- AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
- .addProperty(new PropertyConfig.Builder("foo")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
- ).build();
- mDb1.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).addSchema(
- genericSchema).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("email")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("email")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 2")
- .setBody("This is the body of the testPut second email")
- .build();
- GenericDocument document1 =
- new GenericDocument.Builder<>("uri3", "Generic")
- .setNamespace("document")
- .setPropertyString("foo", "bar").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1, email2, document1)
- .build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, /*namespace=*/"email", "uri1", "uri2")).hasSize(2);
- assertThat(doGet(mDb1, /*namespace=*/"document", "uri3")).hasSize(1);
-
- // Delete the email namespace
- mDb1.removeByQuery("",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addNamespace("email")
- .build())
- .get();
-
- // Make sure it's really gone
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().setNamespace("email")
- .addUri("uri1", "uri2").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- assertThat(getResult.getFailures().get("uri2").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().setNamespace("document")
- .addUri("uri3").build()).get();
- assertThat(getResult.isSuccess()).isTrue();
- assertThat(getResult.getSuccesses().get("uri3")).isEqualTo(document1);
- }
-
- @Test
- public void testRemoveByNamespaces_twoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("email")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("email")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 2")
- .setBody("This is the body of the testPut second email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, /*namespace=*/"email", "uri1")).hasSize(1);
- assertThat(doGet(mDb2, /*namespace=*/"email", "uri2")).hasSize(1);
-
- // Delete the email namespace in instance 1
- mDb1.removeByQuery("",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addNamespace("email")
- .build())
- .get();
-
- // Make sure it's really gone in instance 1
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().setNamespace("email")
- .addUri("uri1").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Make sure it's still in instance 2.
- getResult = mDb2.getByUri(
- new GetByUriRequest.Builder().setNamespace("email")
- .addUri("uri2").build()).get();
- assertThat(getResult.isSuccess()).isTrue();
- assertThat(getResult.getSuccesses().get("uri2")).isEqualTo(email2);
- }
-
- @Test
- public void testRemoveAll_twoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 2")
- .setBody("This is the body of the testPut second email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
- assertThat(doGet(mDb2, GenericDocument.DEFAULT_NAMESPACE, "uri2")).hasSize(1);
-
- // Delete the all document in instance 1
- mDb1.removeByQuery("",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .build())
- .get();
-
- // Make sure it's really gone in instance 1
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Make sure it's still in instance 2.
- getResult = mDb2.getByUri(
- new GetByUriRequest.Builder().addUri("uri2").build()).get();
- assertThat(getResult.isSuccess()).isTrue();
- assertThat(getResult.getSuccesses().get("uri2")).isEqualTo(email2);
- }
-
- @Test
- public void testRemoveAll_termMatchType() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 2")
- .setBody("This is the body of the testPut second email")
- .build();
- AppSearchEmail email3 =
- new AppSearchEmail.Builder("uri3")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 3")
- .setBody("This is the body of the testPut second email")
- .build();
- AppSearchEmail email4 =
- new AppSearchEmail.Builder("uri4")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example 4")
- .setBody("This is the body of the testPut second email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1, email2).build()));
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email3, email4).build()));
-
- // Check the presence of the documents
- SearchResults searchResults = mDb1.query("", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(2);
- searchResults = mDb2.query("", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).hasSize(2);
-
- // Delete the all document in instance 1 with TERM_MATCH_PREFIX
- mDb1.removeByQuery("",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .build())
- .get();
- searchResults = mDb1.query("", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).isEmpty();
-
- // Delete the all document in instance 2 with TERM_MATCH_EXACT_ONLY
- mDb2.removeByQuery("",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build())
- .get();
- searchResults = mDb2.query("", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).isEmpty();
- }
-
- @Test
- public void testRemoveAllAfterEmpty() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Index documents
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
-
- // Check the presence of the documents
- assertThat(doGet(mDb1, "namespace", "uri1")).hasSize(1);
-
- // Remove the document
- checkIsBatchResultSuccess(
- mDb1.removeByUri(new RemoveByUriRequest.Builder()
- .setNamespace("namespace").addUri("uri1").build()));
-
- // Make sure it's really gone
- AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
-
- // Delete the all documents
- mDb1.removeByQuery(
- "", new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_PREFIX).build())
- .get();
-
- // Make sure it's still gone
- getResult = mDb1.getByUri(
- new GetByUriRequest.Builder().addUri("uri1").build()).get();
- assertThat(getResult.isSuccess()).isFalse();
- assertThat(getResult.getFailures().get("uri1").getResultCode())
- .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
- }
-
- @Test
- public void testCloseAndReopen() throws Exception {
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
-
- // Index a document
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail).build()));
-
- // close and re-open the appSearchSession
- mDb1.close();
- mDb1 = createSearchSession(DB_NAME_1).get();
-
- // Query for the document
- SearchResults searchResults = mDb1.query("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
- List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
- assertThat(documents).containsExactly(inEmail);
- }
-
- @Test
- public void testCallAfterClose() throws Exception {
-
- // Create a same-thread database by inject an executor which could help us maintain the
- // execution order of those async tasks.
- Context context = ApplicationProvider.getApplicationContext();
- AppSearchSession sameThreadDb = createSearchSession(
- "sameThreadDb", MoreExecutors.newDirectExecutorService()).get();
-
- try {
- // Schema registration -- just mutate something
- sameThreadDb.setSchema(
- new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // Close the database. No further call will be allowed.
- sameThreadDb.close();
-
- // Try to query the closed database
- // We are using the same-thread db here to make sure it has been closed.
- IllegalStateException e = assertThrows(IllegalStateException.class, () ->
- sameThreadDb.query("query", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build()));
- assertThat(e).hasMessageThat().contains("AppSearchSession has already been closed");
- } finally {
- // To clean the data that has been added in the test, need to re-open the session and
- // set an empty schema.
- AppSearchSession reopen = createSearchSession(
- "sameThreadDb", MoreExecutors.newDirectExecutorService()).get();
- reopen.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
- }
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSessionLocalCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSessionLocalCtsTest.java
deleted file mode 100644
index 541cd5a..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/AppSearchSessionLocalCtsTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// @exportToFramework:skipFile()
-package androidx.appsearch.app.cts;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.appsearch.app.AppSearchSession;
-import androidx.appsearch.localstorage.LocalStorage;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.concurrent.ExecutorService;
-
-public class AppSearchSessionLocalCtsTest extends AppSearchSessionCtsTestBase {
- @Override
- protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
- Context context = ApplicationProvider.getApplicationContext();
- return LocalStorage.createSearchSession(
- new LocalStorage.SearchContext.Builder(context).setDatabaseName(dbName).build());
- }
-
- @Override
- protected ListenableFuture<AppSearchSession> createSearchSession(
- @NonNull String dbName, @NonNull ExecutorService executor) {
- Context context = ApplicationProvider.getApplicationContext();
- return LocalStorage.createSearchSession(
- new LocalStorage.SearchContext.Builder(context).setDatabaseName(dbName).build(),
- executor);
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GenericDocumentCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GenericDocumentCtsTest.java
deleted file mode 100644
index 4fa033a..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GenericDocumentCtsTest.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-import androidx.appsearch.app.GenericDocument;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class GenericDocumentCtsTest {
- private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
- private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6, (byte) 7};
- private static final GenericDocument sDocumentProperties1 = new GenericDocument
- .Builder<>("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
- .setCreationTimestampMillis(12345L)
- .build();
- private static final GenericDocument sDocumentProperties2 = new GenericDocument
- .Builder<>("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
- .setCreationTimestampMillis(6789L)
- .build();
-
- @Test
- public void testDocumentEquals_identical() {
- GenericDocument document1 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setTtlMillis(1L)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
- .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
- .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
- GenericDocument document2 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setTtlMillis(1L)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
- .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
- .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
- assertThat(document1).isEqualTo(document2);
- assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentEquals_differentOrder() {
- GenericDocument document1 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
- .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
- .build();
-
- // Create second document with same parameter but different order.
- GenericDocument document2 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
- .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
- .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .build();
- assertThat(document1).isEqualTo(document2);
- assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentEquals_failure() {
- GenericDocument document1 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .build();
-
- // Create second document with same order but different value.
- GenericDocument document2 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyLong("longKey1", 1L, 2L, 4L) // Different
- .build();
- assertThat(document1).isNotEqualTo(document2);
- assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentEquals_repeatedFieldOrder_failure() {
- GenericDocument document1 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .build();
-
- // Create second document with same order but different value.
- GenericDocument document2 = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyBoolean("booleanKey1", true, true, false) // Different
- .build();
- assertThat(document1).isNotEqualTo(document2);
- assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentGetSingleValue() {
- GenericDocument document = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setScore(1)
- .setTtlMillis(1L)
- .setPropertyLong("longKey1", 1L)
- .setPropertyDouble("doubleKey1", 1.0)
- .setPropertyBoolean("booleanKey1", true)
- .setPropertyString("stringKey1", "test-value1")
- .setPropertyBytes("byteKey1", sByteArray1)
- .setPropertyDocument("documentKey1", sDocumentProperties1)
- .build();
- assertThat(document.getUri()).isEqualTo("uri1");
- assertThat(document.getTtlMillis()).isEqualTo(1L);
- assertThat(document.getSchemaType()).isEqualTo("schemaType1");
- assertThat(document.getCreationTimestampMillis()).isEqualTo(5);
- assertThat(document.getScore()).isEqualTo(1);
- assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
- assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(1.0);
- assertThat(document.getPropertyBoolean("booleanKey1")).isTrue();
- assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
- assertThat(document.getPropertyBytes("byteKey1"))
- .asList().containsExactly((byte) 1, (byte) 2, (byte) 3);
- assertThat(document.getPropertyDocument("documentKey1")).isEqualTo(sDocumentProperties1);
- }
-
- @Test
- public void testDocumentGetArrayValues() {
- GenericDocument document = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
- .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
- .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
-
- assertThat(document.getUri()).isEqualTo("uri1");
- assertThat(document.getSchemaType()).isEqualTo("schemaType1");
- assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L, 2L, 3L);
- assertThat(document.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
- .containsExactly(1.0, 2.0, 3.0);
- assertThat(document.getPropertyBooleanArray("booleanKey1")).asList()
- .containsExactly(true, false, true);
- assertThat(document.getPropertyStringArray("stringKey1")).asList()
- .containsExactly("test-value1", "test-value2", "test-value3");
- assertThat(document.getPropertyBytesArray("byteKey1")).asList()
- .containsExactly(sByteArray1, sByteArray2);
- assertThat(document.getPropertyDocumentArray("documentKey1")).asList()
- .containsExactly(sDocumentProperties1, sDocumentProperties2);
- }
-
- @Ignore
- @Test
- public void testDocument_toString() {
- GenericDocument document = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyString("stringKey1", "String1", "String2", "String3")
- .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
- .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
- String exceptedString = "{ key: 'creationTimestampMillis' value: 5 } "
- + "{ key: 'namespace' value: } "
- + "{ key: 'properties' value: "
- + "{ key: 'booleanKey1' value: [ 'true' 'false' 'true' ] } "
- + "{ key: 'byteKey1' value: "
- + "{ key: 'byteArray' value: [ '1' '2' '3' ] } "
- + "{ key: 'byteArray' value: [ '4' '5' '6' '7' ] } } "
- + "{ key: 'documentKey1' value: [ '"
- + "{ key: 'creationTimestampMillis' value: 12345 } "
- + "{ key: 'namespace' value: } "
- + "{ key: 'properties' value: } "
- + "{ key: 'schemaType' value: sDocumentPropertiesSchemaType1 } "
- + "{ key: 'score' value: 0 } "
- + "{ key: 'ttlMillis' value: 0 } "
- + "{ key: 'uri' value: sDocumentProperties1 } ' '"
- + "{ key: 'creationTimestampMillis' value: 6789 } "
- + "{ key: 'namespace' value: } "
- + "{ key: 'properties' value: } "
- + "{ key: 'schemaType' value: sDocumentPropertiesSchemaType2 } "
- + "{ key: 'score' value: 0 } "
- + "{ key: 'ttlMillis' value: 0 } "
- + "{ key: 'uri' value: sDocumentProperties2 } ' ] } "
- + "{ key: 'doubleKey1' value: [ '1.0' '2.0' '3.0' ] } "
- + "{ key: 'longKey1' value: [ '1' '2' '3' ] } "
- + "{ key: 'stringKey1' value: [ 'String1' 'String2' 'String3' ] } } "
- + "{ key: 'schemaType' value: schemaType1 } "
- + "{ key: 'score' value: 0 } "
- + "{ key: 'ttlMillis' value: 0 } "
- + "{ key: 'uri' value: uri1 } ";
- assertThat(document.toString()).isEqualTo(exceptedString);
- }
-
- @Test
- public void testDocumentGetValues_differentTypes() {
- GenericDocument document = new GenericDocument.Builder<>("uri1", "schemaType1")
- .setScore(1)
- .setPropertyLong("longKey1", 1L)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
- .build();
-
- // Get a value for a key that doesn't exist
- assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(0.0);
- assertThat(document.getPropertyDoubleArray("doubleKey1")).isNull();
-
- // Get a value with a single element as an array and as a single value
- assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
- assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L);
-
- // Get a value with multiple elements as an array and as a single value
- assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
- assertThat(document.getPropertyStringArray("stringKey1")).asList()
- .containsExactly("test-value1", "test-value2", "test-value3");
-
- // Get a value of the wrong type
- assertThat(document.getPropertyDouble("longKey1")).isEqualTo(0.0);
- assertThat(document.getPropertyDoubleArray("longKey1")).isNull();
- }
-
- @Test
- public void testDocumentInvalid() {
- GenericDocument.Builder<?> builder = new GenericDocument.Builder<>("uri1", "schemaType1");
- assertThrows(
- IllegalArgumentException.class,
- () -> builder.setPropertyBoolean("test", new boolean[]{}));
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GlobalSearchSessionCtsTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GlobalSearchSessionCtsTestBase.java
deleted file mode 100644
index 0120153..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GlobalSearchSessionCtsTestBase.java
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app.cts;
-
-import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
-import static androidx.appsearch.app.util.AppSearchTestUtils.convertSearchResultsToDocuments;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.appsearch.app.AppSearchEmail;
-import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
-import androidx.appsearch.app.AppSearchSession;
-import androidx.appsearch.app.GenericDocument;
-import androidx.appsearch.app.GlobalSearchSession;
-import androidx.appsearch.app.PutDocumentsRequest;
-import androidx.appsearch.app.SearchResult;
-import androidx.appsearch.app.SearchResults;
-import androidx.appsearch.app.SearchSpec;
-import androidx.appsearch.app.SetSchemaRequest;
-import androidx.appsearch.localstorage.LocalStorage;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public abstract class GlobalSearchSessionCtsTestBase {
- private AppSearchSession mDb1;
- private static final String DB_NAME_1 = LocalStorage.DEFAULT_DATABASE_NAME;
- private AppSearchSession mDb2;
- private static final String DB_NAME_2 = "testDb2";
-
- private GlobalSearchSession mGlobalAppSearchManager;
-
- protected abstract ListenableFuture<AppSearchSession> createSearchSession(
- @NonNull String dbName);
- protected abstract ListenableFuture<GlobalSearchSession> createGlobalSearchSession();
-
- @Before
- public void setUp() throws Exception {
- Context context = ApplicationProvider.getApplicationContext();
-
- mDb1 = createSearchSession(DB_NAME_1).get();
- mDb2 = createSearchSession(DB_NAME_2).get();
-
- // Cleanup whatever documents may still exist in these databases. This is needed in
- // addition to tearDown in case a test exited without completing properly.
- cleanup();
-
- mGlobalAppSearchManager = createGlobalSearchSession().get();
- }
-
- @After
- public void tearDown() throws Exception {
- // Cleanup whatever documents may still exist in these databases.
- cleanup();
- }
-
- private void cleanup() throws Exception {
- mDb1.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
- mDb2.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
- }
-
- private List<GenericDocument> snapshotResults(String queryExpression, SearchSpec spec)
- throws Exception {
- SearchResults searchResults = mGlobalAppSearchManager.query(queryExpression, spec);
- return convertSearchResultsToDocuments(searchResults);
- }
-
- /**
- * Asserts that the union of {@code addedDocuments} and {@code beforeDocuments} is exactly
- * equivalent to {@code afterDocuments}. Order doesn't matter.
- *
- * @param beforeDocuments Documents that existed first.
- * @param afterDocuments The total collection of documents that should exist now.
- * @param addedDocuments The collection of documents that were expected to be added.
- */
- private void assertAddedBetweenSnapshots(List<? extends GenericDocument> beforeDocuments,
- List<? extends GenericDocument> afterDocuments,
- List<? extends GenericDocument> addedDocuments) {
- List<GenericDocument> expectedDocuments = new ArrayList<>(beforeDocuments);
- expectedDocuments.addAll(addedDocuments);
- assertThat(afterDocuments).containsExactlyElementsIn(expectedDocuments);
- }
-
- @Test
- public void testGlobalQuery_oneInstance() throws Exception {
- // Snapshot what documents may already exist on the device.
- SearchSpec exactSearchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build();
- List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
- List<GenericDocument> beforeBodyEmailDocuments = snapshotResults("body email",
- exactSearchSpec);
-
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
-
- // Index a document
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail).build()));
-
- // Query for the document
- List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
- assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
- Collections.singletonList(inEmail));
-
- // Multi-term query
- List<GenericDocument> afterBodyEmailDocuments = snapshotResults("body email",
- exactSearchSpec);
- assertAddedBetweenSnapshots(beforeBodyEmailDocuments, afterBodyEmailDocuments,
- Collections.singletonList(inEmail));
- }
-
- @Test
- public void testGlobalQuery_twoInstances() throws Exception {
- // Snapshot what documents may already exist on the device.
- SearchSpec exactSearchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build();
- List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
-
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
- mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
-
- // Index a document to instance 1.
- AppSearchEmail inEmail1 =
- new AppSearchEmail.Builder("uri1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail1).build()));
-
- // Index a document to instance 2.
- AppSearchEmail inEmail2 =
- new AppSearchEmail.Builder("uri2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(inEmail2).build()));
-
- // Query across all instances
- List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
- assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
- ImmutableList.of(inEmail1, inEmail2));
- }
-
- @Test
- public void testGlobalQuery_getNextPage() throws Exception {
- // Snapshot what documents may already exist on the device.
- SearchSpec exactSearchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build();
- List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
-
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
- List<AppSearchEmail> emailList = new ArrayList<>();
- PutDocumentsRequest.Builder putDocumentsRequestBuilder = new PutDocumentsRequest.Builder();
-
- // Index 31 documents
- for (int i = 0; i < 31; i++) {
- AppSearchEmail inEmail =
- new AppSearchEmail.Builder("uri" + i)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- emailList.add(inEmail);
- putDocumentsRequestBuilder.addGenericDocument(inEmail);
- }
- checkIsBatchResultSuccess(mDb1.putDocuments(putDocumentsRequestBuilder.build()));
-
- // Set number of results per page is 7.
- int pageSize = 7;
- SearchResults searchResults = mGlobalAppSearchManager.query("body",
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .setResultCountPerPage(pageSize)
- .build());
- List<GenericDocument> documents = new ArrayList<>();
-
- int pageNumber = 0;
- List<SearchResult> results;
-
- // keep loading next page until it's empty.
- do {
- results = searchResults.getNextPage().get();
- ++pageNumber;
- for (SearchResult result : results) {
- documents.add(result.getDocument());
- }
- } while (results.size() > 0);
-
- // check all document presents
- assertAddedBetweenSnapshots(beforeBodyDocuments, documents, emailList);
-
- int totalDocuments = beforeBodyDocuments.size() + documents.size();
-
- // +1 for final empty page
- int expectedPages = (int) Math.ceil(totalDocuments * 1.0 / pageSize) + 1;
- assertThat(pageNumber).isEqualTo(expectedPages);
- }
-
- @Test
- public void testGlobalQuery_acrossTypes() throws Exception {
- // Snapshot what documents may already exist on the device.
- SearchSpec exactSearchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build();
- List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
-
- SearchSpec exactEmailSearchSpec =
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addSchemaType(AppSearchEmail.SCHEMA_TYPE)
- .build();
- List<GenericDocument> beforeBodyEmailDocuments = snapshotResults("body",
- exactEmailSearchSpec);
-
- // Schema registration
- AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
- .addProperty(new PropertyConfig.Builder("foo")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
- ).build();
-
- // db1 has both "Generic" and "builtin:Email"
- mDb1.setSchema(new SetSchemaRequest.Builder()
- .addSchema(genericSchema).addSchema(AppSearchEmail.SCHEMA).build()).get();
-
- // db2 only has "builtin:Email"
- mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
-
- // Index a generic document into db1
- GenericDocument genericDocument = new GenericDocument.Builder<>("uri2", "Generic")
- .setPropertyString("foo", "body").build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(genericDocument).build()));
-
- AppSearchEmail email =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
-
- // Put the email in both databases
- checkIsBatchResultSuccess((mDb1.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email).build())));
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(email).build()));
-
- // Query for all documents across types
- List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
- assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
- ImmutableList.of(genericDocument, email, email));
-
- // Query only for email documents
- List<GenericDocument> afterBodyEmailDocuments = snapshotResults("body",
- exactEmailSearchSpec);
- assertAddedBetweenSnapshots(beforeBodyEmailDocuments, afterBodyEmailDocuments,
- ImmutableList.of(email, email));
- }
-
- @Test
- public void testGlobalQuery_namespaceFilter() throws Exception {
- // Snapshot what documents may already exist on the device.
- SearchSpec exactSearchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build();
- List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
-
- SearchSpec exactNamespace1SearchSpec =
- new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addNamespace("namespace1")
- .build();
- List<GenericDocument> beforeBodyNamespace1Documents = snapshotResults("body",
- exactNamespace1SearchSpec);
-
- // Schema registration
- mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
- mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
- .get();
-
- // Index two documents
- AppSearchEmail document1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace1")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(document1).build()));
-
- AppSearchEmail document2 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace2")
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder().addGenericDocument(document2).build()));
-
- // Query for all namespaces
- List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
- assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
- ImmutableList.of(document1, document2));
-
- // Query only for "namespace1"
- List<GenericDocument> afterBodyNamespace1Documents = snapshotResults("body",
- exactNamespace1SearchSpec);
- assertAddedBetweenSnapshots(beforeBodyNamespace1Documents, afterBodyNamespace1Documents,
- ImmutableList.of(document1));
- }
-
- // TODO(b/175039682) Add test cases for wildcard projection once go/oag/1534646 is submitted.
- @Test
- public void testGlobalQuery_projectionTwoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .build()).get();
- mDb2.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .build()).get();
-
- // Index one document in each database.
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email1).build()));
-
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email2).build()));
-
- // Query with type property paths {"Email", ["subject", "to"]}
- List<GenericDocument> documents =
- snapshotResults("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection(AppSearchEmail.SCHEMA_TYPE,
- "subject", "to")
- .build());
-
- // The two email documents should have been returned with only the "subject" and "to"
- // properties.
- AppSearchEmail expected1 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .build();
- AppSearchEmail expected2 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .build();
- assertThat(documents).containsExactly(expected1, expected2);
- }
-
- @Test
- public void testGlobalQuery_projectionEmptyTwoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .build()).get();
- mDb2.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .build()).get();
-
- // Index one document in each database.
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email1).build()));
-
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email2).build()));
-
- // Query with type property paths {"Email", []}
- List<GenericDocument> documents =
- snapshotResults("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection(AppSearchEmail.SCHEMA_TYPE,
- Collections.emptyList())
- .build());
-
- // The two email documents should have been returned without any properties.
- AppSearchEmail expected1 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .build();
- AppSearchEmail expected2 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .build();
- assertThat(documents).containsExactly(expected1, expected2);
- }
-
- @Test
- public void testGlobalQuery_projectionNonExistentTypeTwoInstances() throws Exception {
- // Schema registration
- mDb1.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .build()).get();
- mDb2.setSchema(
- new SetSchemaRequest.Builder()
- .addSchema(AppSearchEmail.SCHEMA)
- .build()).get();
-
- // Index one document in each database.
- AppSearchEmail email1 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb1.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email1).build()));
-
- AppSearchEmail email2 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setFrom("from@example.com")
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .setBody("This is the body of the testPut email")
- .build();
- checkIsBatchResultSuccess(mDb2.putDocuments(
- new PutDocumentsRequest.Builder()
- .addGenericDocument(email2).build()));
-
- // Query with type property paths {"NonExistentType", []}, {"Email", ["subject", "to"]}
- List<GenericDocument> documents =
- snapshotResults("body", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .addProjection("NonExistentType", Collections.emptyList())
- .addProjection(AppSearchEmail.SCHEMA_TYPE, "subject", "to")
- .build());
-
- // The two email documents should have been returned with only the "subject" and "to"
- // properties.
- AppSearchEmail expected1 =
- new AppSearchEmail.Builder("uri2")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .build();
- AppSearchEmail expected2 =
- new AppSearchEmail.Builder("uri1")
- .setNamespace("namespace")
- .setCreationTimestampMillis(1000)
- .setTo("to1@example.com", "to2@example.com")
- .setSubject("testPut example")
- .build();
- assertThat(documents).containsExactly(expected1, expected2);
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GlobalSearchSessionLocalCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GlobalSearchSessionLocalCtsTest.java
deleted file mode 100644
index 4586ca1..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/GlobalSearchSessionLocalCtsTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// @exportToFramework:skipFile()
-package androidx.appsearch.app.cts;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.appsearch.app.AppSearchSession;
-import androidx.appsearch.app.GlobalSearchSession;
-import androidx.appsearch.localstorage.LocalStorage;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-// TODO(b/175801531): Support this test for the platform backend once the global search API is
-// public.
-public class GlobalSearchSessionLocalCtsTest extends GlobalSearchSessionCtsTestBase {
- @Override
- protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
- Context context = ApplicationProvider.getApplicationContext();
- return LocalStorage.createSearchSession(
- new LocalStorage.SearchContext.Builder(context).setDatabaseName(dbName).build());
- }
-
- @Override
- protected ListenableFuture<GlobalSearchSession> createGlobalSearchSession() {
- Context context = ApplicationProvider.getApplicationContext();
- return LocalStorage.createGlobalSearchSession(
- new LocalStorage.GlobalSearchContext.Builder(context).build());
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/SearchSpecCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/SearchSpecCtsTest.java
deleted file mode 100644
index ad3c9a5..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/SearchSpecCtsTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-import androidx.appsearch.app.SearchSpec;
-
-import org.junit.Test;
-
-public class SearchSpecCtsTest {
- @Test
- public void buildSearchSpecWithoutTermMatchType() {
- RuntimeException e = assertThrows(RuntimeException.class, () -> new SearchSpec.Builder()
- .addSchemaType("testSchemaType")
- .build());
- assertThat(e).hasMessageThat().contains("Missing termMatchType field");
- }
-
- @Test
- public void testBuildSearchSpec() {
- SearchSpec searchSpec = new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addNamespace("namespace1", "namespace2")
- .addSchemaType("schemaTypes1", "schemaTypes2")
- .setSnippetCount(5)
- .setSnippetCountPerProperty(10)
- .setMaxSnippetSize(15)
- .setResultCountPerPage(42)
- .setOrder(SearchSpec.ORDER_ASCENDING)
- .setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE)
- .build();
-
- assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
- assertThat(searchSpec.getNamespaces())
- .containsExactly("namespace1", "namespace2").inOrder();
- assertThat(searchSpec.getSchemaTypes())
- .containsExactly("schemaTypes1", "schemaTypes2").inOrder();
- assertThat(searchSpec.getSnippetCount()).isEqualTo(5);
- assertThat(searchSpec.getSnippetCountPerProperty()).isEqualTo(10);
- assertThat(searchSpec.getMaxSnippetSize()).isEqualTo(15);
- assertThat(searchSpec.getResultCountPerPage()).isEqualTo(42);
- assertThat(searchSpec.getOrder()).isEqualTo(SearchSpec.ORDER_ASCENDING);
- assertThat(searchSpec.getRankingStrategy())
- .isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/customer/CustomerDocumentTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/customer/CustomerDocumentTest.java
deleted file mode 100644
index 07297fb..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/customer/CustomerDocumentTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app.cts.customer;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.annotation.NonNull;
-import androidx.appsearch.app.GenericDocument;
-
-import org.junit.Test;
-
-/**
- * Tests that {@link GenericDocument} and {@link GenericDocument.Builder} are extendable by
- * developers.
- *
- * <p>This class is intentionally in a different package than {@link GenericDocument} to make sure
- * there are no package-private methods required for external developers to add custom types.
- */
-public class CustomerDocumentTest {
-
- private static final byte[] BYTE_ARRAY1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
- private static final byte[] BYTE_ARRAY2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
- private static final GenericDocument DOCUMENT_PROPERTIES1 = new GenericDocument
- .Builder<>("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
- .build();
- private static final GenericDocument DOCUMENT_PROPERTIES2 = new GenericDocument
- .Builder<>("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
- .build();
-
- @Test
- public void testBuildCustomerDocument() {
- CustomerDocument customerDocument = new CustomerDocument.Builder("uri1")
- .setScore(1)
- .setCreationTimestampMillis(0)
- .setPropertyLong("longKey1", 1L, 2L, 3L)
- .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
- .setPropertyBoolean("booleanKey1", true, false, true)
- .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
- .setPropertyBytes("byteKey1", BYTE_ARRAY1, BYTE_ARRAY2)
- .setPropertyDocument("documentKey1", DOCUMENT_PROPERTIES1, DOCUMENT_PROPERTIES2)
- .build();
-
- assertThat(customerDocument.getUri()).isEqualTo("uri1");
- assertThat(customerDocument.getSchemaType()).isEqualTo("customerDocument");
- assertThat(customerDocument.getScore()).isEqualTo(1);
- assertThat(customerDocument.getCreationTimestampMillis()).isEqualTo(0L);
- assertThat(customerDocument.getPropertyLongArray("longKey1")).asList()
- .containsExactly(1L, 2L, 3L);
- assertThat(customerDocument.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
- .containsExactly(1.0, 2.0, 3.0);
- assertThat(customerDocument.getPropertyBooleanArray("booleanKey1")).asList()
- .containsExactly(true, false, true);
- assertThat(customerDocument.getPropertyStringArray("stringKey1")).asList()
- .containsExactly("test-value1", "test-value2", "test-value3");
- assertThat(customerDocument.getPropertyBytesArray("byteKey1")).asList()
- .containsExactly(BYTE_ARRAY1, BYTE_ARRAY2);
- assertThat(customerDocument.getPropertyDocumentArray("documentKey1")).asList()
- .containsExactly(DOCUMENT_PROPERTIES1, DOCUMENT_PROPERTIES2);
- }
-
- /**
- * An example document type for test purposes, defined outside of
- * {@link GenericDocument} (the way an external developer would define
- * it).
- */
- private static class CustomerDocument extends GenericDocument {
- private CustomerDocument(GenericDocument document) {
- super(document);
- }
-
- public static class Builder extends GenericDocument.Builder<CustomerDocument.Builder> {
- private Builder(@NonNull String uri) {
- super(uri, "customerDocument");
- }
-
- @Override
- @NonNull
- public CustomerDocument build() {
- return new CustomerDocument(super.build());
- }
- }
- }
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/customer/EmailDataClass.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/customer/EmailDataClass.java
deleted file mode 100644
index 1f8136d..0000000
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/cts/customer/EmailDataClass.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// @exportToFramework:skipFile()
-package androidx.appsearch.app.cts.customer;
-
-import androidx.appsearch.annotation.AppSearchDocument;
-import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
-
-@AppSearchDocument
-public final class EmailDataClass {
- @AppSearchDocument.Uri
- public String uri;
-
- @AppSearchDocument.Property(indexingType = PropertyConfig.INDEXING_TYPE_PREFIXES)
- public String subject;
-
- @AppSearchDocument.Property(indexingType = PropertyConfig.INDEXING_TYPE_PREFIXES)
- public String body;
-}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/util/AppSearchEmail.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/util/AppSearchEmail.java
new file mode 100644
index 0000000..651e6d3
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/util/AppSearchEmail.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app.util;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
+import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
+import androidx.appsearch.app.GenericDocument;
+
+/**
+ * Encapsulates a {@link GenericDocument} that represent an email.
+ *
+ * <p>This class is a higher level implement of {@link GenericDocument}.
+ */
+public class AppSearchEmail extends GenericDocument {
+ /** The name of the schema type for {@link AppSearchEmail} documents.*/
+ public static final String SCHEMA_TYPE = "builtin:Email";
+
+ private static final String KEY_FROM = "from";
+ private static final String KEY_TO = "to";
+ private static final String KEY_CC = "cc";
+ private static final String KEY_BCC = "bcc";
+ private static final String KEY_SUBJECT = "subject";
+ private static final String KEY_BODY = "body";
+
+ public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new StringPropertyConfig.Builder(KEY_FROM)
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+
+ ).addProperty(new StringPropertyConfig.Builder(KEY_TO)
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+
+ ).addProperty(new StringPropertyConfig.Builder(KEY_CC)
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+
+ ).addProperty(new StringPropertyConfig.Builder(KEY_BCC)
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+
+ ).addProperty(new StringPropertyConfig.Builder(KEY_SUBJECT)
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+
+ ).addProperty(new StringPropertyConfig.Builder(KEY_BODY)
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+
+ ).build();
+
+ /**
+ * Creates a new {@link AppSearchEmail} from the contents of an existing
+ * {@link GenericDocument}.
+ *
+ * @param document The {@link GenericDocument} containing the email content.
+ */
+ public AppSearchEmail(@NonNull GenericDocument document) {
+ super(document);
+ }
+
+ /**
+ * Gets the from address of {@link AppSearchEmail}.
+ *
+ * @return The subject of {@link AppSearchEmail} or {@code null} if it's not been set yet.
+ */
+ @Nullable
+ public String getFrom() {
+ return getPropertyString(KEY_FROM);
+ }
+
+ /**
+ * Gets the destination addresses of {@link AppSearchEmail}.
+ *
+ * @return The destination addresses of {@link AppSearchEmail} or {@code null} if it's not
+ * been set yet.
+ */
+ @Nullable
+ public String[] getTo() {
+ return getPropertyStringArray(KEY_TO);
+ }
+
+ /**
+ * Gets the CC list of {@link AppSearchEmail}.
+ *
+ * @return The CC list of {@link AppSearchEmail} or {@code null} if it's not been set yet.
+ */
+ @Nullable
+ public String[] getCc() {
+ return getPropertyStringArray(KEY_CC);
+ }
+
+ /**
+ * Gets the BCC list of {@link AppSearchEmail}.
+ *
+ * @return The BCC list of {@link AppSearchEmail} or {@code null} if it's not been set yet.
+ */
+ @Nullable
+ public String[] getBcc() {
+ return getPropertyStringArray(KEY_BCC);
+ }
+
+ /**
+ * Gets the subject of {@link AppSearchEmail}.
+ *
+ * @return The value subject of {@link AppSearchEmail} or {@code null} if it's not been set yet.
+ */
+ @Nullable
+ public String getSubject() {
+ return getPropertyString(KEY_SUBJECT);
+ }
+
+ /**
+ * Gets the body of {@link AppSearchEmail}.
+ *
+ * @return The body of {@link AppSearchEmail} or {@code null} if it's not been set yet.
+ */
+ @Nullable
+ public String getBody() {
+ return getPropertyString(KEY_BODY);
+ }
+
+ /**
+ * The builder class for {@link AppSearchEmail}.
+ */
+ public static class Builder extends GenericDocument.Builder<Builder> {
+ /**
+ * Creates a new {@link Builder}
+ *
+ * @param namespace The namespace of the Email.
+ * @param id The ID of the Email.
+ */
+ public Builder(@NonNull String namespace, @NonNull String id) {
+ super(namespace, id, SCHEMA_TYPE);
+ }
+
+ /**
+ * Sets the from address of {@link AppSearchEmail}
+ */
+ @NonNull
+ public Builder setFrom(@NonNull String from) {
+ return setPropertyString(KEY_FROM, from);
+ }
+
+ /**
+ * Sets the destination address of {@link AppSearchEmail}
+ */
+ @NonNull
+ public Builder setTo(@NonNull String... to) {
+ return setPropertyString(KEY_TO, to);
+ }
+
+ /**
+ * Sets the CC list of {@link AppSearchEmail}
+ */
+ @NonNull
+ public Builder setCc(@NonNull String... cc) {
+ return setPropertyString(KEY_CC, cc);
+ }
+
+ /**
+ * Sets the BCC list of {@link AppSearchEmail}
+ */
+ @NonNull
+ public Builder setBcc(@NonNull String... bcc) {
+ return setPropertyString(KEY_BCC, bcc);
+ }
+
+ /**
+ * Sets the subject of {@link AppSearchEmail}
+ */
+ @NonNull
+ public Builder setSubject(@NonNull String subject) {
+ return setPropertyString(KEY_SUBJECT, subject);
+ }
+
+ /**
+ * Sets the body of {@link AppSearchEmail}
+ */
+ @NonNull
+ public Builder setBody(@NonNull String body) {
+ return setPropertyString(KEY_BODY, body);
+ }
+
+ /** Builds the {@link AppSearchEmail} object. */
+ @NonNull
+ @Override
+ public AppSearchEmail build() {
+ return new AppSearchEmail(super.build());
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/util/AppSearchTestUtils.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/util/AppSearchTestUtils.java
index e9cade2..1d25d24 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/util/AppSearchTestUtils.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/util/AppSearchTestUtils.java
@@ -19,18 +19,81 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appsearch.app.AppSearchBatchResult;
import androidx.appsearch.app.AppSearchSession;
import androidx.appsearch.app.GenericDocument;
-import androidx.appsearch.app.GetByUriRequest;
+import androidx.appsearch.app.GetByDocumentIdRequest;
import androidx.appsearch.app.SearchResult;
import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.localstorage.AppSearchLogger;
+import androidx.appsearch.localstorage.stats.CallStats;
+import androidx.appsearch.localstorage.stats.InitializeStats;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
+import androidx.appsearch.localstorage.stats.PutDocumentStats;
+import androidx.appsearch.localstorage.stats.RemoveStats;
+import androidx.appsearch.localstorage.stats.SearchStats;
+import androidx.appsearch.localstorage.stats.SetSchemaStats;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Future;
public class AppSearchTestUtils {
+ // Non-thread-safe logger implementation for testing
+ public static class TestLogger implements AppSearchLogger {
+ @Nullable
+ public CallStats mCallStats;
+ @Nullable
+ public PutDocumentStats mPutDocumentStats;
+ @Nullable
+ public InitializeStats mInitializeStats;
+ @Nullable
+ public SearchStats mSearchStats;
+ @Nullable
+ public RemoveStats mRemoveStats;
+ @Nullable
+ public OptimizeStats mOptimizeStats;
+ @Nullable
+ public SetSchemaStats mSetSchemaStats;
+
+ @Override
+ public void logStats(@NonNull CallStats stats) {
+ mCallStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull PutDocumentStats stats) {
+ mPutDocumentStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull InitializeStats stats) {
+ mInitializeStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull SearchStats stats) {
+ mSearchStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull RemoveStats stats) {
+ mRemoveStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull OptimizeStats stats) {
+ mOptimizeStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull SetSchemaStats stats) {
+ mSetSchemaStats = stats;
+ }
+ }
public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
Future<AppSearchBatchResult<K, V>> future) throws Exception {
@@ -41,30 +104,51 @@
}
public static List<GenericDocument> doGet(
- AppSearchSession session, String namespace, String... uris) throws Exception {
+ AppSearchSession session, String namespace, String... ids) throws Exception {
AppSearchBatchResult<String, GenericDocument> result = checkIsBatchResultSuccess(
- session.getByUri(
- new GetByUriRequest.Builder()
- .setNamespace(namespace).addUri(uris).build()));
- assertThat(result.getSuccesses()).hasSize(uris.length);
+ session.getByDocumentId(
+ new GetByDocumentIdRequest.Builder(namespace).addIds(ids).build()));
+ assertThat(result.getSuccesses()).hasSize(ids.length);
assertThat(result.getFailures()).isEmpty();
- List<GenericDocument> list = new ArrayList<>(uris.length);
- for (String uri : uris) {
- list.add(result.getSuccesses().get(uri));
+ List<GenericDocument> list = new ArrayList<>(ids.length);
+ for (String id : ids) {
+ list.add(result.getSuccesses().get(id));
+ }
+ return list;
+ }
+
+ public static List<GenericDocument> doGet(
+ AppSearchSession session, GetByDocumentIdRequest request) throws Exception {
+ AppSearchBatchResult<String, GenericDocument> result = checkIsBatchResultSuccess(
+ session.getByDocumentId(request));
+ Set<String> ids = request.getIds();
+ assertThat(result.getSuccesses()).hasSize(ids.size());
+ assertThat(result.getFailures()).isEmpty();
+ List<GenericDocument> list = new ArrayList<>(ids.size());
+ for (String id : ids) {
+ list.add(result.getSuccesses().get(id));
}
return list;
}
public static List<GenericDocument> convertSearchResultsToDocuments(SearchResults searchResults)
throws Exception {
- List<SearchResult> results = searchResults.getNextPage().get();
- List<GenericDocument> documents = new ArrayList<>();
- while (results.size() > 0) {
- for (SearchResult result : results) {
- documents.add(result.getDocument());
- }
- results = searchResults.getNextPage().get();
+ List<SearchResult> results = retrieveAllSearchResults(searchResults);
+ List<GenericDocument> documents = new ArrayList<>(results.size());
+ for (SearchResult result : results) {
+ documents.add(result.getGenericDocument());
}
return documents;
}
+
+ public static List<SearchResult> retrieveAllSearchResults(SearchResults searchResults)
+ throws Exception {
+ List<SearchResult> page = searchResults.getNextPage().get();
+ List<SearchResult> results = new ArrayList<>();
+ while (!page.isEmpty()) {
+ results.addAll(page);
+ page = searchResults.getNextPage().get();
+ }
+ return results;
+ }
}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchBatchResultCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchBatchResultCtsTest.java
new file mode 100644
index 0000000..0f8a50e
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchBatchResultCtsTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.app.AppSearchResult;
+
+import org.junit.Test;
+
+public class AppSearchBatchResultCtsTest {
+ @Test
+ public void testIsSuccess_true() {
+ AppSearchBatchResult<String, Integer> result =
+ new AppSearchBatchResult.Builder<String, Integer>()
+ .setSuccess("keySuccess1", 1)
+ .setSuccess("keySuccess2", 2)
+ .setResult("keySuccess3", AppSearchResult.newSuccessfulResult(3))
+ .build();
+ assertThat(result.isSuccess()).isTrue();
+ }
+
+ @Test
+ public void testIsSuccess_false() {
+ AppSearchBatchResult<String, Integer> result1 =
+ new AppSearchBatchResult.Builder<String, Integer>()
+ .setSuccess("keySuccess1", 1)
+ .setSuccess("keySuccess2", 2)
+ .setFailure(
+ "keyFailure1", AppSearchResult.RESULT_UNKNOWN_ERROR, "message1")
+ .build();
+
+ AppSearchBatchResult<String, Integer> result2 =
+ new AppSearchBatchResult.Builder<String, Integer>()
+ .setSuccess("keySuccess1", 1)
+ .setResult(
+ "keyFailure3",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INVALID_ARGUMENT, "message3"))
+ .build();
+
+ assertThat(result1.isSuccess()).isFalse();
+ assertThat(result2.isSuccess()).isFalse();
+ }
+
+ @Test
+ public void testIsSuccess_replace() {
+ AppSearchBatchResult<String, Integer> result1 =
+ new AppSearchBatchResult.Builder<String, Integer>()
+ .setSuccess("key", 1)
+ .setFailure("key", AppSearchResult.RESULT_UNKNOWN_ERROR, "message1")
+ .build();
+
+ AppSearchBatchResult<String, Integer> result2 =
+ new AppSearchBatchResult.Builder<String, Integer>()
+ .setFailure("key", AppSearchResult.RESULT_UNKNOWN_ERROR, "message1")
+ .setSuccess("key", 1)
+ .build();
+
+ assertThat(result1.isSuccess()).isFalse();
+ assertThat(result2.isSuccess()).isTrue();
+ }
+
+ @Test
+ public void testGetters() {
+ AppSearchBatchResult<String, Integer> result =
+ new AppSearchBatchResult.Builder<String, Integer>()
+ .setSuccess("keySuccess1", 1)
+ .setSuccess("keySuccess2", 2)
+ .setFailure(
+ "keyFailure1", AppSearchResult.RESULT_UNKNOWN_ERROR, "message1")
+ .setFailure(
+ "keyFailure2", AppSearchResult.RESULT_INTERNAL_ERROR, "message2")
+ .setResult("keySuccess3", AppSearchResult.newSuccessfulResult(3))
+ .setResult(
+ "keyFailure3",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INVALID_ARGUMENT, "message3"))
+ .build();
+
+ assertThat(result.isSuccess()).isFalse();
+ assertThat(result.getSuccesses()).containsExactly(
+ "keySuccess1", 1, "keySuccess2", 2, "keySuccess3", 3);
+ assertThat(result.getFailures()).containsExactly(
+ "keyFailure1",
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_UNKNOWN_ERROR, "message1"),
+ "keyFailure2",
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR, "message2"),
+ "keyFailure3",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INVALID_ARGUMENT, "message3"));
+ assertThat(result.getAll()).containsExactly(
+ "keySuccess1", AppSearchResult.newSuccessfulResult(1),
+ "keySuccess2", AppSearchResult.newSuccessfulResult(2),
+ "keySuccess3", AppSearchResult.newSuccessfulResult(3),
+ "keyFailure1",
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_UNKNOWN_ERROR, "message1"),
+ "keyFailure2",
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR, "message2"),
+ "keyFailure3",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INVALID_ARGUMENT, "message3"));
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchMigratorTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchMigratorTest.java
new file mode 100644
index 0000000..bf9ad8f
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchMigratorTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.Migrator;
+
+import org.junit.Test;
+
+public class AppSearchMigratorTest {
+
+ @Test
+ public void testOnUpgrade() {
+ Migrator migrator = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return new GenericDocument.Builder<>(document.getNamespace(), document.getId(),
+ document.getSchemaType())
+ .setCreationTimestampMillis(document.getCreationTimestampMillis())
+ .setScore(document.getScore())
+ .setTtlMillis(document.getTtlMillis())
+ .setPropertyString("migration",
+ "Upgrade the document from version " + currentVersion
+ + " to version " + finalVersion)
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ GenericDocument input = new GenericDocument.Builder<>("namespace", "id",
+ "schemaType")
+ .setCreationTimestampMillis(12345L)
+ .setScore(100)
+ .setTtlMillis(54321L).build();
+
+ GenericDocument expected = new GenericDocument.Builder<>("namespace", "id",
+ "schemaType")
+ .setCreationTimestampMillis(12345L)
+ .setScore(100)
+ .setTtlMillis(54321L)
+ .setPropertyString("migration",
+ "Upgrade the document from version 3 to version 5")
+ .build();
+
+ GenericDocument output = migrator.onUpgrade(/*currentVersion=*/3,
+ /*finalVersion=*/5, input);
+ assertThat(output).isEqualTo(expected);
+ }
+
+ @Test
+ public void testOnDowngrade() {
+ Migrator migrator = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return new GenericDocument.Builder<>(document.getNamespace(), document.getId(),
+ document.getSchemaType())
+ .setCreationTimestampMillis(document.getCreationTimestampMillis())
+ .setScore(document.getScore())
+ .setTtlMillis(document.getTtlMillis())
+ .setPropertyString("migration",
+ "Downgrade the document from version " + currentVersion
+ + " to version " + finalVersion)
+ .build();
+ }
+ };
+
+ GenericDocument input = new GenericDocument.Builder<>("namespace", "id",
+ "schemaType")
+ .setCreationTimestampMillis(12345L)
+ .setScore(100)
+ .setTtlMillis(54321L).build();
+
+ GenericDocument expected = new GenericDocument.Builder<>("namespace", "id",
+ "schemaType")
+ .setCreationTimestampMillis(12345L)
+ .setScore(100)
+ .setTtlMillis(54321L)
+ .setPropertyString("migration",
+ "Downgrade the document from version 6 to version 4")
+ .build();
+
+ GenericDocument output = migrator.onDowngrade(/*currentVersion=*/6,
+ /*finalVersion=*/4, input);
+ assertThat(output).isEqualTo(expected);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchResultCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchResultCtsTest.java
new file mode 100644
index 0000000..91dacdb
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchResultCtsTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.AppSearchResult;
+
+import org.junit.Test;
+
+public class AppSearchResultCtsTest {
+
+ @Test
+ public void testResultEquals_identical() {
+ AppSearchResult<String> result1 = AppSearchResult.newSuccessfulResult("String");
+ AppSearchResult<String> result2 = AppSearchResult.newSuccessfulResult("String");
+
+ assertThat(result1).isEqualTo(result2);
+ assertThat(result1.hashCode()).isEqualTo(result2.hashCode());
+
+ AppSearchResult<String> result3 =
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
+ "errorMessage");
+ AppSearchResult<String> result4 =
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
+ "errorMessage");
+
+ assertThat(result3).isEqualTo(result4);
+ assertThat(result3.hashCode()).isEqualTo(result4.hashCode());
+ }
+
+ @Test
+ public void testResultEquals_failure() {
+ AppSearchResult<String> result1 = AppSearchResult.newSuccessfulResult("String");
+ AppSearchResult<String> result2 = AppSearchResult.newSuccessfulResult("Wrong");
+ AppSearchResult<String> resultNull = AppSearchResult.newSuccessfulResult(/*value=*/null);
+
+ assertThat(result1).isNotEqualTo(result2);
+ assertThat(result1.hashCode()).isNotEqualTo(result2.hashCode());
+ assertThat(result1).isNotEqualTo(resultNull);
+ assertThat(result1.hashCode()).isNotEqualTo(resultNull.hashCode());
+
+ AppSearchResult<String> result3 =
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
+ "errorMessage");
+ AppSearchResult<String> result4 =
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_IO_ERROR,
+ "errorMessage");
+
+ assertThat(result3).isNotEqualTo(result4);
+ assertThat(result3.hashCode()).isNotEqualTo(result4.hashCode());
+
+
+ AppSearchResult<String> result5 =
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Wrong");
+
+ assertThat(result3).isNotEqualTo(result5);
+ assertThat(result3.hashCode()).isNotEqualTo(result5.hashCode());
+
+ AppSearchResult<String> result6 =
+ AppSearchResult.newFailedResult(AppSearchResult.RESULT_INTERNAL_ERROR,
+ /*errorMessage=*/null);
+
+ assertThat(result3).isNotEqualTo(result6);
+ assertThat(result3.hashCode()).isNotEqualTo(result6.hashCode());
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaCtsTest.java
new file mode 100644
index 0000000..2ae353a
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaCtsTest.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
+import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
+import androidx.appsearch.app.util.AppSearchEmail;
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class AppSearchSchemaCtsTest {
+ @Test
+ public void testInvalidEnums() {
+ StringPropertyConfig.Builder builder = new StringPropertyConfig.Builder("test");
+ assertThrows(IllegalArgumentException.class, () -> builder.setCardinality(99));
+ }
+
+ @Test
+ public void testDefaultValues() {
+ StringPropertyConfig builder = new StringPropertyConfig.Builder("test").build();
+ assertThat(builder.getIndexingType()).isEqualTo(StringPropertyConfig.INDEXING_TYPE_NONE);
+ assertThat(builder.getTokenizerType()).isEqualTo(StringPropertyConfig.TOKENIZER_TYPE_NONE);
+ assertThat(builder.getCardinality()).isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+ }
+
+ @Test
+ public void testDuplicateProperties() {
+ AppSearchSchema.Builder builder = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ );
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> builder.addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()));
+ assertThat(e).hasMessageThat().contains("Property defined more than once: subject");
+ }
+
+ @Test
+ public void testEquals_identical() {
+ AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ assertThat(schema1).isEqualTo(schema2);
+ assertThat(schema1.hashCode()).isEqualTo(schema2.hashCode());
+ }
+
+ @Test
+ public void testEquals_differentOrder() {
+ AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build()
+ ).build();
+ assertThat(schema1).isEqualTo(schema2);
+ assertThat(schema1.hashCode()).isEqualTo(schema2.hashCode());
+ }
+
+ @Test
+ public void testEquals_failure_differentProperty() {
+ AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS) // Diff
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ assertThat(schema1).isNotEqualTo(schema2);
+ assertThat(schema1.hashCode()).isNotEqualTo(schema2.hashCode());
+ }
+
+ @Test
+ public void testEquals_failure_differentOrder() {
+ AppSearchSchema schema1 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ // Order of 'body' and 'subject' has been switched
+ AppSearchSchema schema2 = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ assertThat(schema1).isNotEqualTo(schema2);
+ assertThat(schema1.hashCode()).isNotEqualTo(schema2.hashCode());
+ }
+
+ @Test
+ public void testPropertyConfig() {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Test")
+ .addProperty(new StringPropertyConfig.Builder("string")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("long")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("double")
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .build())
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("boolean")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("bytes")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
+ "document", AppSearchEmail.SCHEMA_TYPE)
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .setShouldIndexNestedProperties(true)
+ .build())
+ .build();
+
+ assertThat(schema.getSchemaType()).isEqualTo("Test");
+ List<PropertyConfig> properties = schema.getProperties();
+ assertThat(properties).hasSize(6);
+
+ assertThat(properties.get(0).getName()).isEqualTo("string");
+ assertThat(properties.get(0).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+ assertThat(((StringPropertyConfig) properties.get(0)).getIndexingType())
+ .isEqualTo(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS);
+ assertThat(((StringPropertyConfig) properties.get(0)).getTokenizerType())
+ .isEqualTo(StringPropertyConfig.TOKENIZER_TYPE_PLAIN);
+
+ assertThat(properties.get(1).getName()).isEqualTo("long");
+ assertThat(properties.get(1).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+ assertThat(properties.get(1)).isInstanceOf(AppSearchSchema.LongPropertyConfig.class);
+
+ assertThat(properties.get(2).getName()).isEqualTo("double");
+ assertThat(properties.get(2).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+ assertThat(properties.get(2)).isInstanceOf(AppSearchSchema.DoublePropertyConfig.class);
+
+ assertThat(properties.get(3).getName()).isEqualTo("boolean");
+ assertThat(properties.get(3).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+ assertThat(properties.get(3)).isInstanceOf(AppSearchSchema.BooleanPropertyConfig.class);
+
+ assertThat(properties.get(4).getName()).isEqualTo("bytes");
+ assertThat(properties.get(4).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+ assertThat(properties.get(4)).isInstanceOf(AppSearchSchema.BytesPropertyConfig.class);
+
+ assertThat(properties.get(5).getName()).isEqualTo("document");
+ assertThat(properties.get(5).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+ assertThat(((AppSearchSchema.DocumentPropertyConfig) properties.get(5)).getSchemaType())
+ .isEqualTo(AppSearchEmail.SCHEMA_TYPE);
+ assertThat(((AppSearchSchema.DocumentPropertyConfig) properties.get(5))
+ .shouldIndexNestedProperties()).isEqualTo(true);
+ }
+
+ @Test
+ public void testInvalidStringPropertyConfigsTokenizerNone() {
+ // Everything should work fine with the defaults.
+ final StringPropertyConfig.Builder builder =
+ new StringPropertyConfig.Builder("property");
+ assertThat(builder.build()).isNotNull();
+
+ // Setting an indexing type other NONE with the default tokenizer type (NONE) should fail.
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS);
+ assertThrows(IllegalStateException.class, () -> builder.build());
+
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES);
+ assertThrows(IllegalStateException.class, () -> builder.build());
+
+ // Explicitly setting the default should work fine.
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_NONE);
+ assertThat(builder.build()).isNotNull();
+
+ // Explicitly setting the default tokenizer type should result in the same behavior.
+ builder.setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS);
+ assertThrows(IllegalStateException.class, () -> builder.build());
+
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES);
+ assertThrows(IllegalStateException.class, () -> builder.build());
+
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_NONE);
+ assertThat(builder.build()).isNotNull();
+ }
+
+ @Test
+ public void testInvalidStringPropertyConfigsTokenizerPlain() {
+ // Setting indexing type to be NONE with tokenizer type PLAIN should fail. Regardless of
+ // whether NONE is set explicitly or just kept as default.
+ final StringPropertyConfig.Builder builder =
+ new StringPropertyConfig.Builder("property")
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN);
+ assertThrows(IllegalStateException.class, () -> builder.build());
+
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_NONE);
+ assertThrows(IllegalStateException.class, () -> builder.build());
+
+ // Setting indexing type to be something other than NONE with tokenizer type PLAIN should
+ // be just fine.
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS);
+ assertThat(builder.build()).isNotNull();
+
+ builder.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES);
+ assertThat(builder.build()).isNotNull();
+ }
+
+ @Test
+ public void testAppSearchSchema_toString() {
+ AppSearchSchema schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new StringPropertyConfig.Builder("string1")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .build())
+ .addProperty(new StringPropertyConfig.Builder("string2")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new StringPropertyConfig.Builder("string3")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("long")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("double")
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .build())
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("boolean")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("bytes")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
+ "document", AppSearchEmail.SCHEMA_TYPE)
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .setShouldIndexNestedProperties(true)
+ .build())
+ .build();
+
+ String schemaString = schema.toString();
+
+ String expectedString = "{\n"
+ + " schemaType: \"testSchema\",\n"
+ + " properties: [\n"
+ + " {\n"
+ + " name: \"boolean\",\n"
+ + " cardinality: CARDINALITY_REQUIRED,\n"
+ + " dataType: DATA_TYPE_BOOLEAN,\n"
+ + " },\n"
+ + " {\n"
+ + " name: \"bytes\",\n"
+ + " cardinality: CARDINALITY_OPTIONAL,\n"
+ + " dataType: DATA_TYPE_BYTES,\n"
+ + " },\n"
+ + " {\n"
+ + " name: \"document\",\n"
+ + " shouldIndexNestedProperties: true,\n"
+ + " schemaType: \"builtin:Email\",\n"
+ + " cardinality: CARDINALITY_REPEATED,\n"
+ + " dataType: DATA_TYPE_DOCUMENT,\n"
+ + " },\n"
+ + " {\n"
+ + " name: \"double\",\n"
+ + " cardinality: CARDINALITY_REPEATED,\n"
+ + " dataType: DATA_TYPE_DOUBLE,\n"
+ + " },\n"
+ + " {\n"
+ + " name: \"long\",\n"
+ + " cardinality: CARDINALITY_OPTIONAL,\n"
+ + " dataType: DATA_TYPE_LONG,\n"
+ + " },\n"
+ + " {\n"
+ + " name: \"string1\",\n"
+ + " indexingType: INDEXING_TYPE_NONE,\n"
+ + " tokenizerType: TOKENIZER_TYPE_NONE,\n"
+ + " cardinality: CARDINALITY_REQUIRED,\n"
+ + " dataType: DATA_TYPE_STRING,\n"
+ + " },\n"
+ + " {\n"
+ + " name: \"string2\",\n"
+ + " indexingType: INDEXING_TYPE_EXACT_TERMS,\n"
+ + " tokenizerType: TOKENIZER_TYPE_PLAIN,\n"
+ + " cardinality: CARDINALITY_REQUIRED,\n"
+ + " dataType: DATA_TYPE_STRING,\n"
+ + " },\n"
+ + " {\n"
+ + " name: \"string3\",\n"
+ + " indexingType: INDEXING_TYPE_PREFIXES,\n"
+ + " tokenizerType: TOKENIZER_TYPE_PLAIN,\n"
+ + " cardinality: CARDINALITY_REQUIRED,\n"
+ + " dataType: DATA_TYPE_STRING,\n"
+ + " }\n"
+ + " ]\n"
+ + "}";
+
+ assertThat(schemaString).isEqualTo(expectedString);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationCtsTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationCtsTestBase.java
new file mode 100644
index 0000000..ddcae47
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationCtsTestBase.java
@@ -0,0 +1,1406 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.AppSearchResult.RESULT_NOT_FOUND;
+import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.util.AppSearchTestUtils.convertSearchResultsToDocuments;
+import static androidx.appsearch.app.util.AppSearchTestUtils.doGet;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.Migrator;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.SetSchemaResponse;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+/*
+ * For schema migration, we have 4 factors
+ * A. is ForceOverride set to true?
+ * B. is the schema change backwards compatible?
+ * C. is shouldTrigger return true?
+ * D. is there a migration triggered for each incompatible type and no deleted types?
+ * If B is true then D could never be false, so that will give us 12 combinations.
+ *
+ * Trigger Delete First Second
+ * A B C D Migration Types SetSchema SetSchema
+ * TRUE TRUE TRUE TRUE Yes succeeds succeeds(noop)
+ * TRUE TRUE FALSE TRUE succeeds succeeds(noop)
+ * TRUE FALSE TRUE TRUE Yes fail succeeds
+ * TRUE FALSE TRUE FALSE Yes Yes fail succeeds
+ * TRUE FALSE FALSE TRUE Yes fail succeeds
+ * TRUE FALSE FALSE FALSE Yes fail succeeds
+ * FALSE TRUE TRUE TRUE Yes succeeds succeeds(noop)
+ * FALSE TRUE FALSE TRUE succeeds succeeds(noop)
+ * FALSE FALSE TRUE TRUE Yes fail succeeds
+ * FALSE FALSE TRUE FALSE Yes fail throw error
+ * FALSE FALSE FALSE TRUE Impossible case, migrators are inactivity
+ * FALSE FALSE FALSE FALSE fail throw error
+ */
+public abstract class AppSearchSchemaMigrationCtsTestBase {
+
+ private static final String DB_NAME = "";
+ private static final long DOCUMENT_CREATION_TIME = 12345L;
+ private static final Migrator ACTIVE_NOOP_MIGRATOR = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+ private static final Migrator INACTIVE_MIGRATOR = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return false;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ private AppSearchSession mDb;
+
+ protected abstract ListenableFuture<AppSearchSession> createSearchSession(
+ @NonNull String dbName);
+
+ @Before
+ public void setUp() throws Exception {
+ mDb = createSearchSession(DB_NAME).get();
+
+ // Cleanup whatever documents may still exist in these databases. This is needed in
+ // addition to tearDown in case a test exited without completing properly.
+ AppSearchSchema schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(schema).setForceOverride(true).build()).get();
+ GenericDocument doc = new GenericDocument.Builder<>(
+ "namespace", "id0", "testSchema")
+ .setPropertyString("subject", "testPut example1")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc).build()));
+ assertThat(result.getSuccesses()).containsExactly("id0", null);
+ assertThat(result.getFailures()).isEmpty();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Cleanup whatever documents may still exist in these databases.
+ mDb.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_A_B_C_D() throws Exception {
+ // create a backwards compatible schema and update the version
+ AppSearchSchema B_C_Schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(B_C_Schema)
+ .setMigrator("testSchema", ACTIVE_NOOP_MIGRATOR)
+ .setForceOverride(true)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_A_B_NC_D() throws Exception {
+ // create a backwards compatible schema but don't update the version
+ AppSearchSchema B_NC_Schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(B_NC_Schema)
+ .setMigrator("testSchema", ACTIVE_NOOP_MIGRATOR)
+ .setForceOverride(true)
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_A_NB_C_D() throws Exception {
+ // create a backwards incompatible schema and update the version
+ AppSearchSchema NB_C_Schema = new AppSearchSchema.Builder("testSchema")
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(NB_C_Schema)
+ .setMigrator("testSchema", ACTIVE_NOOP_MIGRATOR)
+ .setForceOverride(true)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_A_NB_C_ND() throws Exception {
+ // create a backwards incompatible schema and update the version
+ AppSearchSchema NB_C_Schema = new AppSearchSchema.Builder("testSchema")
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(NB_C_Schema)
+ .setMigrator("testSchema", INACTIVE_MIGRATOR) //ND
+ .setForceOverride(true)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_A_NB_NC_D() throws Exception {
+ // create a backwards incompatible schema but don't update the version
+ AppSearchSchema NB_NC_Schema = new AppSearchSchema.Builder("testSchema")
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(NB_NC_Schema)
+ .setMigrator("testSchema", ACTIVE_NOOP_MIGRATOR)
+ .setForceOverride(true)
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_A_NB_NC_ND() throws Exception {
+ // create a backwards incompatible schema but don't update the version
+ AppSearchSchema $B_$C_Schema = new AppSearchSchema.Builder("testSchema")
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas($B_$C_Schema)
+ .setMigrator("testSchema", INACTIVE_MIGRATOR) //ND
+ .setForceOverride(true)
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_NA_B_C_D() throws Exception {
+ // create a backwards compatible schema and update the version
+ AppSearchSchema B_C_Schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(B_C_Schema)
+ .setMigrator("testSchema", ACTIVE_NOOP_MIGRATOR)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_NA_B_NC_D() throws Exception {
+ // create a backwards compatible schema but don't update the version
+ AppSearchSchema B_NC_Schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(B_NC_Schema)
+ .setMigrator("testSchema", ACTIVE_NOOP_MIGRATOR)
+ .setForceOverride(true)
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_NA_NB_C_D() throws Exception {
+ // create a backwards incompatible schema and update the version
+ AppSearchSchema NB_C_Schema = new AppSearchSchema.Builder("testSchema")
+ .build();
+
+ mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(NB_C_Schema)
+ .setMigrator("testSchema", ACTIVE_NOOP_MIGRATOR)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ }
+
+ @Test
+ public void testSchemaMigration_NA_NB_C_ND() throws Exception {
+ // create a backwards incompatible schema and update the version
+ AppSearchSchema $B_C_Schema = new AppSearchSchema.Builder("testSchema")
+ .build();
+
+ ExecutionException exception = assertThrows(ExecutionException.class,
+ () -> mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas($B_C_Schema)
+ .setMigrator("testSchema", INACTIVE_MIGRATOR) //ND
+ .setVersion(2) // upgrade version
+ .build()).get());
+ assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+ }
+
+ @Test
+ public void testSchemaMigration_NA_NB_NC_ND() throws Exception {
+ // create a backwards incompatible schema but don't update the version
+ AppSearchSchema $B_$C_Schema = new AppSearchSchema.Builder("testSchema")
+ .build();
+
+ ExecutionException exception = assertThrows(ExecutionException.class,
+ () -> mDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas($B_$C_Schema)
+ .setMigrator("testSchema", INACTIVE_MIGRATOR) //ND
+ .build()).get());
+ assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+ }
+
+ @Test
+ public void testSchemaMigration() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("To")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(schema).setForceOverride(true).build()).get();
+
+ GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "testSchema")
+ .setPropertyString("subject", "testPut example1")
+ .setPropertyString("To", "testTo example1")
+ .build();
+ GenericDocument doc2 = new GenericDocument.Builder<>("namespace", "id2", "testSchema")
+ .setPropertyString("subject", "testPut example2")
+ .setPropertyString("To", "testTo example2")
+ .build();
+
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc1, doc2).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null, "id2", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // create new schema type and upgrade the version number
+ AppSearchSchema newSchema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ // set the new schema to AppSearch, the first document will be migrated successfully but the
+ // second one will be failed.
+
+ Migrator migrator = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return currentVersion != finalVersion;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ if (document.getId().equals("id2")) {
+ return new GenericDocument.Builder<>(document.getNamespace(), document.getId(),
+ document.getSchemaType())
+ .setPropertyString("subject", "testPut example2")
+ .setPropertyString("to",
+ "Expect to fail, property not in the schema")
+ .build();
+ }
+ return new GenericDocument.Builder<>(document.getNamespace(), document.getId(),
+ document.getSchemaType())
+ .setPropertyString("subject", "testPut example1 migrated")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ throw new IllegalStateException("Downgrade should not be triggered for this test");
+ }
+ };
+
+ SetSchemaResponse setSchemaResponse =
+ mDb.setSchema(new SetSchemaRequest.Builder().addSchemas(newSchema)
+ .setMigrator("testSchema", migrator)
+ .setVersion(2) // upgrade version
+ .build()).get();
+
+ // Check the schema has been saved
+ assertThat(mDb.getSchema().get().getSchemas()).containsExactly(newSchema);
+
+ assertThat(setSchemaResponse.getDeletedTypes()).isEmpty();
+ assertThat(setSchemaResponse.getIncompatibleTypes())
+ .containsExactly("testSchema");
+ assertThat(setSchemaResponse.getMigratedTypes())
+ .containsExactly("testSchema");
+
+ // Check migrate the first document is success
+ GenericDocument expected = new GenericDocument.Builder<>("namespace", "id1", "testSchema")
+ .setPropertyString("subject", "testPut example1 migrated")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "id1")).containsExactly(expected);
+
+ // Check migrate the second document is fail.
+ assertThat(setSchemaResponse.getMigrationFailures()).hasSize(1);
+ SetSchemaResponse.MigrationFailure migrationFailure =
+ setSchemaResponse.getMigrationFailures().get(0);
+ assertThat(migrationFailure.getNamespace()).isEqualTo("namespace");
+ assertThat(migrationFailure.getSchemaType()).isEqualTo("testSchema");
+ assertThat(migrationFailure.getDocumentId()).isEqualTo("id2");
+
+ AppSearchResult<Void> actualResult = migrationFailure.getAppSearchResult();
+ assertThat(actualResult.isSuccess()).isFalse();
+ assertThat(actualResult.getResultCode()).isEqualTo(RESULT_NOT_FOUND);
+ assertThat(actualResult.getErrorMessage())
+ .contains("Property config 'to' not found for key");
+ }
+
+ @Test
+ public void testSchemaMigration_downgrade() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("To")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(schema).setForceOverride(true).setVersion(3).build()).get();
+
+ GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "testSchema")
+ .setPropertyString("subject", "testPut example1")
+ .setPropertyString("To", "testTo example1")
+ .build();
+
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc1).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // create new schema type and upgrade the version number
+ AppSearchSchema newSchema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ // set the new schema to AppSearch
+ Migrator migrator = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return currentVersion != finalVersion;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ throw new IllegalStateException("Upgrade should not be triggered for this test");
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return new GenericDocument.Builder<>(document.getNamespace(), document.getId(),
+ document.getSchemaType())
+ .setPropertyString("subject", "testPut example1 migrated")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+ };
+
+ SetSchemaResponse setSchemaResponse =
+ mDb.setSchema(new SetSchemaRequest.Builder().addSchemas(newSchema)
+ .setMigrator("testSchema", migrator)
+ .setVersion(1) // downgrade version
+ .build()).get();
+
+ // Check the schema has been saved
+ assertThat(mDb.getSchema().get().getSchemas()).containsExactly(newSchema);
+
+ assertThat(setSchemaResponse.getDeletedTypes()).isEmpty();
+ assertThat(setSchemaResponse.getIncompatibleTypes())
+ .containsExactly("testSchema");
+ assertThat(setSchemaResponse.getMigratedTypes())
+ .containsExactly("testSchema");
+
+ // Check migrate is success
+ GenericDocument expected = new GenericDocument.Builder<>("namespace", "id1", "testSchema")
+ .setPropertyString("subject", "testPut example1 migrated")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "id1")).containsExactly(expected);
+ }
+
+ @Test
+ public void testSchemaMigration_sameVersion() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("To")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(schema).setForceOverride(true).setVersion(3).build()).get();
+
+ GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "testSchema")
+ .setPropertyString("subject", "testPut example1")
+ .setPropertyString("To", "testTo example1")
+ .build();
+
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc1).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // create new schema type with the same version number
+ AppSearchSchema newSchema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ // set the new schema to AppSearch
+ Migrator migrator = new Migrator() {
+
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return currentVersion != finalVersion;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ throw new IllegalStateException("Upgrade should not be triggered for this test");
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ throw new IllegalStateException("Downgrade should not be triggered for this test");
+ }
+ };
+
+ // SetSchema with forceOverride=false
+ ExecutionException exception = assertThrows(ExecutionException.class,
+ () -> mDb.setSchema(new SetSchemaRequest.Builder().addSchemas(newSchema)
+ .setMigrator("testSchema", migrator)
+ .setVersion(3) // same version
+ .build()).get());
+ assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+
+ // SetSchema with forceOverride=true
+ SetSchemaResponse setSchemaResponse =
+ mDb.setSchema(new SetSchemaRequest.Builder().addSchemas(newSchema)
+ .setMigrator("testSchema", migrator)
+ .setVersion(3) // same version
+ .setForceOverride(true).build()).get();
+
+ assertThat(mDb.getSchema().get().getSchemas()).containsExactly(newSchema);
+
+ assertThat(setSchemaResponse.getDeletedTypes()).isEmpty();
+ assertThat(setSchemaResponse.getIncompatibleTypes())
+ .containsExactly("testSchema");
+ assertThat(setSchemaResponse.getMigratedTypes()).isEmpty();
+
+ }
+
+ @Test
+ public void testSchemaMigration_noMigration() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("To")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(schema).setForceOverride(true).setVersion(2).build()).get();
+
+ GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "testSchema")
+ .setPropertyString("subject", "testPut example1")
+ .setPropertyString("To", "testTo example1")
+ .build();
+
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc1).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // create new schema type and upgrade the version number
+ AppSearchSchema newSchema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ // Set start version to be 3 means we won't trigger migration for 2.
+ Migrator migrator = new Migrator() {
+
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return currentVersion > 2 && currentVersion != finalVersion;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ throw new IllegalStateException("Upgrade should not be triggered for this test");
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ throw new IllegalStateException("Downgrade should not be triggered for this test");
+ }
+ };
+
+ // SetSchema with forceOverride=false
+ ExecutionException exception = assertThrows(ExecutionException.class,
+ () -> mDb.setSchema(new SetSchemaRequest.Builder().addSchemas(newSchema)
+ .setMigrator("testSchema", migrator)
+ .setVersion(4) // upgrade version
+ .build()).get());
+ assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+ }
+
+ @Test
+ public void testSchemaMigration_sourceToNowhere() throws Exception {
+ // set the source schema to AppSearch
+ AppSearchSchema schema = new AppSearchSchema.Builder("sourceSchema")
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(schema).setForceOverride(true).build()).get();
+
+ // save a doc to the source type
+ GenericDocument doc = new GenericDocument.Builder<>(
+ "namespace", "id1", "sourceSchema")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ Migrator migrator_sourceToNowhere = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return new GenericDocument.Builder<>(
+ "zombieNamespace", "zombieId", "nonExistSchema")
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ // SetSchema with forceOverride=false
+ // Source type exist, destination type doesn't exist.
+ ExecutionException exception = assertThrows(ExecutionException.class,
+ () -> mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("emptySchema").build())
+ .setMigrator("sourceSchema", migrator_sourceToNowhere)
+ .setVersion(2).build()) // upgrade version
+ .get());
+ assertThat(exception).hasMessageThat().contains(
+ "Receive a migrated document with schema type: nonExistSchema. "
+ + "But the schema types doesn't exist in the request");
+
+ // SetSchema with forceOverride=true
+ // Source type exist, destination type doesn't exist.
+ exception = assertThrows(ExecutionException.class,
+ () -> mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("emptySchema").build())
+ .setMigrator("sourceSchema", migrator_sourceToNowhere)
+ .setForceOverride(true)
+ .setVersion(2).build()) // upgrade version
+ .get());
+ assertThat(exception).hasMessageThat().contains(
+ "Receive a migrated document with schema type: nonExistSchema. "
+ + "But the schema types doesn't exist in the request");
+ }
+
+ @Test
+ public void testSchemaMigration_nowhereToDestination() throws Exception {
+ // set the destination schema to AppSearch
+ AppSearchSchema destinationSchema =
+ new AppSearchSchema.Builder("destinationSchema").build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(destinationSchema).setForceOverride(true).build()).get();
+
+ Migrator migrator_nowhereToDestination = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+
+ // Source type doesn't exist, destination type exist. Since source type doesn't exist,
+ // no matter force override or not, the migrator won't be invoked
+ // SetSchema with forceOverride=false
+ SetSchemaResponse setSchemaResponse =
+ mDb.setSchema(new SetSchemaRequest.Builder().addSchemas(destinationSchema)
+ .addSchemas(new AppSearchSchema.Builder("emptySchema").build())
+ .setMigrator("nonExistSchema", migrator_nowhereToDestination)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ assertThat(setSchemaResponse.getMigratedTypes()).isEmpty();
+
+ // SetSchema with forceOverride=true
+ setSchemaResponse =
+ mDb.setSchema(new SetSchemaRequest.Builder().addSchemas(destinationSchema)
+ .addSchemas(new AppSearchSchema.Builder("emptySchema").build())
+ .setMigrator("nonExistSchema", migrator_nowhereToDestination)
+ .setVersion(2) // upgrade version
+ .setForceOverride(true).build()).get();
+ assertThat(setSchemaResponse.getMigratedTypes()).isEmpty();
+ }
+
+ @Test
+ public void testSchemaMigration_nowhereToNowhere() throws Exception {
+ // set empty schema
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .setForceOverride(true).build()).get();
+ Migrator migrator_nowhereToNowhere = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+
+ // Source type doesn't exist, destination type exist. Since source type doesn't exist,
+ // no matter force override or not, the migrator won't be invoked
+ // SetSchema with forceOverride=false
+ SetSchemaResponse setSchemaResponse =
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("emptySchema").build())
+ .setMigrator("nonExistSchema", migrator_nowhereToNowhere)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ assertThat(setSchemaResponse.getMigratedTypes()).isEmpty();
+
+ // SetSchema with forceOverride=true
+ setSchemaResponse =
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("emptySchema").build())
+ .setMigrator("nonExistSchema", migrator_nowhereToNowhere)
+ .setVersion(2) // upgrade version
+ .setForceOverride(true).build()).get();
+ assertThat(setSchemaResponse.getMigratedTypes()).isEmpty();
+ }
+
+ @Test
+ public void testSchemaMigration_toAnotherType() throws Exception {
+ // set the source schema to AppSearch
+ AppSearchSchema sourceSchema = new AppSearchSchema.Builder("sourceSchema")
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(sourceSchema).setForceOverride(true).build()).get();
+
+ // save a doc to the source type
+ GenericDocument doc = new GenericDocument.Builder<>(
+ "namespace", "id1", "sourceSchema").build();
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // create the destination type and migrator
+ AppSearchSchema destinationSchema = new AppSearchSchema.Builder("destinationSchema")
+ .build();
+ Migrator migrator = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return new GenericDocument.Builder<>("namespace",
+ document.getId(),
+ "destinationSchema")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ // SetSchema with forceOverride=false and increase overall version
+ SetSchemaResponse setSchemaResponse = mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(destinationSchema)
+ .setMigrator("sourceSchema", migrator)
+ .setForceOverride(false)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ assertThat(setSchemaResponse.getDeletedTypes())
+ .containsExactly("sourceSchema");
+ assertThat(setSchemaResponse.getIncompatibleTypes()).isEmpty();
+ assertThat(setSchemaResponse.getMigratedTypes())
+ .containsExactly("sourceSchema");
+
+ // Check successfully migrate the doc to the destination type
+ GenericDocument expected = new GenericDocument.Builder<>(
+ "namespace", "id1", "destinationSchema")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "id1")).containsExactly(expected);
+ }
+
+ @Test
+ public void testSchemaMigration_toMultipleDestinationType() throws Exception {
+ // set the source schema to AppSearch
+ AppSearchSchema sourceSchema = new AppSearchSchema.Builder("Person")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("Age")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(sourceSchema).setForceOverride(true).build()).get();
+
+ // save a child and an adult to the Person type
+ GenericDocument childDoc = new GenericDocument.Builder<>(
+ "namespace", "Person1", "Person")
+ .setPropertyLong("Age", 6).build();
+ GenericDocument adultDoc = new GenericDocument.Builder<>(
+ "namespace", "Person2", "Person")
+ .setPropertyLong("Age", 36).build();
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(childDoc, adultDoc).build()));
+ assertThat(result.getSuccesses()).containsExactly("Person1", null, "Person2", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // create the migrator
+ Migrator migrator = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ if (document.getPropertyLong("Age") < 21) {
+ return new GenericDocument.Builder<>(
+ "namespace", "child-id", "Child")
+ .setPropertyLong("Age", document.getPropertyLong("Age"))
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ } else {
+ return new GenericDocument.Builder<>(
+ "namespace", "adult-id", "Adult")
+ .setPropertyLong("Age", document.getPropertyLong("Age"))
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ // create adult and child schema
+ AppSearchSchema adultSchema = new AppSearchSchema.Builder("Adult")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("Age")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+ AppSearchSchema childSchema = new AppSearchSchema.Builder("Child")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("Age")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+
+ // SetSchema with forceOverride=false and increase overall version
+ SetSchemaResponse setSchemaResponse = mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(adultSchema, childSchema)
+ .setMigrator("Person", migrator)
+ .setForceOverride(false)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ assertThat(setSchemaResponse.getDeletedTypes())
+ .containsExactly("Person");
+ assertThat(setSchemaResponse.getIncompatibleTypes()).isEmpty();
+ assertThat(setSchemaResponse.getMigratedTypes())
+ .containsExactly("Person");
+
+ // Check successfully migrate the child doc
+ GenericDocument expectedInChild = new GenericDocument.Builder<>(
+ "namespace", "child-id", "Child")
+ .setPropertyLong("Age", 6)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "child-id"))
+ .containsExactly(expectedInChild);
+
+ // Check successfully migrate the adult doc
+ GenericDocument expectedInAdult = new GenericDocument.Builder<>(
+ "namespace", "adult-id", "Adult")
+ .setPropertyLong("Age", 36)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "adult-id"))
+ .containsExactly(expectedInAdult);
+ }
+
+ @Test
+ public void testSchemaMigration_loadTest() throws Exception {
+ // set the two source type A & B to AppSearch
+ AppSearchSchema sourceSchemaA = new AppSearchSchema.Builder("schemaA")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("num")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+ AppSearchSchema sourceSchemaB = new AppSearchSchema.Builder("schemaB")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("num")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(sourceSchemaA, sourceSchemaB).setForceOverride(true).build()).get();
+
+ // save 100 docs to each type
+ PutDocumentsRequest.Builder putRequestBuilder = new PutDocumentsRequest.Builder();
+ for (int i = 0; i < 100; i++) {
+ GenericDocument docInA = new GenericDocument.Builder<>(
+ "namespace", "idA-" + i, "schemaA")
+ .setPropertyLong("num", i)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ GenericDocument docInB = new GenericDocument.Builder<>(
+ "namespace", "idB-" + i, "schemaB")
+ .setPropertyLong("num", i)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ putRequestBuilder.addGenericDocuments(docInA, docInB);
+ }
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ putRequestBuilder.build()));
+ assertThat(result.getFailures()).isEmpty();
+
+ // create three destination types B, C & D
+ AppSearchSchema destinationSchemaB = new AppSearchSchema.Builder("schemaB")
+ .addProperty(
+ new AppSearchSchema.LongPropertyConfig.Builder("numNewProperty")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+ AppSearchSchema destinationSchemaC = new AppSearchSchema.Builder("schemaC")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("num")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+ AppSearchSchema destinationSchemaD = new AppSearchSchema.Builder("schemaD")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("num")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .build();
+
+ // Create an active migrator for type A which will migrate first 50 docs to C and second
+ // 50 docs to D
+ Migrator migratorA = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ if (document.getPropertyLong("num") < 50) {
+ return new GenericDocument.Builder<>("namespace",
+ document.getId() + "-destC", "schemaC")
+ .setPropertyLong("num", document.getPropertyLong("num"))
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ } else {
+ return new GenericDocument.Builder<>("namespace",
+ document.getId() + "-destD", "schemaD")
+ .setPropertyLong("num", document.getPropertyLong("num"))
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ // Create an active migrator for type B which will migrate first 50 docs to B and second
+ // 50 docs to D
+ Migrator migratorB = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ if (document.getPropertyLong("num") < 50) {
+ return new GenericDocument.Builder<>("namespace",
+ document.getId() + "-destB", "schemaB")
+ .setPropertyLong("numNewProperty",
+ document.getPropertyLong("num"))
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ } else {
+ return new GenericDocument.Builder<>("namespace",
+ document.getId() + "-destD", "schemaD")
+ .setPropertyLong("num", document.getPropertyLong("num"))
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ // SetSchema with forceOverride=false and increase overall version
+ SetSchemaResponse setSchemaResponse = mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(destinationSchemaB, destinationSchemaC, destinationSchemaD)
+ .setMigrator("schemaA", migratorA)
+ .setMigrator("schemaB", migratorB)
+ .setForceOverride(false)
+ .setVersion(2) // upgrade version
+ .build()).get();
+ assertThat(setSchemaResponse.getDeletedTypes())
+ .containsExactly("schemaA");
+ assertThat(setSchemaResponse.getIncompatibleTypes()).containsExactly("schemaB");
+ assertThat(setSchemaResponse.getMigratedTypes())
+ .containsExactly("schemaA", "schemaB");
+
+ // generate expected documents
+ List<GenericDocument> expectedDocs = new ArrayList<>();
+ for (int i = 0; i < 50; i++) {
+ GenericDocument docAToC = new GenericDocument.Builder<>(
+ "namespace", "idA-" + i + "-destC", "schemaC")
+ .setPropertyLong("num", i)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ GenericDocument docBToB = new GenericDocument.Builder<>(
+ "namespace", "idB-" + i + "-destB", "schemaB")
+ .setPropertyLong("numNewProperty", i)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ expectedDocs.add(docAToC);
+ expectedDocs.add(docBToB);
+ }
+
+ for (int i = 50; i < 100; i++) {
+ GenericDocument docAToD = new GenericDocument.Builder<>(
+ "namespace", "idA-" + i + "-destD", "schemaD")
+ .setPropertyLong("num", i)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ GenericDocument docBToD = new GenericDocument.Builder<>(
+ "namespace", "idB-" + i + "-destD", "schemaD")
+ .setPropertyLong("num", i)
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ expectedDocs.add(docAToD);
+ expectedDocs.add(docBToD);
+ }
+ //query all documents and compare
+ SearchResults searchResults = mDb.search("", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactlyElementsIn(expectedDocs);
+ }
+
+ //*************************** Multi-step migration tests ******************************
+ // Version structure and how version bumps:
+ // Version 1: Start - typeA docs contains "subject" property.
+ // Version 2: typeA docs get new "body" property, contains "subject" and "body" now.
+ // Version 3: typeA docs is migrated to typeB, typeA docs got removed, typeB doc contains
+ // "subject" and "body" property.
+ // Version 4: typeB docs remove "subject" property, contains only "body" now.
+
+ // Create a multi-step migrator for A, which could migrate version 1-3 to 4.
+ private static final Migrator MULTI_STEP_MIGRATOR_A = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return currentVersion < 3;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ GenericDocument.Builder docBuilder =
+ new GenericDocument.Builder<>("namespace", "id", "TypeB")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME);
+ if (currentVersion == 2) {
+ docBuilder.setPropertyString("body", document.getPropertyString("body"));
+ } else {
+ docBuilder.setPropertyString("body",
+ "new content for the newly added 'body' property");
+ }
+ return docBuilder.build();
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ // create a multi-step migrator for B, which could migrate version 1-3 to 4.
+ private static final Migrator MULTI_STEP_MIGRATOR_B = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return currentVersion == 3;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return new GenericDocument.Builder<>("namespace", "id", "TypeB")
+ .setPropertyString("body", document.getPropertyString("body"))
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+
+ // create a setSchemaRequest, which could migrate version 1-3 to 4.
+ private static final SetSchemaRequest MULTI_STEP_REQUEST = new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("TypeB")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("body")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build())
+ .setMigrator("TypeA", MULTI_STEP_MIGRATOR_A)
+ .setMigrator("TypeB", MULTI_STEP_MIGRATOR_B)
+ .setVersion(4)
+ .build();
+
+ @Test
+ public void testSchemaMigration_multiStep1To4() throws Exception {
+ // set version 1 to the database, only contain TypeA
+ AppSearchSchema typeA = new AppSearchSchema.Builder("TypeA")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(typeA).setForceOverride(true).setVersion(1).build()).get();
+
+ // save a doc to version 1.
+ GenericDocument doc = new GenericDocument.Builder<>(
+ "namespace", "id", "TypeA")
+ .setPropertyString("subject", "subject")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc).build()));
+ assertThat(result.getSuccesses()).containsExactly("id", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // update to version 4.
+ SetSchemaResponse setSchemaResponse = mDb.setSchema(MULTI_STEP_REQUEST).get();
+ assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("TypeA");
+ assertThat(setSchemaResponse.getIncompatibleTypes()).isEmpty();
+ assertThat(setSchemaResponse.getMigratedTypes()).containsExactly("TypeA");
+
+ // Create expected doc. Since we started at version 1 and migrated to version 4:
+ // 1: A 'body' property should have been added with "new content for the newly added 'body'
+ // property"
+ // 2: The type should have been changed from 'TypeA' to 'TypeB'
+ // 3: The 'subject' property should have been removed
+ GenericDocument expected = new GenericDocument.Builder<>(
+ "namespace", "id", "TypeB")
+ .setPropertyString("body", "new content for the newly added 'body' property")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "id")).containsExactly(expected);
+ }
+
+ @Test
+ public void testSchemaMigration_multiStep2To4() throws Exception {
+ // set version 2 to the database, only contain TypeA with a new property
+ AppSearchSchema typeA = new AppSearchSchema.Builder("TypeA")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("body")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(typeA).setForceOverride(true).setVersion(2).build()).get();
+
+ // save a doc to version 2.
+ GenericDocument doc = new GenericDocument.Builder<>(
+ "namespace", "id", "TypeA")
+ .setPropertyString("subject", "subject")
+ .setPropertyString("body", "bodyFromA")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc).build()));
+ assertThat(result.getSuccesses()).containsExactly("id", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // update to version 4.
+ SetSchemaResponse setSchemaResponse = mDb.setSchema(MULTI_STEP_REQUEST).get();
+ assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("TypeA");
+ assertThat(setSchemaResponse.getIncompatibleTypes()).isEmpty();
+ assertThat(setSchemaResponse.getMigratedTypes()).containsExactly("TypeA");
+
+ // create expected doc, body exists in type A of version 2
+ GenericDocument expected = new GenericDocument.Builder<>(
+ "namespace", "id", "TypeB")
+ .setPropertyString("body", "bodyFromA")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "id")).containsExactly(expected);
+ }
+
+ @Test
+ public void testSchemaMigration_multiStep3To4() throws Exception {
+ // set version 3 to the database, only contain TypeB
+ AppSearchSchema typeA = new AppSearchSchema.Builder("TypeB")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("body")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(typeA).setForceOverride(true).setVersion(3).build()).get();
+
+ // save a doc to version 2.
+ GenericDocument doc = new GenericDocument.Builder<>(
+ "namespace", "id", "TypeB")
+ .setPropertyString("subject", "subject")
+ .setPropertyString("body", "bodyFromB")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME).build();
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(doc).build()));
+ assertThat(result.getSuccesses()).containsExactly("id", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // update to version 4.
+ SetSchemaResponse setSchemaResponse = mDb.setSchema(MULTI_STEP_REQUEST).get();
+ assertThat(setSchemaResponse.getDeletedTypes()).isEmpty();
+ assertThat(setSchemaResponse.getIncompatibleTypes()).containsExactly("TypeB");
+ assertThat(setSchemaResponse.getMigratedTypes()).containsExactly("TypeB");
+
+ // create expected doc, body exists in type A of version 3
+ GenericDocument expected = new GenericDocument.Builder<>(
+ "namespace", "id", "TypeB")
+ .setPropertyString("body", "bodyFromB")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ assertThat(doGet(mDb, "namespace", "id")).containsExactly(expected);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationLocalCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationLocalCtsTest.java
new file mode 100644
index 0000000..6525ddd
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationLocalCtsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.cts.app;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.localstorage.LocalStorage;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class AppSearchSchemaMigrationLocalCtsTest extends AppSearchSchemaMigrationCtsTestBase{
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, dbName).build());
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationPlatformCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationPlatformCtsTest.java
new file mode 100644
index 0000000..405d82e
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationPlatformCtsTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.cts.app;
+
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.platformstorage.PlatformStorage;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+public class AppSearchSchemaMigrationPlatformCtsTest extends AppSearchSchemaMigrationCtsTestBase{
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return PlatformStorage.createSearchSession(
+ new PlatformStorage.SearchContext.Builder(context, dbName).build());
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionCtsTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionCtsTestBase.java
new file mode 100644
index 0000000..325c432
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionCtsTestBase.java
@@ -0,0 +1,2989 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.AppSearchResult.RESULT_INVALID_SCHEMA;
+import static androidx.appsearch.app.AppSearchResult.RESULT_NOT_FOUND;
+import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.util.AppSearchTestUtils.convertSearchResultsToDocuments;
+import static androidx.appsearch.app.util.AppSearchTestUtils.doGet;
+import static androidx.appsearch.app.util.AppSearchTestUtils.retrieveAllSearchResults;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
+import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.GetByDocumentIdRequest;
+import androidx.appsearch.app.GetSchemaResponse;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.RemoveByDocumentIdRequest;
+import androidx.appsearch.app.ReportUsageRequest;
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.StorageInfo;
+import androidx.appsearch.app.util.AppSearchEmail;
+import androidx.appsearch.cts.app.customer.EmailDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public abstract class AppSearchSessionCtsTestBase {
+ static final String DB_NAME_1 = "";
+ static final String DB_NAME_2 = "testDb2";
+
+ private AppSearchSession mDb1;
+ private AppSearchSession mDb2;
+
+ protected abstract ListenableFuture<AppSearchSession> createSearchSession(
+ @NonNull String dbName);
+
+ protected abstract ListenableFuture<AppSearchSession> createSearchSession(
+ @NonNull String dbName, @NonNull ExecutorService executor);
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+
+ mDb1 = createSearchSession(DB_NAME_1).get();
+ mDb2 = createSearchSession(DB_NAME_2).get();
+
+ // Cleanup whatever documents may still exist in these databases. This is needed in
+ // addition to tearDown in case a test exited without completing properly.
+ cleanup();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Cleanup whatever documents may still exist in these databases.
+ cleanup();
+ }
+
+ private void cleanup() throws Exception {
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+ }
+
+ @Test
+ public void testSetSchema() throws Exception {
+ AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(emailSchema).build()).get();
+ }
+
+ @Test
+ public void testSetSchema_Failure() throws Exception {
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ AppSearchSchema emailSchema1 = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
+ .build();
+
+ Throwable throwable = assertThrows(ExecutionException.class,
+ () -> mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(emailSchema1).build()).get()).getCause();
+ assertThat(throwable).isInstanceOf(AppSearchException.class);
+ AppSearchException exception = (AppSearchException) throwable;
+ assertThat(exception.getResultCode()).isEqualTo(RESULT_INVALID_SCHEMA);
+ assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+ assertThat(exception).hasMessageThat().contains("Incompatible types: {builtin:Email}");
+
+ throwable = assertThrows(ExecutionException.class,
+ () -> mDb1.setSchema(new SetSchemaRequest.Builder().build()).get()).getCause();
+
+ assertThat(throwable).isInstanceOf(AppSearchException.class);
+ exception = (AppSearchException) throwable;
+ assertThat(exception.getResultCode()).isEqualTo(RESULT_INVALID_SCHEMA);
+ assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+ assertThat(exception).hasMessageThat().contains("Deleted types: {builtin:Email}");
+ }
+
+ @Test
+ public void testSetSchema_updateVersion() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+
+ mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(schema)
+ .setVersion(1).build()).get();
+
+ Set<AppSearchSchema> actualSchemaTypes = mDb1.getSchema().get().getSchemas();
+ assertThat(actualSchemaTypes).containsExactly(schema);
+
+ // increase version number
+ mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(schema)
+ .setVersion(2).build()).get();
+
+ GetSchemaResponse getSchemaResponse = mDb1.getSchema().get();
+ assertThat(getSchemaResponse.getSchemas()).containsExactly(schema);
+ assertThat(getSchemaResponse.getVersion()).isEqualTo(2);
+ }
+
+ @Test
+ public void testSetSchema_checkVersion() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Email")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+
+ // set different version number to different database.
+ mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(schema)
+ .setVersion(135).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder().addSchemas(schema)
+ .setVersion(246).build()).get();
+
+
+ // check the version has been set correctly.
+ GetSchemaResponse getSchemaResponse = mDb1.getSchema().get();
+ assertThat(getSchemaResponse.getSchemas()).containsExactly(schema);
+ assertThat(getSchemaResponse.getVersion()).isEqualTo(135);
+
+ getSchemaResponse = mDb2.getSchema().get();
+ assertThat(getSchemaResponse.getSchemas()).containsExactly(schema);
+ assertThat(getSchemaResponse.getVersion()).isEqualTo(246);
+ }
+
+// @exportToFramework:startStrip()
+
+ @Test
+ public void testSetSchema_addDocumentClasses() throws Exception {
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addDocumentClasses(EmailDocument.class).build()).get();
+ }
+// @exportToFramework:endStrip()
+
+// @exportToFramework:startStrip()
+
+ @Test
+ public void testGetSchema() throws Exception {
+ AppSearchSchema emailSchema1 = new AppSearchSchema.Builder("Email1")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ AppSearchSchema emailSchema2 = new AppSearchSchema.Builder("Email2")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS) // Diff
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS) // Diff
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+
+ SetSchemaRequest request1 = new SetSchemaRequest.Builder()
+ .addSchemas(emailSchema1).addDocumentClasses(EmailDocument.class).build();
+ SetSchemaRequest request2 = new SetSchemaRequest.Builder()
+ .addSchemas(emailSchema2).addDocumentClasses(EmailDocument.class).build();
+
+ mDb1.setSchema(request1).get();
+ mDb2.setSchema(request2).get();
+
+ Set<AppSearchSchema> actual1 = mDb1.getSchema().get().getSchemas();
+ assertThat(actual1).hasSize(2);
+ assertThat(actual1).isEqualTo(request1.getSchemas());
+ Set<AppSearchSchema> actual2 = mDb2.getSchema().get().getSchemas();
+ assertThat(actual2).hasSize(2);
+ assertThat(actual2).isEqualTo(request2.getSchemas());
+ }
+// @exportToFramework:endStrip()
+
+ @Test
+ public void testGetSchema_allPropertyTypes() throws Exception {
+ AppSearchSchema inSchema = new AppSearchSchema.Builder("Test")
+ .addProperty(new StringPropertyConfig.Builder("string")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("long")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("double")
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .build())
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("boolean")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .build())
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("bytes")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
+ "document", AppSearchEmail.SCHEMA_TYPE)
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .setShouldIndexNestedProperties(true)
+ .build())
+ .build();
+
+ // Add it to AppSearch and then obtain it again
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(inSchema, AppSearchEmail.SCHEMA).build()).get();
+ GetSchemaResponse response = mDb1.getSchema().get();
+ List<AppSearchSchema> schemas = new ArrayList<>(response.getSchemas());
+ assertThat(schemas).containsExactly(inSchema, AppSearchEmail.SCHEMA);
+ AppSearchSchema outSchema;
+ if (schemas.get(0).getSchemaType().equals("Test")) {
+ outSchema = schemas.get(0);
+ } else {
+ outSchema = schemas.get(1);
+ }
+ assertThat(outSchema.getSchemaType()).isEqualTo("Test");
+ assertThat(outSchema).isNotSameInstanceAs(inSchema);
+
+ List<PropertyConfig> properties = outSchema.getProperties();
+ assertThat(properties).hasSize(6);
+
+ assertThat(properties.get(0).getName()).isEqualTo("string");
+ assertThat(properties.get(0).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+ assertThat(((StringPropertyConfig) properties.get(0)).getIndexingType())
+ .isEqualTo(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS);
+ assertThat(((StringPropertyConfig) properties.get(0)).getTokenizerType())
+ .isEqualTo(StringPropertyConfig.TOKENIZER_TYPE_PLAIN);
+
+ assertThat(properties.get(1).getName()).isEqualTo("long");
+ assertThat(properties.get(1).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+ assertThat(properties.get(1)).isInstanceOf(AppSearchSchema.LongPropertyConfig.class);
+
+ assertThat(properties.get(2).getName()).isEqualTo("double");
+ assertThat(properties.get(2).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+ assertThat(properties.get(2)).isInstanceOf(AppSearchSchema.DoublePropertyConfig.class);
+
+ assertThat(properties.get(3).getName()).isEqualTo("boolean");
+ assertThat(properties.get(3).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+ assertThat(properties.get(3)).isInstanceOf(AppSearchSchema.BooleanPropertyConfig.class);
+
+ assertThat(properties.get(4).getName()).isEqualTo("bytes");
+ assertThat(properties.get(4).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+ assertThat(properties.get(4)).isInstanceOf(AppSearchSchema.BytesPropertyConfig.class);
+
+ assertThat(properties.get(5).getName()).isEqualTo("document");
+ assertThat(properties.get(5).getCardinality())
+ .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+ assertThat(((AppSearchSchema.DocumentPropertyConfig) properties.get(5)).getSchemaType())
+ .isEqualTo(AppSearchEmail.SCHEMA_TYPE);
+ assertThat(((AppSearchSchema.DocumentPropertyConfig) properties.get(5))
+ .shouldIndexNestedProperties()).isEqualTo(true);
+ }
+
+ @Test
+ public void testGetNamespaces() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ assertThat(mDb1.getNamespaces().get()).isEmpty();
+
+ // Index a document
+ checkIsBatchResultSuccess(mDb1.put(new PutDocumentsRequest.Builder()
+ .addGenericDocuments(new AppSearchEmail.Builder("namespace1", "id1").build())
+ .build()));
+ assertThat(mDb1.getNamespaces().get()).containsExactly("namespace1");
+
+ // Index additional data
+ checkIsBatchResultSuccess(mDb1.put(new PutDocumentsRequest.Builder()
+ .addGenericDocuments(
+ new AppSearchEmail.Builder("namespace2", "id1").build(),
+ new AppSearchEmail.Builder("namespace2", "id2").build(),
+ new AppSearchEmail.Builder("namespace3", "id1").build())
+ .build()));
+ assertThat(mDb1.getNamespaces().get()).containsExactly(
+ "namespace1", "namespace2", "namespace3");
+
+ // Remove namespace2/id2 -- namespace2 should still exist because of namespace2/id1
+ checkIsBatchResultSuccess(
+ mDb1.remove(new RemoveByDocumentIdRequest.Builder("namespace2").addIds(
+ "id2").build()));
+ assertThat(mDb1.getNamespaces().get()).containsExactly(
+ "namespace1", "namespace2", "namespace3");
+
+ // Remove namespace2/id1 -- namespace2 should now be gone
+ checkIsBatchResultSuccess(
+ mDb1.remove(new RemoveByDocumentIdRequest.Builder("namespace2").addIds(
+ "id1").build()));
+ assertThat(mDb1.getNamespaces().get()).containsExactly("namespace1", "namespace3");
+
+ // Make sure the list of namespaces is preserved after restart
+ mDb1.close();
+ mDb1 = createSearchSession(DB_NAME_1).get();
+ assertThat(mDb1.getNamespaces().get()).containsExactly("namespace1", "namespace3");
+ }
+
+ @Test
+ public void testGetNamespaces_dbIsolation() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ assertThat(mDb1.getNamespaces().get()).isEmpty();
+ assertThat(mDb2.getNamespaces().get()).isEmpty();
+
+ // Index documents
+ checkIsBatchResultSuccess(mDb1.put(new PutDocumentsRequest.Builder()
+ .addGenericDocuments(new AppSearchEmail.Builder("namespace1_db1", "id1").build())
+ .build()));
+ checkIsBatchResultSuccess(mDb1.put(new PutDocumentsRequest.Builder()
+ .addGenericDocuments(new AppSearchEmail.Builder("namespace2_db1", "id1").build())
+ .build()));
+ checkIsBatchResultSuccess(mDb2.put(new PutDocumentsRequest.Builder()
+ .addGenericDocuments(new AppSearchEmail.Builder("namespace_db2", "id1").build())
+ .build()));
+ assertThat(mDb1.getNamespaces().get()).containsExactly("namespace1_db1", "namespace2_db1");
+ assertThat(mDb2.getNamespaces().get()).containsExactly("namespace_db2");
+
+ // Make sure the list of namespaces is preserved after restart
+ mDb1.close();
+ mDb1 = createSearchSession(DB_NAME_1).get();
+ assertThat(mDb1.getNamespaces().get()).containsExactly("namespace1_db1", "namespace2_db1");
+ assertThat(mDb2.getNamespaces().get()).containsExactly("namespace_db2");
+ }
+
+ @Test
+ public void testGetSchema_emptyDB() throws Exception {
+ GetSchemaResponse getSchemaResponse = mDb1.getSchema().get();
+ assertThat(getSchemaResponse.getVersion()).isEqualTo(0);
+ }
+
+ @Test
+ public void testPutDocuments() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+ }
+
+// @exportToFramework:startStrip()
+
+ @Test
+ public void testPut_addDocumentClasses() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addDocumentClasses(EmailDocument.class).build()).get();
+
+ // Index a document
+ EmailDocument email = new EmailDocument();
+ email.namespace = "namespace";
+ email.id = "id1";
+ email.subject = "testPut example";
+ email.body = "This is the body of the testPut email";
+
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addDocuments(email).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+ }
+// @exportToFramework:endStrip()
+
+ @Test
+ public void testUpdateSchema() throws Exception {
+ // Schema registration
+ AppSearchSchema oldEmailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ AppSearchSchema newEmailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ AppSearchSchema giftSchema = new AppSearchSchema.Builder("Gift")
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(oldEmailSchema).build()).get();
+
+ // Try to index a gift. This should fail as it's not in the schema.
+ GenericDocument gift =
+ new GenericDocument.Builder<>("namespace", "gift1", "Gift").setPropertyLong("price",
+ 5).build();
+ AppSearchBatchResult<String, Void> result =
+ mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(gift).build()).get();
+ assertThat(result.isSuccess()).isFalse();
+ assertThat(result.getFailures().get("gift1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Update the schema to include the gift and update email with a new field
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(newEmailSchema, giftSchema).build()).get();
+
+ // Try to index the document again, which should now work
+ checkIsBatchResultSuccess(
+ mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(gift).build()));
+
+ // Indexing an email with a body should also work
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace", "email1")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(
+ mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()));
+ }
+
+ @Test
+ public void testRemoveSchema() throws Exception {
+ // Schema registration
+ AppSearchSchema emailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(emailSchema).build()).get();
+
+ // Index an email and check it present.
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace", "email1")
+ .setSubject("testPut example")
+ .build();
+ checkIsBatchResultSuccess(
+ mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()));
+ List<GenericDocument> outDocuments =
+ doGet(mDb1, "namespace", "email1");
+ assertThat(outDocuments).hasSize(1);
+ AppSearchEmail outEmail = new AppSearchEmail(outDocuments.get(0));
+ assertThat(outEmail).isEqualTo(email);
+
+ // Try to remove the email schema. This should fail as it's an incompatible change.
+ Throwable failResult1 = assertThrows(
+ ExecutionException.class,
+ () -> mDb1.setSchema(new SetSchemaRequest.Builder().build()).get()).getCause();
+ assertThat(failResult1).isInstanceOf(AppSearchException.class);
+ assertThat(failResult1).hasMessageThat().contains("Schema is incompatible");
+ assertThat(failResult1).hasMessageThat().contains(
+ "Deleted types: {builtin:Email}");
+
+ // Try to remove the email schema again, which should now work as we set forceOverride to
+ // be true.
+ mDb1.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+
+ // Make sure the indexed email is gone.
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("email1")
+ .build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("email1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Try to index an email again. This should fail as the schema has been removed.
+ AppSearchEmail email2 = new AppSearchEmail.Builder("namespace", "email2")
+ .setSubject("testPut example")
+ .build();
+ AppSearchBatchResult<String, Void> failResult2 = mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email2).build()).get();
+ assertThat(failResult2.isSuccess()).isFalse();
+ assertThat(failResult2.getFailures().get("email2").getErrorMessage())
+ .isEqualTo("Schema type config 'androidx.appsearch.test$" + DB_NAME_1
+ + "/builtin:Email' not found");
+ }
+
+ @Test
+ public void testRemoveSchema_twoDatabases() throws Exception {
+ // Schema registration in mDb1 and mDb2
+ AppSearchSchema emailSchema = new AppSearchSchema.Builder(AppSearchEmail.SCHEMA_TYPE)
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(emailSchema).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder().addSchemas(emailSchema).build()).get();
+
+ // Index an email and check it present in database1.
+ AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "email1")
+ .setSubject("testPut example")
+ .build();
+ checkIsBatchResultSuccess(
+ mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+ List<GenericDocument> outDocuments =
+ doGet(mDb1, "namespace", "email1");
+ assertThat(outDocuments).hasSize(1);
+ AppSearchEmail outEmail = new AppSearchEmail(outDocuments.get(0));
+ assertThat(outEmail).isEqualTo(email1);
+
+ // Index an email and check it present in database2.
+ AppSearchEmail email2 = new AppSearchEmail.Builder("namespace", "email2")
+ .setSubject("testPut example")
+ .build();
+ checkIsBatchResultSuccess(
+ mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email2).build()));
+ outDocuments = doGet(mDb2, "namespace", "email2");
+ assertThat(outDocuments).hasSize(1);
+ outEmail = new AppSearchEmail(outDocuments.get(0));
+ assertThat(outEmail).isEqualTo(email2);
+
+ // Try to remove the email schema in database1. This should fail as it's an incompatible
+ // change.
+ Throwable failResult1 = assertThrows(
+ ExecutionException.class,
+ () -> mDb1.setSchema(new SetSchemaRequest.Builder().build()).get()).getCause();
+ assertThat(failResult1).isInstanceOf(AppSearchException.class);
+ assertThat(failResult1).hasMessageThat().contains("Schema is incompatible");
+ assertThat(failResult1).hasMessageThat().contains(
+ "Deleted types: {builtin:Email}");
+
+ // Try to remove the email schema again, which should now work as we set forceOverride to
+ // be true.
+ mDb1.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+
+ // Make sure the indexed email is gone in database 1.
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("email1").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("email1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Try to index an email again. This should fail as the schema has been removed.
+ AppSearchEmail email3 = new AppSearchEmail.Builder("namespace", "email3")
+ .setSubject("testPut example")
+ .build();
+ AppSearchBatchResult<String, Void> failResult2 = mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email3).build()).get();
+ assertThat(failResult2.isSuccess()).isFalse();
+ assertThat(failResult2.getFailures().get("email3").getErrorMessage())
+ .isEqualTo("Schema type config 'androidx.appsearch.test$" + DB_NAME_1
+ + "/builtin:Email' not found");
+
+ // Make sure email in database 2 still present.
+ outDocuments = doGet(mDb2, "namespace", "email2");
+ assertThat(outDocuments).hasSize(1);
+ outEmail = new AppSearchEmail(outDocuments.get(0));
+ assertThat(outEmail).isEqualTo(email2);
+
+ // Make sure email could still be indexed in database 2.
+ checkIsBatchResultSuccess(
+ mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email2).build()));
+ }
+
+ @Test
+ public void testGetDocuments() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // Get the document
+ List<GenericDocument> outDocuments = doGet(mDb1, "namespace", "id1");
+ assertThat(outDocuments).hasSize(1);
+ AppSearchEmail outEmail = new AppSearchEmail(outDocuments.get(0));
+ assertThat(outEmail).isEqualTo(inEmail);
+
+ // Can't get the document in the other instance.
+ AppSearchBatchResult<String, GenericDocument> failResult = mDb2.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds(
+ "id1").build()).get();
+ assertThat(failResult.isSuccess()).isFalse();
+ assertThat(failResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+// @exportToFramework:startStrip()
+
+ @Test
+ public void testGet_addDocumentClasses() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addDocumentClasses(EmailDocument.class).build()).get();
+
+ // Index a document
+ EmailDocument inEmail = new EmailDocument();
+ inEmail.namespace = "namespace";
+ inEmail.id = "id1";
+ inEmail.subject = "testPut example";
+ inEmail.body = "This is the body of the testPut inEmail";
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addDocuments(inEmail).build()));
+
+ // Get the document
+ List<GenericDocument> outDocuments = doGet(mDb1, "namespace", "id1");
+ assertThat(outDocuments).hasSize(1);
+ EmailDocument outEmail = outDocuments.get(0).toDocumentClass(EmailDocument.class);
+ assertThat(inEmail.id).isEqualTo(outEmail.id);
+ assertThat(inEmail.subject).isEqualTo(outEmail.subject);
+ assertThat(inEmail.body).isEqualTo(outEmail.body);
+ }
+// @exportToFramework:endStrip()
+
+
+ @Test
+ public void testGetDocuments_projection() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1, email2).build()));
+
+ // Get with type property paths {"Email", ["subject", "to"]}
+ GetByDocumentIdRequest request = new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("id1", "id2")
+ .addProjection(
+ AppSearchEmail.SCHEMA_TYPE, ImmutableList.of("subject", "to"))
+ .build();
+ List<GenericDocument> outDocuments = doGet(mDb1, request);
+
+ // The two email documents should have been returned with only the "subject" and "to"
+ // properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ assertThat(outDocuments).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testGetDocuments_projectionEmpty() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1, email2).build()));
+
+ // Get with type property paths {"Email", ["subject", "to"]}
+ GetByDocumentIdRequest request = new GetByDocumentIdRequest.Builder("namespace").addIds(
+ "id1",
+ "id2").addProjection(AppSearchEmail.SCHEMA_TYPE, Collections.emptyList()).build();
+ List<GenericDocument> outDocuments = doGet(mDb1, request);
+
+ // The two email documents should have been returned without any properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .build();
+ assertThat(outDocuments).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testGetDocuments_projectionNonExistentType() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1, email2).build()));
+
+ // Get with type property paths {"Email", ["subject", "to"]}
+ GetByDocumentIdRequest request = new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("id1", "id2")
+ .addProjection("NonExistentType", Collections.emptyList())
+ .addProjection(AppSearchEmail.SCHEMA_TYPE, ImmutableList.of("subject", "to"))
+ .build();
+ List<GenericDocument> outDocuments = doGet(mDb1, request);
+
+ // The two email documents should have been returned with only the "subject" and "to"
+ // properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ assertThat(outDocuments).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testGetDocuments_wildcardProjection() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1, email2).build()));
+
+ // Get with type property paths {"Email", ["subject", "to"]}
+ GetByDocumentIdRequest request = new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("id1", "id2")
+ .addProjection(
+ GetByDocumentIdRequest.PROJECTION_SCHEMA_TYPE_WILDCARD,
+ ImmutableList.of("subject", "to"))
+ .build();
+ List<GenericDocument> outDocuments = doGet(mDb1, request);
+
+ // The two email documents should have been returned with only the "subject" and "to"
+ // properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ assertThat(outDocuments).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testGetDocuments_wildcardProjectionEmpty() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1, email2).build()));
+
+ // Get with type property paths {"Email", ["subject", "to"]}
+ GetByDocumentIdRequest request = new GetByDocumentIdRequest.Builder("namespace").addIds(
+ "id1",
+ "id2").addProjection(GetByDocumentIdRequest.PROJECTION_SCHEMA_TYPE_WILDCARD,
+ Collections.emptyList()).build();
+ List<GenericDocument> outDocuments = doGet(mDb1, request);
+
+ // The two email documents should have been returned without any properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .build();
+ assertThat(outDocuments).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testGetDocuments_wildcardProjectionNonExistentType() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1, email2).build()));
+
+ // Get with type property paths {"Email", ["subject", "to"]}
+ GetByDocumentIdRequest request = new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("id1", "id2")
+ .addProjection("NonExistentType", Collections.emptyList())
+ .addProjection(
+ GetByDocumentIdRequest.PROJECTION_SCHEMA_TYPE_WILDCARD,
+ ImmutableList.of("subject", "to"))
+ .build();
+ List<GenericDocument> outDocuments = doGet(mDb1, request);
+
+ // The two email documents should have been returned with only the "subject" and "to"
+ // properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ assertThat(outDocuments).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testQuery() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // Query for the document
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(1);
+ assertThat(documents.get(0)).isEqualTo(inEmail);
+
+ // Multi-term query
+ searchResults = mDb1.search("body email", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(1);
+ assertThat(documents.get(0)).isEqualTo(inEmail);
+ }
+
+ @Test
+ public void testQuery_getNextPage() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ Set<AppSearchEmail> emailSet = new HashSet<>();
+ PutDocumentsRequest.Builder putDocumentsRequestBuilder = new PutDocumentsRequest.Builder();
+ // Index 31 documents
+ for (int i = 0; i < 31; i++) {
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id" + i)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ emailSet.add(inEmail);
+ putDocumentsRequestBuilder.addGenericDocuments(inEmail);
+ }
+ checkIsBatchResultSuccess(mDb1.put(putDocumentsRequestBuilder.build()));
+
+ // Set number of results per page is 7.
+ SearchResults searchResults = mDb1.search("body",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(7)
+ .build());
+ List<GenericDocument> documents = new ArrayList<>();
+
+ int pageNumber = 0;
+ List<SearchResult> results;
+
+ // keep loading next page until it's empty.
+ do {
+ results = searchResults.getNextPage().get();
+ ++pageNumber;
+ for (SearchResult result : results) {
+ documents.add(result.getGenericDocument());
+ }
+ } while (results.size() > 0);
+
+ // check all document presents
+ assertThat(documents).containsExactlyElementsIn(emailSet);
+ assertThat(pageNumber).isEqualTo(6); // 5 (upper(31/7)) + 1 (final empty page)
+ }
+
+ @Test
+ public void testQuery_relevanceScoring() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("Mary had a little lamb")
+ .setBody("A little lamb, little lamb")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("I'm a little teapot")
+ .setBody("short and stout. Here is my handle, here is my spout.")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1, email2).build()));
+
+ // Query for "little". It should match both emails.
+ SearchResults searchResults = mDb1.search("little", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
+ .build());
+ List<SearchResult> results = retrieveAllSearchResults(searchResults);
+
+ // The email1 should be ranked higher because 'little' appears three times in email1 and
+ // only once in email2.
+ assertThat(results).hasSize(2);
+ assertThat(results.get(0).getGenericDocument()).isEqualTo(email1);
+ assertThat(results.get(0).getRankingSignal()).isGreaterThan(
+ results.get(1).getRankingSignal());
+ assertThat(results.get(1).getGenericDocument()).isEqualTo(email2);
+ assertThat(results.get(1).getRankingSignal()).isGreaterThan(0);
+
+ // Query for "little OR stout". It should match both emails.
+ searchResults = mDb1.search("little OR stout", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
+ .build());
+ results = retrieveAllSearchResults(searchResults);
+
+ // The email2 should be ranked higher because 'little' appears once and "stout", which is a
+ // rarer term, appears once. email1 only has the three 'little' appearances.
+ assertThat(results).hasSize(2);
+ assertThat(results.get(0).getGenericDocument()).isEqualTo(email2);
+ assertThat(results.get(0).getRankingSignal()).isGreaterThan(
+ results.get(1).getRankingSignal());
+ assertThat(results.get(1).getGenericDocument()).isEqualTo(email1);
+ assertThat(results.get(1).getRankingSignal()).isGreaterThan(0);
+ }
+
+ @Test
+ public void testQuery_typeFilter() throws Exception {
+ // Schema registration
+ AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
+ .addProperty(new StringPropertyConfig.Builder("foo")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+ ).build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(genericSchema)
+ .build()).get();
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument inDoc = new GenericDocument.Builder<>("namespace", "id2", "Generic")
+ .setPropertyString("foo", "body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail, inDoc).build()));
+
+ // Query for the documents
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(2);
+ assertThat(documents).containsExactly(inEmail, inDoc);
+
+ // Query only for Document
+ searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .addFilterSchemas("Generic", "Generic") // duplicate type in filter won't matter.
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(1);
+ assertThat(documents).containsExactly(inDoc);
+ }
+
+ @Test
+ public void testQuery_packageFilter() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("foo")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()));
+
+ // Query for the document within our package
+ SearchResults searchResults = mDb1.search("foo", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addFilterPackageNames(ApplicationProvider.getApplicationContext().getPackageName())
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(email);
+
+ // Query for the document in some other package, which won't exist
+ searchResults = mDb1.search("foo", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addFilterPackageNames("some.other.package")
+ .build());
+ List<SearchResult> results = searchResults.getNextPage().get();
+ assertThat(results).isEmpty();
+ }
+
+ @Test
+ public void testQuery_namespaceFilter() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index two documents
+ AppSearchEmail expectedEmail =
+ new AppSearchEmail.Builder("expectedNamespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail unexpectedEmail =
+ new AppSearchEmail.Builder("unexpectedNamespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(expectedEmail, unexpectedEmail).build()));
+
+ // Query for all namespaces
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(2);
+ assertThat(documents).containsExactly(expectedEmail, unexpectedEmail);
+
+ // Query only for expectedNamespace
+ searchResults = mDb1.search("body",
+ new SearchSpec.Builder()
+ .addFilterNamespaces("expectedNamespace")
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(1);
+ assertThat(documents).containsExactly(expectedEmail);
+ }
+
+ @Test
+ public void testQuery_getPackageName() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // Query for the document
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+
+ List<SearchResult> results;
+ List<GenericDocument> documents = new ArrayList<>();
+ // keep loading next page until it's empty.
+ do {
+ results = searchResults.getNextPage().get();
+ for (SearchResult result : results) {
+ assertThat(result.getGenericDocument()).isEqualTo(inEmail);
+ assertThat(result.getPackageName()).isEqualTo(
+ ApplicationProvider.getApplicationContext().getPackageName());
+ documents.add(result.getGenericDocument());
+ }
+ } while (results.size() > 0);
+ assertThat(documents).hasSize(1);
+ }
+
+ @Test
+ public void testQuery_getDatabaseName() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // Query for the document
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+
+ List<SearchResult> results;
+ List<GenericDocument> documents = new ArrayList<>();
+ // keep loading next page until it's empty.
+ do {
+ results = searchResults.getNextPage().get();
+ for (SearchResult result : results) {
+ assertThat(result.getGenericDocument()).isEqualTo(inEmail);
+ assertThat(result.getDatabaseName()).isEqualTo(DB_NAME_1);
+ documents.add(result.getGenericDocument());
+ }
+ } while (results.size() > 0);
+ assertThat(documents).hasSize(1);
+
+ // Schema registration for another database
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // Query for the document
+ searchResults = mDb2.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+
+ documents = new ArrayList<>();
+ // keep loading next page until it's empty.
+ do {
+ results = searchResults.getNextPage().get();
+ for (SearchResult result : results) {
+ assertThat(result.getGenericDocument()).isEqualTo(inEmail);
+ assertThat(result.getDatabaseName()).isEqualTo(DB_NAME_2);
+ documents.add(result.getGenericDocument());
+ }
+ } while (results.size() > 0);
+ assertThat(documents).hasSize(1);
+ }
+
+ @Test
+ public void testQuery_projection() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(new AppSearchSchema.Builder("Note")
+ .addProperty(new StringPropertyConfig.Builder("title")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build())
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument note =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email, note).build()));
+
+ // Query with type property paths {"Email", ["body", "to"]}
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection(AppSearchEmail.SCHEMA_TYPE, ImmutableList.of("body", "to"))
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+ // The email document should have been returned with only the "body" and "to"
+ // properties. The note document should have been returned with all of its properties.
+ AppSearchEmail expectedEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument expectedNote =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ assertThat(documents).containsExactly(expectedNote, expectedEmail);
+ }
+
+ @Test
+ public void testQuery_projectionEmpty() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(new AppSearchSchema.Builder("Note")
+ .addProperty(new StringPropertyConfig.Builder("title")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build())
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument note =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email, note).build()));
+
+ // Query with type property paths {"Email", []}
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection(AppSearchEmail.SCHEMA_TYPE, Collections.emptyList())
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+ // The email document should have been returned without any properties. The note document
+ // should have been returned with all of its properties.
+ AppSearchEmail expectedEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .build();
+ GenericDocument expectedNote =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ assertThat(documents).containsExactly(expectedNote, expectedEmail);
+ }
+
+ @Test
+ public void testQuery_projectionNonExistentType() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(new AppSearchSchema.Builder("Note")
+ .addProperty(new StringPropertyConfig.Builder("title")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build())
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument note =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email, note).build()));
+
+ // Query with type property paths {"NonExistentType", []}, {"Email", ["body", "to"]}
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection("NonExistentType", Collections.emptyList())
+ .addProjection(AppSearchEmail.SCHEMA_TYPE, ImmutableList.of("body", "to"))
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+ // The email document should have been returned with only the "body" and "to" properties.
+ // The note document should have been returned with all of its properties.
+ AppSearchEmail expectedEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument expectedNote =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ assertThat(documents).containsExactly(expectedNote, expectedEmail);
+ }
+
+ @Test
+ public void testQuery_wildcardProjection() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(new AppSearchSchema.Builder("Note")
+ .addProperty(new StringPropertyConfig.Builder("title")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN).build())
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build())
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument note =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email, note).build()));
+
+ // Query with type property paths {"*", ["body", "to"]}
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection(
+ SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD, ImmutableList.of("body", "to"))
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+ // The email document should have been returned with only the "body" and "to"
+ // properties. The note document should have been returned with only the "body" property.
+ AppSearchEmail expectedEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument expectedNote =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("body", "Note body").build();
+ assertThat(documents).containsExactly(expectedNote, expectedEmail);
+ }
+
+ @Test
+ public void testQuery_wildcardProjectionEmpty() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(new AppSearchSchema.Builder("Note")
+ .addProperty(new StringPropertyConfig.Builder("title")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN).build())
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN).build())
+ .build()).build()).get();
+
+ // Index two documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument note =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email, note).build()));
+
+ // Query with type property paths {"*", []}
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection(SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD, Collections.emptyList())
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+ // The email and note documents should have been returned without any properties.
+ AppSearchEmail expectedEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .build();
+ GenericDocument expectedNote =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000).build();
+ assertThat(documents).containsExactly(expectedNote, expectedEmail);
+ }
+
+ @Test
+ public void testQuery_wildcardProjectionNonExistentType() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(new AppSearchSchema.Builder("Note")
+ .addProperty(new StringPropertyConfig.Builder("title")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new StringPropertyConfig.Builder("body")
+ .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build())
+ .build()).get();
+
+ // Index two documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument note =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("title", "Note title")
+ .setPropertyString("body", "Note body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email, note).build()));
+
+ // Query with type property paths {"NonExistentType", []}, {"*", ["body", "to"]}
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection("NonExistentType", Collections.emptyList())
+ .addProjection(
+ SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD, ImmutableList.of("body", "to"))
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+ // The email document should have been returned with only the "body" and "to"
+ // properties. The note document should have been returned with only the "body" property.
+ AppSearchEmail expectedEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setBody("This is the body of the testPut email")
+ .build();
+ GenericDocument expectedNote =
+ new GenericDocument.Builder<>("namespace", "id2", "Note")
+ .setCreationTimestampMillis(1000)
+ .setPropertyString("body", "Note body").build();
+ assertThat(documents).containsExactly(expectedNote, expectedEmail);
+ }
+
+ @Test
+ public void testQuery_twoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document to instance 1.
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+
+ // Index a document to instance 2.
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail2).build()));
+
+ // Query for instance 1.
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(1);
+ assertThat(documents).containsExactly(inEmail1);
+
+ // Query for instance 2.
+ searchResults = mDb2.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(1);
+ assertThat(documents).containsExactly(inEmail2);
+ }
+
+ @Test
+ public void testSnippet() throws Exception {
+ // Schema registration
+ AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+ ).build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(genericSchema).build()).get();
+
+ // Index a document
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "id", "Generic")
+ .setPropertyString("subject", "A commonly used fake word is foo. "
+ + "Another nonsense word that’s used a lot is bar")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(document).build()));
+
+ // Query for the document
+ SearchResults searchResults = mDb1.search("foo",
+ new SearchSpec.Builder()
+ .addFilterSchemas("Generic")
+ .setSnippetCount(1)
+ .setSnippetCountPerProperty(1)
+ .setMaxSnippetSize(10)
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build());
+ List<SearchResult> results = searchResults.getNextPage().get();
+ assertThat(results).hasSize(1);
+
+ List<SearchResult.MatchInfo> matchInfos = results.get(0).getMatchInfos();
+ assertThat(matchInfos).isNotNull();
+ assertThat(matchInfos).hasSize(1);
+ SearchResult.MatchInfo matchInfo = matchInfos.get(0);
+ assertThat(matchInfo.getFullText()).isEqualTo("A commonly used fake word is foo. "
+ + "Another nonsense word that’s used a lot is bar");
+ assertThat(matchInfo.getExactMatchRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/29, /*upper=*/32));
+ assertThat(matchInfo.getExactMatch()).isEqualTo("foo");
+ assertThat(matchInfo.getSnippetRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/26, /*upper=*/33));
+ assertThat(matchInfo.getSnippet()).isEqualTo("is foo.");
+ }
+
+ @Test
+ public void testSetSnippetCount() throws Exception {
+ // Schema registration
+ AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+ ).build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(genericSchema).build()).get();
+
+ // Index documents
+ checkIsBatchResultSuccess(mDb1.put(new PutDocumentsRequest.Builder().addGenericDocuments(
+ new GenericDocument.Builder<>("namespace", "id1", "Generic")
+ .setPropertyString(
+ "subject",
+ "I like cats", "I like dogs", "I like birds", "I like fish")
+ .setScore(10)
+ .build(),
+ new GenericDocument.Builder<>("namespace", "id2", "Generic")
+ .setPropertyString(
+ "subject",
+ "I like red", "I like green", "I like blue", "I like yellow")
+ .setScore(20)
+ .build(),
+ new GenericDocument.Builder<>("namespace", "id3", "Generic")
+ .setPropertyString(
+ "subject",
+ "I like cupcakes",
+ "I like donuts",
+ "I like eclairs",
+ "I like froyo")
+ .setScore(5)
+ .build())
+ .build()));
+
+ // Query for the document
+ SearchResults searchResults = mDb1.search(
+ "like",
+ new SearchSpec.Builder()
+ .addFilterSchemas("Generic")
+ .setSnippetCount(2)
+ .setSnippetCountPerProperty(3)
+ .setMaxSnippetSize(11)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE)
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build());
+
+ // Check result 1
+ List<SearchResult> results = searchResults.getNextPage().get();
+ assertThat(results).hasSize(3);
+
+ assertThat(results.get(0).getGenericDocument().getId()).isEqualTo("id2");
+ List<SearchResult.MatchInfo> matchInfos = results.get(0).getMatchInfos();
+ assertThat(matchInfos).hasSize(3);
+ assertThat(matchInfos.get(0).getSnippet()).isEqualTo("I like red");
+ assertThat(matchInfos.get(1).getSnippet()).isEqualTo("I like");
+ assertThat(matchInfos.get(2).getSnippet()).isEqualTo("I like blue");
+
+ // Check result 2
+ assertThat(results.get(1).getGenericDocument().getId()).isEqualTo("id1");
+ matchInfos = results.get(1).getMatchInfos();
+ assertThat(matchInfos).hasSize(3);
+ assertThat(matchInfos.get(0).getSnippet()).isEqualTo("I like cats");
+ assertThat(matchInfos.get(1).getSnippet()).isEqualTo("I like dogs");
+ assertThat(matchInfos.get(2).getSnippet()).isEqualTo("I like");
+
+ // Check result 2
+ assertThat(results.get(2).getGenericDocument().getId()).isEqualTo("id3");
+ matchInfos = results.get(2).getMatchInfos();
+ assertThat(matchInfos).isEmpty();
+ }
+
+ @Test
+ public void testCJKSnippet() throws Exception {
+ // Schema registration
+ AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
+ .addProperty(new StringPropertyConfig.Builder("subject")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+ ).build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(genericSchema).build()).get();
+
+ String japanese =
+ "差し出されたのが今日ランドセルでした普通の子であれば満面の笑みで俺を言うでしょうしかし私は赤いランド"
+ + "セルを見て笑うことができませんでしたどうしたのと心配そうな仕事ガラスながら渋い顔する私書いたこと言"
+ + "うんじゃないのカードとなる声を聞きたい私は目から涙をこぼしながらおじいちゃんの近くにかけおり頭をポ"
+ + "ンポンと叩きピンクが良かったんだもん";
+ // Index a document
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "id", "Generic")
+ .setPropertyString("subject", japanese)
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(document).build()));
+
+ // Query for the document
+ SearchResults searchResults = mDb1.search("は",
+ new SearchSpec.Builder()
+ .addFilterSchemas("Generic")
+ .setSnippetCount(1)
+ .setSnippetCountPerProperty(1)
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build());
+ List<SearchResult> results = searchResults.getNextPage().get();
+ assertThat(results).hasSize(1);
+
+ List<SearchResult.MatchInfo> matchInfos = results.get(0).getMatchInfos();
+ assertThat(matchInfos).isNotNull();
+ assertThat(matchInfos).hasSize(1);
+ SearchResult.MatchInfo matchInfo = matchInfos.get(0);
+ assertThat(matchInfo.getFullText()).isEqualTo(japanese);
+ assertThat(matchInfo.getExactMatchRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/44, /*upper=*/45));
+ assertThat(matchInfo.getExactMatch()).isEqualTo("は");
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+ assertThat(doGet(mDb1, "namespace", "id2")).hasSize(1);
+
+ // Delete the document
+ checkIsBatchResultSuccess(mDb1.remove(
+ new RemoveByDocumentIdRequest.Builder("namespace").addIds(
+ "id1").build()));
+
+ // Make sure it's really gone
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1",
+ "id2").build())
+ .get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(getResult.getSuccesses().get("id2")).isEqualTo(email2);
+
+ // Test if we delete a nonexistent id.
+ AppSearchBatchResult<String, Void> deleteResult = mDb1.remove(
+ new RemoveByDocumentIdRequest.Builder("namespace").addIds(
+ "id1").build()).get();
+
+ assertThat(deleteResult.getFailures().get("id1").getResultCode()).isEqualTo(
+ AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testRemove_multipleIds() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+ assertThat(doGet(mDb1, "namespace", "id2")).hasSize(1);
+
+ // Delete the document
+ checkIsBatchResultSuccess(mDb1.remove(
+ new RemoveByDocumentIdRequest.Builder("namespace").addIds("id1", "id2").build()));
+
+ // Make sure it's really gone
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1",
+ "id2").build())
+ .get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(getResult.getFailures().get("id2").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testRemoveByQuery() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("foo")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("bar")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+ assertThat(doGet(mDb1, "namespace", "id2")).hasSize(1);
+
+ // Delete the email 1 by query "foo"
+ mDb1.remove("foo",
+ new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_PREFIX).build()).get();
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1", "id2").build())
+ .get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(getResult.getSuccesses().get("id2")).isEqualTo(email2);
+
+ // Delete the email 2 by query "bar"
+ mDb1.remove("bar",
+ new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_PREFIX).build()).get();
+ getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id2").build())
+ .get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id2").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testRemoveByQuery_packageFilter() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("foo")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+
+ // Try to delete email with query "foo", but restricted to a different package name.
+ // Won't work and email will still exist.
+ mDb1.remove("foo",
+ new SearchSpec.Builder().setTermMatch(
+ SearchSpec.TERM_MATCH_PREFIX).addFilterPackageNames(
+ "some.other.package").build()).get();
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+
+ // Delete the email by query "foo", restricted to the correct package this time.
+ mDb1.remove("foo", new SearchSpec.Builder().setTermMatch(
+ SearchSpec.TERM_MATCH_PREFIX).addFilterPackageNames(
+ ApplicationProvider.getApplicationContext().getPackageName()).build()).get();
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1", "id2").build())
+ .get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testRemove_twoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+
+ // Can't delete in the other instance.
+ AppSearchBatchResult<String, Void> deleteResult = mDb2.remove(
+ new RemoveByDocumentIdRequest.Builder("namespace").addIds("id1").build()).get();
+ assertThat(deleteResult.getFailures().get("id1").getResultCode()).isEqualTo(
+ AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+
+ // Delete the document
+ checkIsBatchResultSuccess(mDb1.remove(
+ new RemoveByDocumentIdRequest.Builder("namespace").addIds("id1").build()));
+
+ // Make sure it's really gone
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Test if we delete a nonexistent id.
+ deleteResult = mDb1.remove(
+ new RemoveByDocumentIdRequest.Builder("namespace").addIds("id1").build()).get();
+ assertThat(deleteResult.getFailures().get("id1").getResultCode()).isEqualTo(
+ AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testRemoveByTypes() throws Exception {
+ // Schema registration
+ AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic").build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).addSchemas(
+ genericSchema).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id3", "Generic").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2, document1)
+ .build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1", "id2", "id3")).hasSize(3);
+
+ // Delete the email type
+ mDb1.remove("",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterSchemas(AppSearchEmail.SCHEMA_TYPE)
+ .build())
+ .get();
+
+ // Make sure it's really gone
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1", "id2", "id3").build())
+ .get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(getResult.getFailures().get("id2").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(getResult.getSuccesses().get("id3")).isEqualTo(document1);
+ }
+
+ @Test
+ public void testRemoveByTypes_twoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email2).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+ assertThat(doGet(mDb2, "namespace", "id2")).hasSize(1);
+
+ // Delete the email type in instance 1
+ mDb1.remove("",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterSchemas(AppSearchEmail.SCHEMA_TYPE)
+ .build())
+ .get();
+
+ // Make sure it's really gone in instance 1
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Make sure it's still in instance 2.
+ getResult = mDb2.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id2").build()).get();
+ assertThat(getResult.isSuccess()).isTrue();
+ assertThat(getResult.getSuccesses().get("id2")).isEqualTo(email2);
+ }
+
+ @Test
+ public void testRemoveByNamespace() throws Exception {
+ // Schema registration
+ AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
+ .addProperty(new StringPropertyConfig.Builder("foo")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+ ).build();
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).addSchemas(
+ genericSchema).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("email", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("email", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("document", "id3", "Generic")
+ .setPropertyString("foo", "bar").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2, document1)
+ .build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, /*namespace=*/"email", "id1", "id2")).hasSize(2);
+ assertThat(doGet(mDb1, /*namespace=*/"document", "id3")).hasSize(1);
+
+ // Delete the email namespace
+ mDb1.remove("",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterNamespaces("email")
+ .build())
+ .get();
+
+ // Make sure it's really gone
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("email")
+ .addIds("id1", "id2").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(getResult.getFailures().get("id2").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("document")
+ .addIds("id3").build()).get();
+ assertThat(getResult.isSuccess()).isTrue();
+ assertThat(getResult.getSuccesses().get("id3")).isEqualTo(document1);
+ }
+
+ @Test
+ public void testRemoveByNamespaces_twoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("email", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("email", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email2).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, /*namespace=*/"email", "id1")).hasSize(1);
+ assertThat(doGet(mDb2, /*namespace=*/"email", "id2")).hasSize(1);
+
+ // Delete the email namespace in instance 1
+ mDb1.remove("",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterNamespaces("email")
+ .build())
+ .get();
+
+ // Make sure it's really gone in instance 1
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("email")
+ .addIds("id1").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Make sure it's still in instance 2.
+ getResult = mDb2.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("email")
+ .addIds("id2").build()).get();
+ assertThat(getResult.isSuccess()).isTrue();
+ assertThat(getResult.getSuccesses().get("id2")).isEqualTo(email2);
+ }
+
+ @Test
+ public void testRemoveAll_twoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email2).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+ assertThat(doGet(mDb2, "namespace", "id2")).hasSize(1);
+
+ // Delete the all document in instance 1
+ mDb1.remove("",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build())
+ .get();
+
+ // Make sure it's really gone in instance 1
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Make sure it's still in instance 2.
+ getResult = mDb2.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id2").build()).get();
+ assertThat(getResult.isSuccess()).isTrue();
+ assertThat(getResult.getSuccesses().get("id2")).isEqualTo(email2);
+ }
+
+ @Test
+ public void testRemoveAll_termMatchType() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 2")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ AppSearchEmail email3 =
+ new AppSearchEmail.Builder("namespace", "id3")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 3")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ AppSearchEmail email4 =
+ new AppSearchEmail.Builder("namespace", "id4")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example 4")
+ .setBody("This is the body of the testPut second email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2).build()));
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email3, email4).build()));
+
+ // Check the presence of the documents
+ SearchResults searchResults = mDb1.search("", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(2);
+ searchResults = mDb2.search("", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).hasSize(2);
+
+ // Delete the all document in instance 1 with TERM_MATCH_PREFIX
+ mDb1.remove("",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build())
+ .get();
+ searchResults = mDb1.search("", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).isEmpty();
+
+ // Delete the all document in instance 2 with TERM_MATCH_EXACT_ONLY
+ mDb2.remove("",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build())
+ .get();
+ searchResults = mDb2.search("", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).isEmpty();
+ }
+
+ @Test
+ public void testRemoveAllAfterEmpty() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+
+ // Check the presence of the documents
+ assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+
+ // Remove the document
+ checkIsBatchResultSuccess(
+ mDb1.remove(new RemoveByDocumentIdRequest.Builder("namespace").addIds(
+ "id1").build()));
+
+ // Make sure it's really gone
+ AppSearchBatchResult<String, GenericDocument> getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Delete the all documents
+ mDb1.remove(
+ "", new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_PREFIX).build())
+ .get();
+
+ // Make sure it's still gone
+ getResult = mDb1.getByDocumentId(
+ new GetByDocumentIdRequest.Builder("namespace").addIds("id1").build()).get();
+ assertThat(getResult.isSuccess()).isFalse();
+ assertThat(getResult.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testCloseAndReopen() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // close and re-open the appSearchSession
+ mDb1.close();
+ mDb1 = createSearchSession(DB_NAME_1).get();
+
+ // Query for the document
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(inEmail);
+ }
+
+ @Test
+ public void testCallAfterClose() throws Exception {
+
+ // Create a same-thread database by inject an executor which could help us maintain the
+ // execution order of those async tasks.
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession sameThreadDb = createSearchSession(
+ "sameThreadDb", MoreExecutors.newDirectExecutorService()).get();
+
+ try {
+ // Schema registration -- just mutate something
+ sameThreadDb.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Close the database. No further call will be allowed.
+ sameThreadDb.close();
+
+ // Try to query the closed database
+ // We are using the same-thread db here to make sure it has been closed.
+ IllegalStateException e = assertThrows(IllegalStateException.class, () ->
+ sameThreadDb.search("query", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build()));
+ assertThat(e).hasMessageThat().contains("SearchSession has already been closed");
+ } finally {
+ // To clean the data that has been added in the test, need to re-open the session and
+ // set an empty schema.
+ AppSearchSession reopen = createSearchSession(
+ "sameThreadDb", MoreExecutors.newDirectExecutorService()).get();
+ reopen.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+ }
+ }
+
+ @Test
+ public void testReportUsage() throws Exception {
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index two documents.
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1").build();
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2).build()));
+
+ // Email 1 has more usages, but email 2 has more recent usages.
+ mDb1.reportUsage(new ReportUsageRequest.Builder("namespace", "id1")
+ .setUsageTimestampMillis(1000).build()).get();
+ mDb1.reportUsage(new ReportUsageRequest.Builder("namespace", "id1")
+ .setUsageTimestampMillis(2000).build()).get();
+ mDb1.reportUsage(new ReportUsageRequest.Builder("namespace", "id1")
+ .setUsageTimestampMillis(3000).build()).get();
+ mDb1.reportUsage(new ReportUsageRequest.Builder("namespace", "id2")
+ .setUsageTimestampMillis(10000).build()).get();
+ mDb1.reportUsage(new ReportUsageRequest.Builder("namespace", "id2")
+ .setUsageTimestampMillis(20000).build()).get();
+
+ // Query by number of usages
+ List<SearchResult> results = retrieveAllSearchResults(
+ mDb1.search("", new SearchSpec.Builder()
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_USAGE_COUNT)
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build()));
+ // Email 1 has three usages and email 2 has two usages.
+ assertThat(results).hasSize(2);
+ assertThat(results.get(0).getGenericDocument()).isEqualTo(email1);
+ assertThat(results.get(1).getGenericDocument()).isEqualTo(email2);
+ assertThat(results.get(0).getRankingSignal()).isEqualTo(3);
+ assertThat(results.get(1).getRankingSignal()).isEqualTo(2);
+
+ // Query by most recent usage.
+ results = retrieveAllSearchResults(
+ mDb1.search("", new SearchSpec.Builder()
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP)
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build()));
+ assertThat(results).hasSize(2);
+ assertThat(results.get(0).getGenericDocument()).isEqualTo(email2);
+ assertThat(results.get(1).getGenericDocument()).isEqualTo(email1);
+ assertThat(results.get(0).getRankingSignal()).isEqualTo(20000);
+ assertThat(results.get(1).getRankingSignal()).isEqualTo(3000);
+ }
+
+ @Test
+ public void testReportUsage_invalidNamespace() throws Exception {
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+
+ // Use the correct namespace; it works
+ mDb1.reportUsage(new ReportUsageRequest.Builder("namespace", "id1").build()).get();
+
+ // Use an incorrect namespace; it fails
+ ExecutionException e = assertThrows(
+ ExecutionException.class,
+ () -> mDb1.reportUsage(
+ new ReportUsageRequest.Builder("namespace2", "id1").build()).get());
+ assertThat(e).hasCauseThat().isInstanceOf(AppSearchException.class);
+ AppSearchException cause = (AppSearchException) e.getCause();
+ assertThat(cause.getResultCode()).isEqualTo(RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testGetStorageInfo() throws Exception {
+ StorageInfo storageInfo = mDb1.getStorageInfo().get();
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0);
+
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Still no storage space attributed with just a schema
+ storageInfo = mDb1.getStorageInfo().get();
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0);
+
+ // Index two documents.
+ AppSearchEmail email1 = new AppSearchEmail.Builder("namespace1", "id1").build();
+ AppSearchEmail email2 = new AppSearchEmail.Builder("namespace1", "id2").build();
+ AppSearchEmail email3 = new AppSearchEmail.Builder("namespace2", "id1").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email1, email2,
+ email3).build()));
+
+ // Non-zero size now
+ storageInfo = mDb1.getStorageInfo().get();
+ assertThat(storageInfo.getSizeBytes()).isGreaterThan(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(3);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testFlush() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+
+ AppSearchBatchResult<String, Void> result = checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()));
+ assertThat(result.getSuccesses()).containsExactly("id1", null);
+ assertThat(result.getFailures()).isEmpty();
+
+ // The future returned from requestFlush will be set as a void or an Exception on error.
+ mDb1.requestFlush().get();
+ }
+
+ @Test
+ public void testQuery_ResultGroupingLimits() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index four documents.
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace1", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace1", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail2).build()));
+ AppSearchEmail inEmail3 =
+ new AppSearchEmail.Builder("namespace2", "id3")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail3).build()));
+ AppSearchEmail inEmail4 =
+ new AppSearchEmail.Builder("namespace2", "id4")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail4).build()));
+
+ // Query with per package result grouping. Only the last document 'email4' should be
+ // returned.
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultGrouping(SearchSpec.GROUPING_TYPE_PER_PACKAGE, /*resultLimit=*/ 1)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(inEmail4);
+
+ // Query with per namespace result grouping. Only the last document in each namespace should
+ // be returned ('email4' and 'email2').
+ searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultGrouping(
+ SearchSpec.GROUPING_TYPE_PER_NAMESPACE, /*resultLimit=*/ 1)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(inEmail4, inEmail2);
+
+ // Query with per package and per namespace result grouping. Only the last document in each
+ // namespace should be returned ('email4' and 'email2').
+ searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultGrouping(
+ SearchSpec.GROUPING_TYPE_PER_NAMESPACE
+ | SearchSpec.GROUPING_TYPE_PER_PACKAGE, /*resultLimit=*/ 1)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(inEmail4, inEmail2);
+ }
+
+ @Test
+ public void testIndexNestedDocuments() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .addSchemas(new AppSearchSchema.Builder("YesNestedIndex")
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
+ "prop", AppSearchEmail.SCHEMA_TYPE)
+ .setShouldIndexNestedProperties(true)
+ .build())
+ .build())
+ .addSchemas(new AppSearchSchema.Builder("NoNestedIndex")
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
+ "prop", AppSearchEmail.SCHEMA_TYPE)
+ .setShouldIndexNestedProperties(false)
+ .build())
+ .build())
+ .build())
+ .get();
+
+ // Index the documents.
+ AppSearchEmail email = new AppSearchEmail.Builder("", "")
+ .setSubject("This is the body")
+ .build();
+ GenericDocument yesNestedIndex =
+ new GenericDocument.Builder<>("namespace", "yesNestedIndex", "YesNestedIndex")
+ .setPropertyDocument("prop", email)
+ .build();
+ GenericDocument noNestedIndex =
+ new GenericDocument.Builder<>("namespace", "noNestedIndex", "NoNestedIndex")
+ .setPropertyDocument("prop", email)
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(new PutDocumentsRequest.Builder()
+ .addGenericDocuments(yesNestedIndex, noNestedIndex).build()));
+
+ // Query.
+ SearchResults searchResults = mDb1.search("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setSnippetCount(10)
+ .setSnippetCountPerProperty(10)
+ .build());
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(1);
+ assertThat(page.get(0).getGenericDocument()).isEqualTo(yesNestedIndex);
+ List<SearchResult.MatchInfo> matches = page.get(0).getMatchInfos();
+ assertThat(matches).hasSize(1);
+ assertThat(matches.get(0).getPropertyPath()).isEqualTo("prop.subject");
+ assertThat(matches.get(0).getFullText()).isEqualTo("This is the body");
+ assertThat(matches.get(0).getExactMatch()).isEqualTo("body");
+ }
+
+ @Test
+ public void testCJKTQuery() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document to instance 1.
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "uri1")
+ .setBody("他是個男孩 is a boy")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+
+ // Query for "他" (He)
+ SearchResults searchResults = mDb1.search("他", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build());
+ List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(inEmail1);
+
+ // Query for "男孩" (boy)
+ searchResults = mDb1.search("男孩", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(inEmail1);
+
+ // Query for "boy"
+ searchResults = mDb1.search("boy", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .build());
+ documents = convertSearchResultsToDocuments(searchResults);
+ assertThat(documents).containsExactly(inEmail1);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
new file mode 100644
index 0000000..0a05aeb
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.util.AppSearchTestUtils.convertSearchResultsToDocuments;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.util.AppSearchEmail;
+import androidx.appsearch.app.util.AppSearchTestUtils;
+import androidx.appsearch.localstorage.LocalStorage;
+import androidx.appsearch.localstorage.stats.SearchStats;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+public class AppSearchSessionLocalCtsTest extends AppSearchSessionCtsTestBase {
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, dbName).build());
+ }
+
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(
+ @NonNull String dbName, @NonNull ExecutorService executor) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, dbName)
+ .setWorkerExecutor(executor).build());
+ }
+
+ // TODO(b/194207451) Following test can be moved to CtsTestBase if customized logger is
+ // supported for platform backend.
+ @Test
+ public void testLogger_searchStatsLogged_forEmptyFirstPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger = new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ assertThat(logger.mSearchStats).isNull();
+
+ // Query for the document
+ int resultCountPerPage = 4;
+ String queryStr = "bodies";
+ SearchResults searchResults = db2.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(0);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isEqualTo(DB_NAME_2);
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(queryStr.length());
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(true);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_LOCAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(resultCountPerPage);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(
+ 0);
+ }
+
+ @Test
+ public void testLogger_searchStatsLogged_forNonEmptyFirstPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger = new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ assertThat(logger.mSearchStats).isNull();
+
+ // Query for the document
+ int resultCountPerPage = 4;
+ String queryStr = "body";
+ SearchResults searchResults = db2.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(2);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isEqualTo(DB_NAME_2);
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(queryStr.length());
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(true);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_LOCAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(resultCountPerPage);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(
+ 2);
+ }
+
+ @Test
+ public void testLogger_searchStatsLogged_forEmptySecondPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger = new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ // Query for the document
+ int resultCountPerPage = 2;
+ String queryStr = "body";
+ SearchResults searchResults = db2.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ // include all documents in the 1st page
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(2);
+
+ // Get second(empty) page
+ logger.mSearchStats = null;
+ page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(0);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isEqualTo(DB_NAME_2);
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ // Query length is 0 for getNextPage in IcingLib
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(0);
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(false);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_LOCAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(0);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testLogger_searchStatsLogged_forNonEmptySecondPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger = new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ // Query for the document
+ int resultCountPerPage = 1;
+ String queryStr = "body";
+ SearchResults searchResults = db2.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ // only include one result in a page
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(1);
+
+ // Get second page
+ logger.mSearchStats = null;
+ page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(1);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isEqualTo(DB_NAME_2);
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ // Query length is 0 for getNextPage in IcingLib
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(0);
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(false);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_LOCAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(resultCountPerPage);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(1);
+ }
+
+ // TODO(b/185441119) Following test can be moved to CtsTestBase if we fix the binder
+ // transaction limit in framework.
+ @Test
+ public void testPutLargeDocument() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchTestUtils.TestLogger logger = new AppSearchTestUtils.TestLogger();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ char[] chars = new char[16_000_000];
+ Arrays.fill(chars, ' ');
+ String body = String.valueOf(chars) + "the end.";
+
+ // Index a document
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody(body)
+ .build();
+ AppSearchBatchResult<String, Void> result = db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()).get();
+ assertThat(result.isSuccess()).isTrue();
+
+ SearchResults searchResults = db2.search("end", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ List<GenericDocument> outDocuments = convertSearchResultsToDocuments(searchResults);
+ assertThat(outDocuments).hasSize(1);
+ AppSearchEmail outEmail = new AppSearchEmail(outDocuments.get(0));
+ assertThat(outEmail).isEqualTo(email);
+ }
+
+ // TODO(b/185441119) Following test can be moved to CtsTestBase if we fix the binder
+ // transaction limit in framework.
+ @Test
+ public void testPutLargeDocument_exceedLimit() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchTestUtils.TestLogger logger = new AppSearchTestUtils.TestLogger();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Create a String property that make the document exceed the total size limit.
+ char[] chars = new char[17_000_000];
+ String body = new StringBuilder().append(chars).toString();
+
+ // Index a document
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody(body)
+ .build();
+ AppSearchBatchResult<String, Void> result = db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()).get();
+ assertThat(result.getFailures()).containsKey("id1");
+ assertThat(result.getFailures().get("id1").getErrorMessage())
+ .contains("was too large to write. Max is 16777215");
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionPlatformCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionPlatformCtsTest.java
new file mode 100644
index 0000000..f467c77
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionPlatformCtsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.cts.app;
+
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.platformstorage.PlatformStorage;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.ExecutorService;
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+public class AppSearchSessionPlatformCtsTest extends AppSearchSessionCtsTestBase {
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return PlatformStorage.createSearchSession(
+ new PlatformStorage.SearchContext.Builder(context, dbName).build());
+ }
+
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(
+ @NonNull String dbName, @NonNull ExecutorService executor) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return PlatformStorage.createSearchSession(
+ new PlatformStorage.SearchContext.Builder(context, dbName)
+ .setWorkerExecutor(executor).build());
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GenericDocumentCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GenericDocumentCtsTest.java
new file mode 100644
index 0000000..ce25fef
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GenericDocumentCtsTest.java
@@ -0,0 +1,854 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.appsearch.app.GenericDocument;
+
+import org.junit.Test;
+
+public class GenericDocumentCtsTest {
+ private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
+ private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6, (byte) 7};
+ private static final GenericDocument sDocumentProperties1 = new GenericDocument
+ .Builder<>("namespace", "sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+ .setCreationTimestampMillis(12345L)
+ .build();
+ private static final GenericDocument sDocumentProperties2 = new GenericDocument
+ .Builder<>("namespace", "sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+ .setCreationTimestampMillis(6789L)
+ .build();
+
+ @Test
+ public void testMaxIndexedProperties() {
+ assertThat(GenericDocument.getMaxIndexedProperties()).isEqualTo(16);
+ }
+
+ @Test
+ public void testDocumentEquals_identical() {
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setTtlMillis(1L)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
+ .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
+ .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setTtlMillis(1L)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
+ .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
+ .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .build();
+ assertThat(document1).isEqualTo(document2);
+ assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
+ }
+
+ @Test
+ public void testDocumentEquals_differentOrder() {
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
+ .build();
+
+ // Create second document with same parameter but different order.
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .build();
+ assertThat(document1).isEqualTo(document2);
+ assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
+ }
+
+ @Test
+ public void testDocumentEquals_failure() {
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .build();
+
+ // Create second document with same order but different value.
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyLong("longKey1", 1L, 2L, 4L) // Different
+ .build();
+ assertThat(document1).isNotEqualTo(document2);
+ assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
+ }
+
+ @Test
+ public void testDocumentEquals_repeatedFieldOrder_failure() {
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .build();
+
+ // Create second document with same order but different value.
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyBoolean("booleanKey1", true, true, false) // Different
+ .build();
+ assertThat(document1).isNotEqualTo(document2);
+ assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
+ }
+
+ @Test
+ public void testDocumentGetSingleValue() {
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setScore(1)
+ .setTtlMillis(1L)
+ .setPropertyLong("longKey1", 1L)
+ .setPropertyDouble("doubleKey1", 1.0)
+ .setPropertyBoolean("booleanKey1", true)
+ .setPropertyString("stringKey1", "test-value1")
+ .setPropertyBytes("byteKey1", sByteArray1)
+ .setPropertyDocument("documentKey1", sDocumentProperties1)
+ .build();
+ assertThat(document.getId()).isEqualTo("id1");
+ assertThat(document.getTtlMillis()).isEqualTo(1L);
+ assertThat(document.getSchemaType()).isEqualTo("schemaType1");
+ assertThat(document.getCreationTimestampMillis()).isEqualTo(5);
+ assertThat(document.getScore()).isEqualTo(1);
+ assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
+ assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(1.0);
+ assertThat(document.getPropertyBoolean("booleanKey1")).isTrue();
+ assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
+ assertThat(document.getPropertyBytes("byteKey1"))
+ .asList().containsExactly((byte) 1, (byte) 2, (byte) 3).inOrder();
+ assertThat(document.getPropertyDocument("documentKey1")).isEqualTo(sDocumentProperties1);
+
+ assertThat(document.getProperty("longKey1")).isInstanceOf(long[].class);
+ assertThat((long[]) document.getProperty("longKey1")).asList().containsExactly(1L);
+ assertThat(document.getProperty("doubleKey1")).isInstanceOf(double[].class);
+ assertThat((double[]) document.getProperty("doubleKey1")).usingTolerance(
+ 0.05).containsExactly(1.0);
+ assertThat(document.getProperty("booleanKey1")).isInstanceOf(boolean[].class);
+ assertThat((boolean[]) document.getProperty("booleanKey1")).asList().containsExactly(true);
+ assertThat(document.getProperty("stringKey1")).isInstanceOf(String[].class);
+ assertThat((String[]) document.getProperty("stringKey1")).asList().containsExactly(
+ "test-value1");
+ assertThat(document.getProperty("byteKey1")).isInstanceOf(byte[][].class);
+ assertThat((byte[][]) document.getProperty("byteKey1")).asList().containsExactly(
+ sByteArray1).inOrder();
+ assertThat(document.getProperty("documentKey1")).isInstanceOf(GenericDocument[].class);
+ assertThat(
+ (GenericDocument[]) document.getProperty("documentKey1")).asList().containsExactly(
+ sDocumentProperties1);
+ }
+
+ @Test
+ public void testDocumentGetArrayValues() {
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
+ .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
+ .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .build();
+
+ assertThat(document.getId()).isEqualTo("id1");
+ assertThat(document.getSchemaType()).isEqualTo("schemaType1");
+ assertThat(document.getPropertyLongArray("longKey1")).asList()
+ .containsExactly(1L, 2L, 3L).inOrder();
+ assertThat(document.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
+ .containsExactly(1.0, 2.0, 3.0).inOrder();
+ assertThat(document.getPropertyBooleanArray("booleanKey1")).asList()
+ .containsExactly(true, false, true).inOrder();
+ assertThat(document.getPropertyStringArray("stringKey1")).asList()
+ .containsExactly("test-value1", "test-value2", "test-value3").inOrder();
+ assertThat(document.getPropertyBytesArray("byteKey1")).asList()
+ .containsExactly(sByteArray1, sByteArray2).inOrder();
+ assertThat(document.getPropertyDocumentArray("documentKey1")).asList()
+ .containsExactly(sDocumentProperties1, sDocumentProperties2).inOrder();
+ }
+
+ @Test
+ public void testDocument_toString() {
+ GenericDocument nestedDocValue = new GenericDocument.Builder<GenericDocument.Builder<?>>(
+ "namespace", "id2", "schemaType2")
+ .setCreationTimestampMillis(1L)
+ .setScore(1)
+ .setTtlMillis(1L)
+ .setPropertyString("stringKey1", "val1", "val2")
+ .build();
+ GenericDocument document =
+ new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace", "id1",
+ "schemaType1")
+ .setCreationTimestampMillis(1L)
+ .setScore(1)
+ .setTtlMillis(1L)
+ .setPropertyString("stringKey1", "val1", "val2")
+ .setPropertyBytes("bytesKey1", new byte[]{(byte) 1, (byte) 2})
+ .setPropertyLong("longKey1", 1L, 2L)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0)
+ .setPropertyBoolean("booleanKey1", true, false)
+ .setPropertyDocument("documentKey1", nestedDocValue)
+ .build();
+
+ String documentString = document.toString();
+
+ String expectedString = "{\n"
+ + " namespace: \"namespace\",\n"
+ + " id: \"id1\",\n"
+ + " score: 1,\n"
+ + " schemaType: \"schemaType1\",\n"
+ + " creationTimestampMillis: 1,\n"
+ + " timeToLiveMillis: 1,\n"
+ + " properties: {\n"
+ + " \"booleanKey1\": [true, false],\n"
+ + " \"bytesKey1\": [[1, 2]],\n"
+ + " \"documentKey1\": [\n"
+ + " {\n"
+ + " namespace: \"namespace\",\n"
+ + " id: \"id2\",\n"
+ + " score: 1,\n"
+ + " schemaType: \"schemaType2\",\n"
+ + " creationTimestampMillis: 1,\n"
+ + " timeToLiveMillis: 1,\n"
+ + " properties: {\n"
+ + " \"stringKey1\": [\"val1\", \"val2\"]\n"
+ + " }\n"
+ + " }\n"
+ + " ],\n"
+ + " \"doubleKey1\": [1.0, 2.0],\n"
+ + " \"longKey1\": [1, 2],\n"
+ + " \"stringKey1\": [\"val1\", \"val2\"]\n"
+ + " }\n"
+ + "}";
+
+ assertThat(documentString).isEqualTo(expectedString);
+ }
+
+ @Test
+ public void testDocumentGetValues_differentTypes() {
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+ .setScore(1)
+ .setPropertyLong("longKey1", 1L)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
+ .build();
+
+ // Get a value for a key that doesn't exist
+ assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(0.0);
+ assertThat(document.getPropertyDoubleArray("doubleKey1")).isNull();
+
+ // Get a value with a single element as an array and as a single value
+ assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
+ assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L);
+
+ // Get a value with multiple elements as an array and as a single value
+ assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
+ assertThat(document.getPropertyStringArray("stringKey1")).asList()
+ .containsExactly("test-value1", "test-value2", "test-value3").inOrder();
+
+ // Get a value of the wrong type
+ assertThat(document.getPropertyDouble("longKey1")).isEqualTo(0.0);
+ assertThat(document.getPropertyDoubleArray("longKey1")).isNull();
+ }
+
+ @Test
+ public void testDocument_setEmptyValues() {
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+ .setPropertyBoolean("testKey")
+ .build();
+ assertThat(document.getPropertyBooleanArray("testKey")).isEmpty();
+ }
+
+ @Test
+ public void testDocumentInvalid() {
+ GenericDocument.Builder<?> builder = new GenericDocument.Builder<>("namespace", "id1",
+ "schemaType1");
+ String nullString = null;
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> builder.setPropertyString("testKey", "string1", nullString));
+ }
+
+// @exportToFramework:startStrip()
+
+ // TODO(b/171882200): Expose this test in Android T
+ @Test
+ public void testDocument_toBuilder() {
+ GenericDocument document1 = new GenericDocument.Builder<>(
+ /*namespace=*/"", "id1", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyString("stringKey1", "String1", "String2", "String3")
+ .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
+ .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .build();
+ GenericDocument document2 = document1.toBuilder()
+ .setId("id2")
+ .setNamespace("namespace2")
+ .setPropertyBytes("byteKey1", sByteArray2)
+ .setPropertyLong("longKey2", 10L)
+ .clearProperty("booleanKey1")
+ .build();
+
+ // Make sure old doc hasn't changed
+ assertThat(document1.getId()).isEqualTo("id1");
+ assertThat(document1.getNamespace()).isEqualTo("");
+ assertThat(document1.getPropertyLongArray("longKey1")).asList()
+ .containsExactly(1L, 2L, 3L).inOrder();
+ assertThat(document1.getPropertyBooleanArray("booleanKey1")).asList()
+ .containsExactly(true, false, true).inOrder();
+ assertThat(document1.getPropertyLongArray("longKey2")).isNull();
+
+ // Make sure the new doc contains the expected values
+ GenericDocument expectedDoc = new GenericDocument.Builder<>(
+ "namespace2", "id2", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .setPropertyLong("longKey2", 10L)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyString("stringKey1", "String1", "String2", "String3")
+ .setPropertyBytes("byteKey1", sByteArray2)
+ .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .build();
+ assertThat(document2).isEqualTo(expectedDoc);
+ }
+
+// @exportToFramework:endStrip()
+
+ @Test
+ public void testRetrieveTopLevelProperties() {
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+
+ // Top-level repeated properties should be retrievable
+ assertThat(doc.getPropertyStringArray("propString")).asList()
+ .containsExactly("Goodbye", "Hello").inOrder();
+ assertThat(doc.getPropertyLongArray("propInts")).asList()
+ .containsExactly(3L, 1L, 4L).inOrder();
+ assertThat(doc.getPropertyDoubleArray("propDoubles")).usingTolerance(0.0001)
+ .containsExactly(3.14, 0.42).inOrder();
+ assertThat(doc.getPropertyBooleanArray("propBools")).asList().containsExactly(false);
+ assertThat(doc.getPropertyBytesArray("propBytes")).isEqualTo(new byte[][]{{3, 4}});
+
+ // Top-level repeated properties should retrieve the first element
+ assertThat(doc.getPropertyString("propString")).isEqualTo("Goodbye");
+ assertThat(doc.getPropertyLong("propInts")).isEqualTo(3);
+ assertThat(doc.getPropertyDouble("propDoubles")).isWithin(0.0001)
+ .of(3.14);
+ assertThat(doc.getPropertyBoolean("propBools")).isFalse();
+ assertThat(doc.getPropertyBytes("propBytes")).isEqualTo(new byte[]{3, 4});
+ }
+
+ @Test
+ public void testRetrieveNestedProperties() {
+ GenericDocument innerDoc = new GenericDocument.Builder<>("namespace", "id2", "schema2")
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyDocument("propDocument", innerDoc)
+ .build();
+
+ // Document should be retrievable via both array and single getters
+ assertThat(doc.getPropertyDocument("propDocument")).isEqualTo(innerDoc);
+ assertThat(doc.getPropertyDocumentArray("propDocument")).asList()
+ .containsExactly(innerDoc);
+ assertThat((GenericDocument[]) doc.getProperty("propDocument")).asList()
+ .containsExactly(innerDoc);
+
+ // Nested repeated properties should be retrievable
+ assertThat(doc.getPropertyStringArray("propDocument.propString")).asList()
+ .containsExactly("Goodbye", "Hello").inOrder();
+ assertThat(doc.getPropertyLongArray("propDocument.propInts")).asList()
+ .containsExactly(3L, 1L, 4L).inOrder();
+ assertThat(doc.getPropertyDoubleArray("propDocument.propDoubles")).usingTolerance(0.0001)
+ .containsExactly(3.14, 0.42).inOrder();
+ assertThat(doc.getPropertyBooleanArray("propDocument.propBools")).asList()
+ .containsExactly(false);
+ assertThat(doc.getPropertyBytesArray("propDocument.propBytes")).isEqualTo(
+ new byte[][]{{3, 4}});
+ assertThat(doc.getProperty("propDocument.propBytes")).isEqualTo(
+ new byte[][]{{3, 4}});
+
+ // Nested properties should retrieve the first element
+ assertThat(doc.getPropertyString("propDocument.propString"))
+ .isEqualTo("Goodbye");
+ assertThat(doc.getPropertyLong("propDocument.propInts")).isEqualTo(3);
+ assertThat(doc.getPropertyDouble("propDocument.propDoubles")).isWithin(0.0001)
+ .of(3.14);
+ assertThat(doc.getPropertyBoolean("propDocument.propBools")).isFalse();
+ assertThat(doc.getPropertyBytes("propDocument.propBytes")).isEqualTo(new byte[]{3, 4});
+ }
+
+ @Test
+ public void testRetrieveNestedPropertiesMultipleNestedDocuments() {
+ GenericDocument innerDoc0 = new GenericDocument.Builder<>("namespace", "id2", "schema2")
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyString("propStringTwo", "Fee", "Fi")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+ GenericDocument innerDoc1 = new GenericDocument.Builder<>("namespace", "id3", "schema2")
+ .setPropertyString("propString", "Aloha")
+ .setPropertyLong("propInts", 7, 5, 6)
+ .setPropertyLong("propIntsTwo", 8, 6)
+ .setPropertyDouble("propDoubles", 7.14, 0.356)
+ .setPropertyBoolean("propBools", true)
+ .setPropertyBytes("propBytes", new byte[][]{{8, 9}})
+ .build();
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyDocument("propDocument", innerDoc0, innerDoc1)
+ .build();
+
+ // Documents should be retrievable via both array and single getters
+ assertThat(doc.getPropertyDocument("propDocument")).isEqualTo(innerDoc0);
+ assertThat(doc.getPropertyDocumentArray("propDocument")).asList()
+ .containsExactly(innerDoc0, innerDoc1).inOrder();
+ assertThat((GenericDocument[]) doc.getProperty("propDocument")).asList()
+ .containsExactly(innerDoc0, innerDoc1).inOrder();
+
+ // Nested repeated properties should be retrievable and should merge the arrays from the
+ // inner documents.
+ assertThat(doc.getPropertyStringArray("propDocument.propString")).asList()
+ .containsExactly("Goodbye", "Hello", "Aloha").inOrder();
+ assertThat(doc.getPropertyLongArray("propDocument.propInts")).asList()
+ .containsExactly(3L, 1L, 4L, 7L, 5L, 6L).inOrder();
+ assertThat(doc.getPropertyDoubleArray("propDocument.propDoubles")).usingTolerance(0.0001)
+ .containsExactly(3.14, 0.42, 7.14, 0.356).inOrder();
+ assertThat(doc.getPropertyBooleanArray("propDocument.propBools")).asList()
+ .containsExactly(false, true).inOrder();
+ assertThat(doc.getPropertyBytesArray("propDocument.propBytes")).isEqualTo(
+ new byte[][]{{3, 4}, {8, 9}});
+ assertThat(doc.getProperty("propDocument.propBytes")).isEqualTo(
+ new byte[][]{{3, 4}, {8, 9}});
+
+ // Nested repeated properties should properly handle properties appearing in only one inner
+ // document, but not the other.
+ assertThat(
+ doc.getPropertyStringArray("propDocument.propStringTwo")).asList()
+ .containsExactly("Fee", "Fi").inOrder();
+ assertThat(doc.getPropertyLongArray("propDocument.propIntsTwo")).asList()
+ .containsExactly(8L, 6L).inOrder();
+
+ // Nested properties should retrieve the first element
+ assertThat(doc.getPropertyString("propDocument.propString"))
+ .isEqualTo("Goodbye");
+ assertThat(doc.getPropertyString("propDocument.propStringTwo"))
+ .isEqualTo("Fee");
+ assertThat(doc.getPropertyLong("propDocument.propInts")).isEqualTo(3);
+ assertThat(doc.getPropertyLong("propDocument.propIntsTwo")).isEqualTo(8L);
+ assertThat(doc.getPropertyDouble("propDocument.propDoubles")).isWithin(0.0001)
+ .of(3.14);
+ assertThat(doc.getPropertyBoolean("propDocument.propBools")).isFalse();
+ assertThat(doc.getPropertyBytes("propDocument.propBytes")).isEqualTo(new byte[]{3, 4});
+ }
+
+ @Test
+ public void testRetrieveTopLevelPropertiesIndex() {
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+
+ // Top-level repeated properties should be retrievable
+ assertThat(doc.getPropertyStringArray("propString[1]")).asList()
+ .containsExactly("Hello");
+ assertThat(doc.getPropertyLongArray("propInts[2]")).asList()
+ .containsExactly(4L);
+ assertThat(doc.getPropertyDoubleArray("propDoubles[0]")).usingTolerance(0.0001)
+ .containsExactly(3.14);
+ assertThat(doc.getPropertyBooleanArray("propBools[0]")).asList().containsExactly(false);
+ assertThat(doc.getPropertyBytesArray("propBytes[0]")).isEqualTo(new byte[][]{{3, 4}});
+ assertThat(doc.getProperty("propBytes[0]")).isEqualTo(new byte[][]{{3, 4}});
+
+ // Top-level repeated properties should retrieve the first element
+ assertThat(doc.getPropertyString("propString[1]")).isEqualTo("Hello");
+ assertThat(doc.getPropertyLong("propInts[2]")).isEqualTo(4L);
+ assertThat(doc.getPropertyDouble("propDoubles[0]")).isWithin(0.0001)
+ .of(3.14);
+ assertThat(doc.getPropertyBoolean("propBools[0]")).isFalse();
+ assertThat(doc.getPropertyBytes("propBytes[0]")).isEqualTo(new byte[]{3, 4});
+ }
+
+ @Test
+ public void testRetrieveTopLevelPropertiesIndexOutOfRange() {
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+
+ // Array getters should return null when given a bad index.
+ assertThat(doc.getPropertyStringArray("propString[5]")).isNull();
+
+ // Single getters should return default when given a bad index.
+ assertThat(doc.getPropertyDouble("propDoubles[7]")).isEqualTo(0.0);
+ }
+
+ @Test
+ public void testNestedProperties_unusualPaths() {
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setPropertyString("propString", "Hello", "Goodbye")
+ .setPropertyDocument("propDocs1", new GenericDocument.Builder<>("", "", "schema1")
+ .setPropertyString("", "Cat", "Dog")
+ .build())
+ .setPropertyDocument("propDocs2", new GenericDocument.Builder<>("", "", "schema1")
+ .setPropertyDocument("", new GenericDocument.Builder<>("", "", "schema1")
+ .setPropertyString("", "Red", "Blue")
+ .setPropertyString("propString", "Bat", "Hawk")
+ .build())
+ .build())
+ .setPropertyDocument("", new GenericDocument.Builder<>("", "", "schema1")
+ .setPropertyDocument("", new GenericDocument.Builder<>("", "", "schema1")
+ .setPropertyString("", "Orange", "Green")
+ .setPropertyString("propString", "Toad", "Bird")
+ .build())
+ .build())
+ .build();
+ assertThat(doc.getPropertyString("propString")).isEqualTo("Hello");
+ assertThat(doc.getPropertyString("propString[1]")).isEqualTo("Goodbye");
+ assertThat(doc.getPropertyString("propDocs1.")).isEqualTo("Cat");
+ assertThat(doc.getPropertyString("propDocs1.[1]")).isEqualTo("Dog");
+ assertThat(doc.getPropertyStringArray("propDocs1[0].")).asList()
+ .containsExactly("Cat", "Dog").inOrder();
+ assertThat(doc.getPropertyString("propDocs2..propString")).isEqualTo("Bat");
+ assertThat(doc.getPropertyString("propDocs2..propString[1]")).isEqualTo("Hawk");
+ assertThat(doc.getPropertyString("propDocs2..")).isEqualTo("Red");
+ assertThat(doc.getPropertyString("propDocs2..[1]")).isEqualTo("Blue");
+ assertThat(doc.getPropertyString("[0]..propString[1]")).isEqualTo("Bird");
+ assertThat(doc.getPropertyString("[0]..[1]")).isEqualTo("Green");
+ }
+
+ @Test
+ public void testNestedProperties_invalidPaths() {
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .setPropertyDocument("propDocs", new GenericDocument.Builder<>("", "", "schema1")
+ .setPropertyString("", "Cat")
+ .build())
+ .build();
+
+ // Some paths are invalid because they don't apply to the given document --- these should
+ // return null. It's not the querier's fault.
+ assertThat(doc.getPropertyStringArray("propString.propInts")).isNull();
+ assertThat(doc.getPropertyStringArray("propDocs.propFoo")).isNull();
+ assertThat(doc.getPropertyStringArray("propDocs.propNestedString.propFoo")).isNull();
+
+ // Some paths are invalid because they are malformed. These throw an exception --- the
+ // querier shouldn't provide such paths.
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> doc.getPropertyStringArray("propDocs.[0]propInts"));
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> doc.getPropertyStringArray("propString[0"));
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> doc.getPropertyStringArray("propString[0.]"));
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> doc.getPropertyStringArray("propString[banana]"));
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> doc.getPropertyStringArray("propString[-1]"));
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> doc.getPropertyStringArray("propDocs[0]cat"));
+ }
+
+ @Test
+ public void testRetrieveNestedPropertiesIntermediateIndex() {
+ GenericDocument innerDoc0 = new GenericDocument.Builder<>("namespace", "id2", "schema2")
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyString("propStringTwo", "Fee", "Fi")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+ GenericDocument innerDoc1 = new GenericDocument.Builder<>("namespace", "id3", "schema2")
+ .setPropertyString("propString", "Aloha")
+ .setPropertyLong("propInts", 7, 5, 6)
+ .setPropertyLong("propIntsTwo", 8, 6)
+ .setPropertyDouble("propDoubles", 7.14, 0.356)
+ .setPropertyBoolean("propBools", true)
+ .setPropertyBytes("propBytes", new byte[][]{{8, 9}})
+ .build();
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyDocument("propDocument", innerDoc0, innerDoc1)
+ .build();
+
+ // Documents should be retrievable via both array and single getters
+ assertThat(doc.getPropertyDocument("propDocument[1]")).isEqualTo(innerDoc1);
+ assertThat(doc.getPropertyDocumentArray("propDocument[1]")).asList()
+ .containsExactly(innerDoc1);
+ assertThat((GenericDocument[]) doc.getProperty("propDocument[1]")).asList()
+ .containsExactly(innerDoc1);
+
+ // Nested repeated properties should be retrievable and should merge the arrays from the
+ // inner documents.
+ assertThat(doc.getPropertyStringArray("propDocument[1].propString")).asList()
+ .containsExactly("Aloha");
+ assertThat(doc.getPropertyLongArray("propDocument[0].propInts")).asList()
+ .containsExactly(3L, 1L, 4L).inOrder();
+ assertThat(doc.getPropertyDoubleArray("propDocument[1].propDoubles")).usingTolerance(0.0001)
+ .containsExactly(7.14, 0.356).inOrder();
+ assertThat(doc.getPropertyBooleanArray("propDocument[0].propBools")).asList()
+ .containsExactly(false);
+ assertThat((boolean[]) doc.getProperty("propDocument[0].propBools")).asList()
+ .containsExactly(false);
+ assertThat(doc.getPropertyBytesArray("propDocument[1].propBytes")).isEqualTo(
+ new byte[][]{{8, 9}});
+
+ // Nested repeated properties should properly handle properties appearing in only one inner
+ // document, but not the other.
+ assertThat(doc.getPropertyStringArray("propDocument[0].propStringTwo")).asList()
+ .containsExactly("Fee", "Fi").inOrder();
+ assertThat(doc.getPropertyStringArray("propDocument[1].propStringTwo")).isNull();
+ assertThat(doc.getPropertyLongArray("propDocument[0].propIntsTwo")).isNull();
+ assertThat(doc.getPropertyLongArray("propDocument[1].propIntsTwo")).asList()
+ .containsExactly(8L, 6L).inOrder();
+
+ // Nested properties should retrieve the first element
+ assertThat(doc.getPropertyString("propDocument[1].propString"))
+ .isEqualTo("Aloha");
+ assertThat(doc.getPropertyString("propDocument[0].propStringTwo"))
+ .isEqualTo("Fee");
+ assertThat(doc.getPropertyLong("propDocument[1].propInts")).isEqualTo(7L);
+ assertThat(doc.getPropertyLong("propDocument[1].propIntsTwo")).isEqualTo(8L);
+ assertThat(doc.getPropertyDouble("propDocument[0].propDoubles"))
+ .isWithin(0.0001).of(3.14);
+ assertThat(doc.getPropertyBoolean("propDocument[1].propBools")).isTrue();
+ assertThat(doc.getPropertyBytes("propDocument[0].propBytes"))
+ .isEqualTo(new byte[]{3, 4});
+ }
+
+ @Test
+ public void testRetrieveNestedPropertiesLeafIndex() {
+ GenericDocument innerDoc0 = new GenericDocument.Builder<>("namespace", "id2", "schema2")
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyString("propStringTwo", "Fee", "Fi")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+ GenericDocument innerDoc1 = new GenericDocument.Builder<>("namespace", "id3", "schema2")
+ .setPropertyString("propString", "Aloha")
+ .setPropertyLong("propInts", 7, 5, 6)
+ .setPropertyLong("propIntsTwo", 8, 6)
+ .setPropertyDouble("propDoubles", 7.14, 0.356)
+ .setPropertyBoolean("propBools", true)
+ .setPropertyBytes("propBytes", new byte[][]{{8, 9}})
+ .build();
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyDocument("propDocument", innerDoc0, innerDoc1)
+ .build();
+
+ // Nested repeated properties should be retrievable and should merge the arrays from the
+ // inner documents.
+ assertThat(doc.getPropertyStringArray("propDocument.propString[0]")).asList()
+ .containsExactly("Goodbye", "Aloha").inOrder();
+ assertThat(doc.getPropertyLongArray("propDocument.propInts[2]")).asList()
+ .containsExactly(4L, 6L).inOrder();
+ assertThat(doc.getPropertyDoubleArray("propDocument.propDoubles[1]"))
+ .usingTolerance(0.0001).containsExactly(0.42, 0.356).inOrder();
+ assertThat((double[]) doc.getProperty("propDocument.propDoubles[1]"))
+ .usingTolerance(0.0001).containsExactly(0.42, 0.356).inOrder();
+ assertThat(doc.getPropertyBooleanArray("propDocument.propBools[0]")).asList()
+ .containsExactly(false, true).inOrder();
+ assertThat(doc.getPropertyBytesArray("propDocument.propBytes[0]"))
+ .isEqualTo(new byte[][]{{3, 4}, {8, 9}});
+
+ // Nested repeated properties should properly handle properties appearing in only one inner
+ // document, but not the other.
+ assertThat(doc.getPropertyStringArray("propDocument.propStringTwo[0]")).asList()
+ .containsExactly("Fee");
+ assertThat((String[]) doc.getProperty("propDocument.propStringTwo[0]")).asList()
+ .containsExactly("Fee");
+ assertThat(doc.getPropertyLongArray("propDocument.propIntsTwo[1]")).asList()
+ .containsExactly(6L);
+
+ // Nested properties should retrieve the first element
+ assertThat(doc.getPropertyString("propDocument.propString[1]"))
+ .isEqualTo("Hello");
+ assertThat(doc.getPropertyString("propDocument.propStringTwo[1]"))
+ .isEqualTo("Fi");
+ assertThat(doc.getPropertyLong("propDocument.propInts[1]"))
+ .isEqualTo(1L);
+ assertThat(doc.getPropertyLong("propDocument.propIntsTwo[1]")).isEqualTo(6L);
+ assertThat(doc.getPropertyDouble("propDocument.propDoubles[1]"))
+ .isWithin(0.0001).of(0.42);
+ assertThat(doc.getPropertyBoolean("propDocument.propBools[0]")).isFalse();
+ assertThat(doc.getPropertyBytes("propDocument.propBytes[0]"))
+ .isEqualTo(new byte[]{3, 4});
+ }
+
+ @Test
+ public void testRetrieveNestedPropertiesIntermediateAndLeafIndices() {
+ GenericDocument innerDoc0 = new GenericDocument.Builder<>("namespace", "id2", "schema2")
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyString("propStringTwo", "Fee", "Fi")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .setPropertyDouble("propDoubles", 3.14, 0.42)
+ .setPropertyBoolean("propBools", false)
+ .setPropertyBytes("propBytes", new byte[][]{{3, 4}})
+ .build();
+ GenericDocument innerDoc1 = new GenericDocument.Builder<>("namespace", "id3", "schema2")
+ .setPropertyString("propString", "Aloha")
+ .setPropertyLong("propInts", 7, 5, 6)
+ .setPropertyLong("propIntsTwo", 8, 6)
+ .setPropertyDouble("propDoubles", 7.14, 0.356)
+ .setPropertyBoolean("propBools", true)
+ .setPropertyBytes("propBytes", new byte[][]{{8, 9}})
+ .build();
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setScore(42)
+ .setPropertyDocument("propDocument", innerDoc0, innerDoc1)
+ .build();
+
+ // Nested repeated properties should be retrievable and should merge the arrays from the
+ // inner documents.
+ assertThat(doc.getPropertyStringArray("propDocument[1].propString[0]")).asList()
+ .containsExactly("Aloha");
+ assertThat(doc.getPropertyLongArray("propDocument[0].propInts[2]")).asList()
+ .containsExactly(4L);
+ assertThat((long[]) doc.getProperty("propDocument[0].propInts[2]")).asList()
+ .containsExactly(4L);
+ assertThat(doc.getPropertyDoubleArray("propDocument[1].propDoubles[1]"))
+ .usingTolerance(0.0001).containsExactly(0.356);
+ assertThat(doc.getPropertyBooleanArray("propDocument[0].propBools[0]")).asList()
+ .containsExactly(false);
+ assertThat(doc.getPropertyBytesArray("propDocument[1].propBytes[0]"))
+ .isEqualTo(new byte[][]{{8, 9}});
+
+ // Nested properties should retrieve the first element
+ assertThat(doc.getPropertyString("propDocument[0].propString[1]"))
+ .isEqualTo("Hello");
+ assertThat(doc.getPropertyString("propDocument[0].propStringTwo[1]"))
+ .isEqualTo("Fi");
+ assertThat(doc.getPropertyLong("propDocument[1].propInts[1]"))
+ .isEqualTo(5L);
+ assertThat(doc.getPropertyLong("propDocument[1].propIntsTwo[1]"))
+ .isEqualTo(6L);
+ assertThat(doc.getPropertyDouble("propDocument[0].propDoubles[1]"))
+ .isWithin(0.0001).of(0.42);
+ assertThat(doc.getPropertyBoolean("propDocument[1].propBools[0]")).isTrue();
+ assertThat(doc.getPropertyBytes("propDocument[0].propBytes[0]"))
+ .isEqualTo(new byte[]{3, 4});
+ }
+
+ @Test
+ public void testDocumentGetPropertyNamesSingleLevel() {
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setScore(1)
+ .setTtlMillis(1L)
+ .setPropertyLong("longKey1", 1L)
+ .setPropertyDouble("doubleKey1", 1.0)
+ .setPropertyBoolean("booleanKey1", true)
+ .setPropertyString("stringKey1", "test-value1")
+ .setPropertyBytes("byteKey1", sByteArray1)
+ .build();
+ assertThat(document.getPropertyNames()).containsExactly("longKey1", "doubleKey1",
+ "booleanKey1", "stringKey1", "byteKey1");
+ }
+
+ @Test
+ public void testDocumentGetPropertyNamesMultiLevel() {
+ GenericDocument innerDoc0 = new GenericDocument.Builder<>("namespace", "id2", "schema2")
+ .setPropertyString("propString", "Goodbye", "Hello")
+ .setPropertyString("propStringTwo", "Fee", "Fi")
+ .setPropertyLong("propInts", 3, 1, 4)
+ .build();
+ GenericDocument innerDoc1 = new GenericDocument.Builder<>("namespace", "id3", "schema2")
+ .setPropertyString("propString", "Aloha")
+ .setPropertyLong("propInts", 7, 5, 6)
+ .setPropertyLong("propIntsTwo", 8, 6)
+ .build();
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setScore(1)
+ .setTtlMillis(1L)
+ .setPropertyString("stringKey1", "test-value1")
+ .setPropertyDocument("docKey1", innerDoc0, innerDoc1)
+ .build();
+ assertThat(document.getPropertyNames()).containsExactly("stringKey1", "docKey1");
+
+ GenericDocument[] documents = document.getPropertyDocumentArray("docKey1");
+ assertThat(documents).asList().containsExactly(innerDoc0, innerDoc1).inOrder();
+ assertThat(documents[0].getPropertyNames()).containsExactly("propString", "propStringTwo",
+ "propInts");
+ assertThat(documents[1].getPropertyNames()).containsExactly("propString", "propInts",
+ "propIntsTwo");
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GetByDocumentIdRequestCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GetByDocumentIdRequestCtsTest.java
new file mode 100644
index 0000000..f9c1e6a
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GetByDocumentIdRequestCtsTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.GetByDocumentIdRequest;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class GetByDocumentIdRequestCtsTest {
+ @Test
+ public void testBuildRequest() {
+ List<String> expectedPropertyPaths1 = Arrays.asList("path1", "path2");
+ List<String> expectedPropertyPaths2 = Arrays.asList("path3", "path4");
+ GetByDocumentIdRequest getByDocumentIdRequest =
+ new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("uri1", "uri2")
+ .addIds(Arrays.asList("uri3", "uri4"))
+ .addProjection("schemaType1", expectedPropertyPaths1)
+ .addProjection("schemaType2", expectedPropertyPaths2)
+ .build();
+
+ assertThat(getByDocumentIdRequest.getIds()).containsExactly(
+ "uri1", "uri2", "uri3", "uri4");
+ assertThat(getByDocumentIdRequest.getNamespace()).isEqualTo("namespace");
+ assertThat(getByDocumentIdRequest.getProjections())
+ .containsExactly("schemaType1", expectedPropertyPaths1, "schemaType2",
+ expectedPropertyPaths2);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GetSchemaResponseCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GetSchemaResponseCtsTest.java
new file mode 100644
index 0000000..1220731
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GetSchemaResponseCtsTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GetSchemaResponse;
+
+import org.junit.Test;
+
+public class GetSchemaResponseCtsTest {
+ @Test
+ public void testRebuild() {
+ AppSearchSchema schema1 = new AppSearchSchema.Builder("Email1")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+ AppSearchSchema schema2 = new AppSearchSchema.Builder("Email2")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+
+ GetSchemaResponse.Builder builder =
+ new GetSchemaResponse.Builder().setVersion(42).addSchema(schema1);
+
+ GetSchemaResponse original = builder.build();
+ GetSchemaResponse rebuild = builder.setVersion(37).addSchema(schema2).build();
+
+ // rebuild won't effect the original object
+ assertThat(original.getVersion()).isEqualTo(42);
+ assertThat(original.getSchemas()).containsExactly(schema1);
+
+ assertThat(rebuild.getVersion()).isEqualTo(37);
+ assertThat(rebuild.getSchemas()).containsExactly(schema1, schema2);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java
new file mode 100644
index 0000000..04a48dd
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java
@@ -0,0 +1,748 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.util.AppSearchTestUtils.convertSearchResultsToDocuments;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.GlobalSearchSession;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.ReportSystemUsageRequest;
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.util.AppSearchEmail;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+public abstract class GlobalSearchSessionCtsTestBase {
+ static final String DB_NAME_1 = "";
+ static final String DB_NAME_2 = "testDb2";
+
+ private AppSearchSession mDb1;
+ private AppSearchSession mDb2;
+
+ private GlobalSearchSession mGlobalAppSearchManager;
+
+ protected abstract ListenableFuture<AppSearchSession> createSearchSession(
+ @NonNull String dbName);
+
+ protected abstract ListenableFuture<GlobalSearchSession> createGlobalSearchSession();
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+
+ mDb1 = createSearchSession(DB_NAME_1).get();
+ mDb2 = createSearchSession(DB_NAME_2).get();
+
+ // Cleanup whatever documents may still exist in these databases. This is needed in
+ // addition to tearDown in case a test exited without completing properly.
+ cleanup();
+
+ mGlobalAppSearchManager = createGlobalSearchSession().get();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Cleanup whatever documents may still exist in these databases.
+ cleanup();
+ }
+
+ private void cleanup() throws Exception {
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+ }
+
+ private List<GenericDocument> snapshotResults(String queryExpression, SearchSpec spec)
+ throws Exception {
+ SearchResults searchResults = mGlobalAppSearchManager.search(queryExpression, spec);
+ return convertSearchResultsToDocuments(searchResults);
+ }
+
+ /**
+ * Asserts that the union of {@code addedDocuments} and {@code beforeDocuments} is exactly
+ * equivalent to {@code afterDocuments}. Order doesn't matter.
+ *
+ * @param beforeDocuments Documents that existed first.
+ * @param afterDocuments The total collection of documents that should exist now.
+ * @param addedDocuments The collection of documents that were expected to be added.
+ */
+ private void assertAddedBetweenSnapshots(List<? extends GenericDocument> beforeDocuments,
+ List<? extends GenericDocument> afterDocuments,
+ List<? extends GenericDocument> addedDocuments) {
+ List<GenericDocument> expectedDocuments = new ArrayList<>(beforeDocuments);
+ expectedDocuments.addAll(addedDocuments);
+ assertThat(afterDocuments).containsExactlyElementsIn(expectedDocuments);
+ }
+
+ @Test
+ public void testGlobalQuery_oneInstance() throws Exception {
+ // Snapshot what documents may already exist on the device.
+ SearchSpec exactSearchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
+ List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
+ List<GenericDocument> beforeBodyEmailDocuments = snapshotResults("body email",
+ exactSearchSpec);
+
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // Query for the document
+ List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
+ assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
+ Collections.singletonList(inEmail));
+
+ // Multi-term query
+ List<GenericDocument> afterBodyEmailDocuments = snapshotResults("body email",
+ exactSearchSpec);
+ assertAddedBetweenSnapshots(beforeBodyEmailDocuments, afterBodyEmailDocuments,
+ Collections.singletonList(inEmail));
+ }
+
+ @Test
+ public void testGlobalQuery_twoInstances() throws Exception {
+ // Snapshot what documents may already exist on the device.
+ SearchSpec exactSearchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
+ List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
+
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a document to instance 1.
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+
+ // Index a document to instance 2.
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail2).build()));
+
+ // Query across all instances
+ List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
+ assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
+ ImmutableList.of(inEmail1, inEmail2));
+ }
+
+ @Test
+ public void testGlobalQuery_getNextPage() throws Exception {
+ // Snapshot what documents may already exist on the device.
+ SearchSpec exactSearchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
+ List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
+
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ List<AppSearchEmail> emailList = new ArrayList<>();
+ PutDocumentsRequest.Builder putDocumentsRequestBuilder = new PutDocumentsRequest.Builder();
+
+ // Index 31 documents
+ for (int i = 0; i < 31; i++) {
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id" + i)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ emailList.add(inEmail);
+ putDocumentsRequestBuilder.addGenericDocuments(inEmail);
+ }
+ checkIsBatchResultSuccess(mDb1.put(putDocumentsRequestBuilder.build()));
+
+ // Set number of results per page is 7.
+ int pageSize = 7;
+ SearchResults searchResults = mGlobalAppSearchManager.search("body",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(pageSize)
+ .build());
+ List<GenericDocument> documents = new ArrayList<>();
+
+ int pageNumber = 0;
+ List<SearchResult> results;
+
+ // keep loading next page until it's empty.
+ do {
+ results = searchResults.getNextPage().get();
+ ++pageNumber;
+ for (SearchResult result : results) {
+ documents.add(result.getGenericDocument());
+ }
+ } while (results.size() > 0);
+
+ // check all document presents
+ assertAddedBetweenSnapshots(beforeBodyDocuments, documents, emailList);
+
+ int totalDocuments = beforeBodyDocuments.size() + documents.size();
+
+ // +1 for final empty page
+ int expectedPages = (int) Math.ceil(totalDocuments * 1.0 / pageSize) + 1;
+ assertThat(pageNumber).isEqualTo(expectedPages);
+ }
+
+ @Test
+ public void testGlobalQuery_acrossTypes() throws Exception {
+ // Snapshot what documents may already exist on the device.
+ SearchSpec exactSearchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
+ List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
+
+ SearchSpec exactEmailSearchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addFilterSchemas(AppSearchEmail.SCHEMA_TYPE)
+ .build();
+ List<GenericDocument> beforeBodyEmailDocuments = snapshotResults("body",
+ exactEmailSearchSpec);
+
+ // Schema registration
+ AppSearchSchema genericSchema = new AppSearchSchema.Builder("Generic")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("foo")
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build()
+ ).build();
+
+ // db1 has both "Generic" and "builtin:Email"
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(genericSchema).addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // db2 only has "builtin:Email"
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index a generic document into db1
+ GenericDocument genericDocument = new GenericDocument.Builder<>("namespace", "id2",
+ "Generic")
+ .setPropertyString("foo", "body").build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(genericDocument).build()));
+
+ AppSearchEmail email =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+
+ // Put the email in both databases
+ checkIsBatchResultSuccess((mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build())));
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(email).build()));
+
+ // Query for all documents across types
+ List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
+ assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
+ ImmutableList.of(genericDocument, email, email));
+
+ // Query only for email documents
+ List<GenericDocument> afterBodyEmailDocuments = snapshotResults("body",
+ exactEmailSearchSpec);
+ assertAddedBetweenSnapshots(beforeBodyEmailDocuments, afterBodyEmailDocuments,
+ ImmutableList.of(email, email));
+ }
+
+ @Test
+ public void testGlobalQuery_namespaceFilter() throws Exception {
+ // Snapshot what documents may already exist on the device.
+ SearchSpec exactSearchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
+ List<GenericDocument> beforeBodyDocuments = snapshotResults("body", exactSearchSpec);
+
+ SearchSpec exactNamespace1SearchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addFilterNamespaces("namespace1")
+ .build();
+ List<GenericDocument> beforeBodyNamespace1Documents = snapshotResults("body",
+ exactNamespace1SearchSpec);
+
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index two documents
+ AppSearchEmail document1 =
+ new AppSearchEmail.Builder("namespace1", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(document1).build()));
+
+ AppSearchEmail document2 =
+ new AppSearchEmail.Builder("namespace2", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(document2).build()));
+
+ // Query for all namespaces
+ List<GenericDocument> afterBodyDocuments = snapshotResults("body", exactSearchSpec);
+ assertAddedBetweenSnapshots(beforeBodyDocuments, afterBodyDocuments,
+ ImmutableList.of(document1, document2));
+
+ // Query only for "namespace1"
+ List<GenericDocument> afterBodyNamespace1Documents = snapshotResults("body",
+ exactNamespace1SearchSpec);
+ assertAddedBetweenSnapshots(beforeBodyNamespace1Documents, afterBodyNamespace1Documents,
+ ImmutableList.of(document1));
+ }
+
+ @Test
+ public void testGlobalQuery_packageFilter() throws Exception {
+ // Snapshot what documents may already exist on the device.
+ SearchSpec otherPackageSearchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addFilterPackageNames("some.other.package")
+ .build();
+ List<GenericDocument> beforeOtherPackageDocuments = snapshotResults("body",
+ otherPackageSearchSpec);
+
+ SearchSpec testPackageSearchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addFilterPackageNames(
+ ApplicationProvider.getApplicationContext().getPackageName())
+ .build();
+ List<GenericDocument> beforeTestPackageDocuments = snapshotResults("body",
+ testPackageSearchSpec);
+
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index two documents
+ AppSearchEmail document1 =
+ new AppSearchEmail.Builder("namespace1", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(document1).build()));
+
+ AppSearchEmail document2 =
+ new AppSearchEmail.Builder("namespace2", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(document2).build()));
+
+ // Query in some other package
+ List<GenericDocument> afterOtherPackageDocuments = snapshotResults("body",
+ otherPackageSearchSpec);
+ assertAddedBetweenSnapshots(beforeOtherPackageDocuments, afterOtherPackageDocuments,
+ Collections.emptyList());
+
+ // Query within our package
+ List<GenericDocument> afterTestPackageDocuments = snapshotResults("body",
+ testPackageSearchSpec);
+ assertAddedBetweenSnapshots(beforeTestPackageDocuments, afterTestPackageDocuments,
+ ImmutableList.of(document1, document2));
+ }
+
+ // TODO(b/175039682) Add test cases for wildcard projection once go/oag/1534646 is submitted.
+ @Test
+ public void testGlobalQuery_projectionTwoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index one document in each database.
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1).build()));
+
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email2).build()));
+
+ // Query with type property paths {"Email", ["subject", "to"]}
+ List<GenericDocument> documents =
+ snapshotResults("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection(
+ AppSearchEmail.SCHEMA_TYPE, ImmutableList.of("subject", "to"))
+ .build());
+
+ // The two email documents should have been returned with only the "subject" and "to"
+ // properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ assertThat(documents).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testGlobalQuery_projectionEmptyTwoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index one document in each database.
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1).build()));
+
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email2).build()));
+
+ // Query with type property paths {"Email", []}
+ List<GenericDocument> documents =
+ snapshotResults("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection(AppSearchEmail.SCHEMA_TYPE,
+ Collections.emptyList())
+ .build());
+
+ // The two email documents should have been returned without any properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .build();
+ assertThat(documents).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testGlobalQuery_projectionNonExistentTypeTwoInstances() throws Exception {
+ // Schema registration
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+ mDb2.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA)
+ .build()).get();
+
+ // Index one document in each database.
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email1).build()));
+
+ AppSearchEmail email2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email2).build()));
+
+ // Query with type property paths {"NonExistentType", []}, {"Email", ["subject", "to"]}
+ List<GenericDocument> documents =
+ snapshotResults("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addProjection("NonExistentType", Collections.emptyList())
+ .addProjection(
+ AppSearchEmail.SCHEMA_TYPE, ImmutableList.of("subject", "to"))
+ .build());
+
+ // The two email documents should have been returned with only the "subject" and "to"
+ // properties.
+ AppSearchEmail expected1 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ AppSearchEmail expected2 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .build();
+ assertThat(documents).containsExactly(expected1, expected2);
+ }
+
+ @Test
+ public void testQuery_ResultGroupingLimits() throws Exception {
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ mDb2.setSchema(new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index one document in 'namespace1' and one document in 'namespace2' into db1.
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace1", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace2", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb1.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail2).build()));
+
+ // Index one document in 'namespace1' and one document in 'namespace2' into db2.
+ AppSearchEmail inEmail3 =
+ new AppSearchEmail.Builder("namespace1", "id3")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail3).build()));
+ AppSearchEmail inEmail4 =
+ new AppSearchEmail.Builder("namespace2", "id4")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(mDb2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail4).build()));
+
+ // Query with per package result grouping. Only the last document 'email4' should be
+ // returned.
+ List<GenericDocument> documents =
+ snapshotResults("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultGrouping(
+ SearchSpec.GROUPING_TYPE_PER_PACKAGE, /*resultLimit=*/ 1)
+ .build());
+ assertThat(documents).containsExactly(inEmail4);
+
+ // Query with per namespace result grouping. Only the last document in each namespace should
+ // be returned ('email4' and 'email3').
+ documents =
+ snapshotResults("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultGrouping(
+ SearchSpec.GROUPING_TYPE_PER_NAMESPACE, /*resultLimit=*/ 1)
+ .build());
+ assertThat(documents).containsExactly(inEmail4, inEmail3);
+
+ // Query with per package and per namespace result grouping. Only the last document in each
+ // namespace should be returned ('email4' and 'email3').
+ documents =
+ snapshotResults("body", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultGrouping(
+ SearchSpec.GROUPING_TYPE_PER_NAMESPACE
+ | SearchSpec.GROUPING_TYPE_PER_PACKAGE, /*resultLimit=*/ 1)
+ .build());
+ assertThat(documents).containsExactly(inEmail4, inEmail3);
+ }
+
+ @Test
+ public void testReportSystemUsage_ForbiddenFromNonSystem() throws Exception {
+ // Index a document
+ mDb1.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ AppSearchEmail email1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setCreationTimestampMillis(1000)
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(
+ mDb1.put(new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+
+ // Query
+ List<SearchResult> page;
+ try (SearchResults results = mGlobalAppSearchManager.search("", new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .addFilterSchemas(AppSearchEmail.SCHEMA_TYPE)
+ .build())) {
+ page = results.getNextPage().get();
+ }
+ assertThat(page).isNotEmpty();
+ SearchResult firstResult = page.get(0);
+
+ ExecutionException exception = assertThrows(
+ ExecutionException.class, () -> mGlobalAppSearchManager.reportSystemUsage(
+ new ReportSystemUsageRequest.Builder(
+ firstResult.getPackageName(),
+ firstResult.getDatabaseName(),
+ firstResult.getGenericDocument().getNamespace(),
+ firstResult.getGenericDocument().getId())
+ .build()).get());
+ assertThat(exception).hasCauseThat().isInstanceOf(AppSearchException.class);
+ AppSearchException ase = (AppSearchException) exception.getCause();
+ assertThat(ase.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+ assertThat(ase).hasMessageThat().contains(
+ "androidx.appsearch.test does not have access to report system usage");
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionLocalCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionLocalCtsTest.java
new file mode 100644
index 0000000..eedb926
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionLocalCtsTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.util.AppSearchTestUtils.checkIsBatchResultSuccess;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GlobalSearchSession;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.util.AppSearchEmail;
+import androidx.appsearch.app.util.AppSearchTestUtils;
+import androidx.appsearch.localstorage.LocalStorage;
+import androidx.appsearch.localstorage.stats.SearchStats;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class GlobalSearchSessionLocalCtsTest extends GlobalSearchSessionCtsTestBase {
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, dbName).build());
+ }
+
+ @Override
+ protected ListenableFuture<GlobalSearchSession> createGlobalSearchSession() {
+ Context context = ApplicationProvider.getApplicationContext();
+ return LocalStorage.createGlobalSearchSession(
+ new LocalStorage.GlobalSearchContext.Builder(context).build());
+ }
+
+ // TODO(b/194207451) Following tests can be moved to CtsTestBase if customized logger is
+ // supported for platform backend.
+ @Test
+ public void testLogger_searchStatsLogged_forEmptyFirstPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger =
+ new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ GlobalSearchSession globalSearchSession = LocalStorage.createGlobalSearchSession(
+ new LocalStorage.GlobalSearchContext.Builder(context).setLogger(
+ logger).build()).get();
+ assertThat(logger.mSearchStats).isNull();
+
+ // Query for the document using global search session.
+ int resultCountPerPage = 1;
+ String queryStr = "bodies";
+ SearchResults searchResults = globalSearchSession.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(0);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isNull();
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(queryStr.length());
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(true);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_GLOBAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(resultCountPerPage);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testLogger_searchStatsLogged_forNonEmptyFirstPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger =
+ new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ GlobalSearchSession globalSearchSession = LocalStorage.createGlobalSearchSession(
+ new LocalStorage.GlobalSearchContext.Builder(context).setLogger(
+ logger).build()).get();
+ assertThat(logger.mSearchStats).isNull();
+
+ // Query for the document using global search session.
+ int resultCountPerPage = 1;
+ String queryStr = "body";
+ SearchResults searchResults = globalSearchSession.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(1);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isNull();
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(queryStr.length());
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(true);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_GLOBAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(resultCountPerPage);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testLogger_searchStatsLogged_forEmptySecondPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger =
+ new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ GlobalSearchSession globalSearchSession = LocalStorage.createGlobalSearchSession(
+ new LocalStorage.GlobalSearchContext.Builder(context).setLogger(
+ logger).build()).get();
+ assertThat(logger.mSearchStats).isNull();
+
+ // Query for the document using global search session.
+ int resultCountPerPage = 2;
+ String queryStr = "body";
+ SearchResults searchResults = globalSearchSession.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(2);
+
+ // Get second(empty) page
+ logger.mSearchStats = null;
+ page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(0);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isNull();
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(0);
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(false);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_GLOBAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(0);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testLogger_searchStatsLogged_forNonEmptySecondPage() throws Exception {
+ AppSearchTestUtils.TestLogger logger =
+ new AppSearchTestUtils.TestLogger();
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession db2 = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, DB_NAME_2)
+ .setLogger(logger).build()).get();
+
+ // Schema registration
+ db2.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+ // Index documents
+ AppSearchEmail inEmail1 =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ AppSearchEmail inEmail2 =
+ new AppSearchEmail.Builder("namespace", "id2")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(db2.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1, inEmail2).build()));
+
+ GlobalSearchSession globalSearchSession = LocalStorage.createGlobalSearchSession(
+ new LocalStorage.GlobalSearchContext.Builder(context).setLogger(
+ logger).build()).get();
+ assertThat(logger.mSearchStats).isNull();
+
+ // Query for the document using global search session.
+ int resultCountPerPage = 1;
+ String queryStr = "body";
+ SearchResults searchResults = globalSearchSession.search(queryStr, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setResultCountPerPage(resultCountPerPage)
+ .build());
+
+ // Get first page
+ List<SearchResult> page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(1);
+
+ // Get second page
+ logger.mSearchStats = null;
+ page = searchResults.getNextPage().get();
+ assertThat(page).hasSize(1);
+
+ // Check searchStats has been set. We won't check all the fields here.
+ assertThat(logger.mSearchStats).isNotNull();
+ assertThat(logger.mSearchStats.getDatabase()).isNull();
+ assertThat(logger.mSearchStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(logger.mSearchStats.getQueryLength()).isEqualTo(0);
+ assertThat(logger.mSearchStats.isFirstPage()).isEqualTo(false);
+ assertThat(logger.mSearchStats.getVisibilityScope()).isEqualTo(
+ SearchStats.VISIBILITY_SCOPE_GLOBAL);
+ assertThat(logger.mSearchStats.getRequestedPageSize()).isEqualTo(resultCountPerPage);
+ assertThat(logger.mSearchStats.getCurrentPageReturnedResultCount()).isEqualTo(1);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionPlatformCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionPlatformCtsTest.java
new file mode 100644
index 0000000..a5fd1fe
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionPlatformCtsTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.cts.app;
+
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GlobalSearchSession;
+import androidx.appsearch.platformstorage.PlatformStorage;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+public class GlobalSearchSessionPlatformCtsTest extends GlobalSearchSessionCtsTestBase {
+ @Override
+ protected ListenableFuture<AppSearchSession> createSearchSession(@NonNull String dbName) {
+ Context context = ApplicationProvider.getApplicationContext();
+ return PlatformStorage.createSearchSession(
+ new PlatformStorage.SearchContext.Builder(context, dbName).build());
+ }
+
+ @Override
+ protected ListenableFuture<GlobalSearchSession> createGlobalSearchSession() {
+ Context context = ApplicationProvider.getApplicationContext();
+ return PlatformStorage.createGlobalSearchSession(
+ new PlatformStorage.GlobalSearchContext.Builder(context).build());
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/PackageIdentifierCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/PackageIdentifierCtsTest.java
new file mode 100644
index 0000000..bae9e22
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/PackageIdentifierCtsTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.PackageIdentifier;
+
+import org.junit.Test;
+
+public class PackageIdentifierCtsTest {
+ @Test
+ public void testGetters() {
+ PackageIdentifier packageIdentifier = new PackageIdentifier("com.packageName",
+ /*sha256Certificate=*/ new byte[]{100});
+ assertThat(packageIdentifier.getPackageName()).isEqualTo("com.packageName");
+ assertThat(packageIdentifier.getSha256Certificate()).isEqualTo(new byte[]{100});
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/PutDocumentsRequestCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/PutDocumentsRequestCtsTest.java
new file mode 100644
index 0000000..7753e15
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/PutDocumentsRequestCtsTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.appsearch.annotation.Document;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.util.AppSearchEmail;
+import androidx.appsearch.localstorage.LocalStorage;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Test;
+
+import java.util.Set;
+
+public class PutDocumentsRequestCtsTest {
+
+ @Test
+ public void addGenericDocument_byCollection() {
+ Set<AppSearchEmail> emails =
+ ImmutableSet.of(new AppSearchEmail.Builder("namespace", "test1").build(),
+ new AppSearchEmail.Builder("namespace", "test2").build());
+ PutDocumentsRequest request = new PutDocumentsRequest.Builder().addGenericDocuments(emails)
+ .build();
+
+ assertThat(request.getGenericDocuments().get(0).getId()).isEqualTo("test1");
+ assertThat(request.getGenericDocuments().get(1).getId()).isEqualTo("test2");
+ }
+
+// @exportToFramework:startStrip()
+ @Document
+ static class Card {
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.Id
+ String mId;
+
+ @Document.StringProperty(indexingType = INDEXING_TYPE_PREFIXES)
+ String mString;
+
+ Card(String namespace, String id, String string) {
+ mId = id;
+ mNamespace = namespace;
+ mString = string;
+ }
+ }
+
+ @Test
+ public void addDocumentClasses_byCollection() throws Exception {
+ // A schema with Card must be set in order to be able to add a Card instance to
+ // PutDocumentsRequest.
+ Context context = ApplicationProvider.getApplicationContext();
+ AppSearchSession session = LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(context, /*databaseName=*/ "")
+ .build()
+ ).get();
+ session.setSchema(new SetSchemaRequest.Builder().addDocumentClasses(Card.class).build())
+ .get();
+
+ Set<Card> cards = ImmutableSet.of(new Card("cardNamespace", "cardId", "cardProperty"));
+ PutDocumentsRequest request = new PutDocumentsRequest.Builder().addDocuments(cards)
+ .build();
+
+ assertThat(request.getGenericDocuments().get(0).getId()).isEqualTo("cardId");
+ }
+// @exportToFramework:endStrip()
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/RemoveByDocumentIdRequestCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/RemoveByDocumentIdRequestCtsTest.java
new file mode 100644
index 0000000..9fe1ebb
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/RemoveByDocumentIdRequestCtsTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.RemoveByDocumentIdRequest;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class RemoveByDocumentIdRequestCtsTest {
+ @Test
+ public void testBuildRequest() {
+ RemoveByDocumentIdRequest request = new RemoveByDocumentIdRequest.Builder("namespace")
+ .addIds("uri1", "uri2")
+ .addIds(Arrays.asList("uri3"))
+ .build();
+
+ assertThat(request.getNamespace()).isEqualTo("namespace");
+ assertThat(request.getIds()).containsExactly("uri1", "uri2", "uri3").inOrder();
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/ReportSystemUsageRequestCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/ReportSystemUsageRequestCtsTest.java
new file mode 100644
index 0000000..69331f8
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/ReportSystemUsageRequestCtsTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.ReportSystemUsageRequest;
+
+import org.junit.Test;
+
+public class ReportSystemUsageRequestCtsTest {
+ @Test
+ public void testGettersAndSetters() {
+ ReportSystemUsageRequest request = new ReportSystemUsageRequest.Builder(
+ "package1", "database1", "namespace1", "id1")
+ .setUsageTimestampMillis(32)
+ .build();
+ assertThat(request.getPackageName()).isEqualTo("package1");
+ assertThat(request.getDatabaseName()).isEqualTo("database1");
+ assertThat(request.getNamespace()).isEqualTo("namespace1");
+ assertThat(request.getDocumentId()).isEqualTo("id1");
+ assertThat(request.getUsageTimestampMillis()).isEqualTo(32);
+ }
+
+ @Test
+ public void testUsageTimestampDefault() {
+ long startTs = System.currentTimeMillis();
+ ReportSystemUsageRequest request =
+ new ReportSystemUsageRequest.Builder("package1", "database1", "namespace1", "id1")
+ .build();
+ assertThat(request.getUsageTimestampMillis()).isAtLeast(startTs);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/ReportUsageRequestCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/ReportUsageRequestCtsTest.java
new file mode 100644
index 0000000..a873c33
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/ReportUsageRequestCtsTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.ReportUsageRequest;
+
+import org.junit.Test;
+
+public class ReportUsageRequestCtsTest {
+ @Test
+ public void testGettersAndSetters() {
+ ReportUsageRequest request = new ReportUsageRequest.Builder("namespace1", "id1")
+ .setUsageTimestampMillis(32)
+ .build();
+ assertThat(request.getNamespace()).isEqualTo("namespace1");
+ assertThat(request.getDocumentId()).isEqualTo("id1");
+ assertThat(request.getUsageTimestampMillis()).isEqualTo(32);
+ }
+
+ @Test
+ public void testUsageTimestampDefault() {
+ long startTs = System.currentTimeMillis();
+ ReportUsageRequest request = new ReportUsageRequest.Builder("namespace1", "id1").build();
+ assertThat(request.getUsageTimestampMillis()).isAtLeast(startTs);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchResultCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchResultCtsTest.java
new file mode 100644
index 0000000..ea3efe8
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchResultCtsTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.util.AppSearchEmail;
+
+import org.junit.Test;
+
+public class SearchResultCtsTest {
+
+ @Test
+ public void testBuildSearchResult() {
+ SearchResult.MatchRange exactMatchRange = new SearchResult.MatchRange(3, 8);
+ SearchResult.MatchRange snippetMatchRange = new SearchResult.MatchRange(1, 10);
+ SearchResult.MatchInfo matchInfo =
+ new SearchResult.MatchInfo.Builder("body")
+ .setExactMatchRange(exactMatchRange)
+ .setSnippetRange(snippetMatchRange).build();
+
+ AppSearchEmail email = new AppSearchEmail.Builder("namespace1", "id1")
+ .setBody("Hello World.")
+ .build();
+ SearchResult searchResult = new SearchResult.Builder("packageName", "databaseName")
+ .setGenericDocument(email)
+ .addMatchInfo(matchInfo)
+ .setRankingSignal(2.9)
+ .build();
+
+ assertThat(searchResult.getPackageName()).isEqualTo("packageName");
+ assertThat(searchResult.getDatabaseName()).isEqualTo("databaseName");
+ assertThat(searchResult.getRankingSignal()).isEqualTo(2.9);
+ assertThat(searchResult.getGenericDocument()).isEqualTo(email);
+ assertThat(searchResult.getMatchInfos()).hasSize(1);
+ SearchResult.MatchInfo actualMatchInfo = searchResult.getMatchInfos().get(0);
+ assertThat(actualMatchInfo.getPropertyPath()).isEqualTo("body");
+ assertThat(actualMatchInfo.getExactMatchRange()).isEqualTo(exactMatchRange);
+ assertThat(actualMatchInfo.getSnippetRange()).isEqualTo(snippetMatchRange);
+ assertThat(actualMatchInfo.getExactMatch()).isEqualTo("lo Wo");
+ assertThat(actualMatchInfo.getSnippet()).isEqualTo("ello Worl");
+ assertThat(actualMatchInfo.getFullText()).isEqualTo("Hello World.");
+ }
+
+ @Test
+ public void testMatchRange() {
+ SearchResult.MatchRange matchRange = new SearchResult.MatchRange(13, 47);
+ assertThat(matchRange.getStart()).isEqualTo(13);
+ assertThat(matchRange.getEnd()).isEqualTo(47);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchSpecCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchSpecCtsTest.java
new file mode 100644
index 0000000..c62ba4f
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchSpecCtsTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.annotation.Document;
+import androidx.appsearch.app.SearchSpec;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class SearchSpecCtsTest {
+ @Test
+ public void testBuildSearchSpecWithoutTermMatch() {
+ SearchSpec searchSpec = new SearchSpec.Builder().addFilterSchemas("testSchemaType").build();
+ assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
+ }
+
+ @Test
+ public void testBuildSearchSpec() {
+ List<String> expectedPropertyPaths1 = ImmutableList.of("path1", "path2");
+ List<String> expectedPropertyPaths2 = ImmutableList.of("path3", "path4");
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterNamespaces("namespace1", "namespace2")
+ .addFilterNamespaces(ImmutableList.of("namespace3"))
+ .addFilterSchemas("schemaTypes1", "schemaTypes2")
+ .addFilterSchemas(ImmutableList.of("schemaTypes3"))
+ .addFilterPackageNames("package1", "package2")
+ .addFilterPackageNames(ImmutableList.of("package3"))
+ .setSnippetCount(5)
+ .setSnippetCountPerProperty(10)
+ .setMaxSnippetSize(15)
+ .setResultCountPerPage(42)
+ .setOrder(SearchSpec.ORDER_ASCENDING)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
+ .setResultGrouping(SearchSpec.GROUPING_TYPE_PER_NAMESPACE
+ | SearchSpec.GROUPING_TYPE_PER_PACKAGE, /*limit=*/ 37)
+ .addProjection("schemaType1", expectedPropertyPaths1)
+ .addProjection("schemaType2", expectedPropertyPaths2)
+ .build();
+
+ assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
+ assertThat(searchSpec.getFilterNamespaces())
+ .containsExactly("namespace1", "namespace2", "namespace3").inOrder();
+ assertThat(searchSpec.getFilterSchemas())
+ .containsExactly("schemaTypes1", "schemaTypes2", "schemaTypes3").inOrder();
+ assertThat(searchSpec.getFilterPackageNames())
+ .containsExactly("package1", "package2", "package3").inOrder();
+ assertThat(searchSpec.getSnippetCount()).isEqualTo(5);
+ assertThat(searchSpec.getSnippetCountPerProperty()).isEqualTo(10);
+ assertThat(searchSpec.getMaxSnippetSize()).isEqualTo(15);
+ assertThat(searchSpec.getResultCountPerPage()).isEqualTo(42);
+ assertThat(searchSpec.getOrder()).isEqualTo(SearchSpec.ORDER_ASCENDING);
+ assertThat(searchSpec.getRankingStrategy())
+ .isEqualTo(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE);
+ assertThat(searchSpec.getResultGroupingTypeFlags())
+ .isEqualTo(SearchSpec.GROUPING_TYPE_PER_NAMESPACE
+ | SearchSpec.GROUPING_TYPE_PER_PACKAGE);
+ assertThat(searchSpec.getProjections())
+ .containsExactly("schemaType1", expectedPropertyPaths1, "schemaType2",
+ expectedPropertyPaths2);
+ assertThat(searchSpec.getResultGroupingLimit()).isEqualTo(37);
+ }
+
+ @Test
+ public void testGetProjectionTypePropertyMasks() {
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addProjection("TypeA", ImmutableList.of("field1", "field2.subfield2"))
+ .addProjection("TypeB", ImmutableList.of("field7"))
+ .addProjection("TypeC", ImmutableList.of())
+ .build();
+
+ Map<String, List<String>> typePropertyPathMap = searchSpec.getProjections();
+ assertThat(typePropertyPathMap.keySet())
+ .containsExactly("TypeA", "TypeB", "TypeC");
+ assertThat(typePropertyPathMap.get("TypeA")).containsExactly("field1", "field2.subfield2");
+ assertThat(typePropertyPathMap.get("TypeB")).containsExactly("field7");
+ assertThat(typePropertyPathMap.get("TypeC")).isEmpty();
+ }
+
+// @exportToFramework:startStrip()
+ @Document
+ static class King extends Card {
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.Id
+ String mId;
+
+ @Document.StringProperty
+ (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
+ String mString;
+ }
+
+ static class Card {}
+
+ @Test
+ public void testFilterDocumentClasses_byCollection() throws Exception {
+ Set<Class<King>> cardClassSet = ImmutableSet.of(King.class);
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterDocumentClasses(cardClassSet)
+ .build();
+
+ assertThat(searchSpec.getFilterSchemas()).containsExactly("King");
+ }
+// @exportToFramework:endStrip()
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SetSchemaRequestCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SetSchemaRequestCtsTest.java
new file mode 100644
index 0000000..d00bf30
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SetSchemaRequestCtsTest.java
@@ -0,0 +1,501 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.annotation.Document;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.Migrator;
+import androidx.appsearch.app.PackageIdentifier;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.util.AppSearchEmail;
+import androidx.collection.ArrayMap;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class SetSchemaRequestCtsTest {
+ @Test
+ public void testBuildSetSchemaRequest() {
+ AppSearchSchema.StringPropertyConfig prop1 =
+ new AppSearchSchema.StringPropertyConfig.Builder("prop1")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build();
+ AppSearchSchema schema1 =
+ new AppSearchSchema.Builder("type1").addProperty(prop1).build();
+ AppSearchSchema schema2 =
+ new AppSearchSchema.Builder("type2").addProperty(prop1).build();
+ AppSearchSchema schema3 =
+ new AppSearchSchema.Builder("type3").addProperty(prop1).build();
+ AppSearchSchema schema4 =
+ new AppSearchSchema.Builder("type4").addProperty(prop1).build();
+
+ PackageIdentifier packageIdentifier =
+ new PackageIdentifier("com.package.foo", new byte[]{100});
+
+ SetSchemaRequest request = new SetSchemaRequest.Builder()
+ .addSchemas(schema1, schema2)
+ .addSchemas(Arrays.asList(schema3, schema4))
+ .setSchemaTypeDisplayedBySystem("type2", /*displayed=*/ false)
+ .setSchemaTypeVisibilityForPackage("type1", /*visible=*/ true,
+ packageIdentifier)
+ .setForceOverride(true)
+ .setVersion(142857)
+ .build();
+
+ assertThat(request.getSchemas()).containsExactly(schema1, schema2, schema3, schema4);
+ assertThat(request.getSchemasNotDisplayedBySystem()).containsExactly("type2");
+
+ assertThat(request.getSchemasVisibleToPackages()).containsExactly(
+ "type1", Collections.singleton(packageIdentifier));
+ assertThat(request.getVersion()).isEqualTo(142857);
+ assertThat(request.isForceOverride()).isTrue();
+ }
+
+ @Test
+ public void testSetSchemaRequestTypeChanges() {
+ AppSearchSchema.StringPropertyConfig requiredProp =
+ new AppSearchSchema.StringPropertyConfig.Builder("prop1")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build();
+ AppSearchSchema schema1 =
+ new AppSearchSchema.Builder("type1").addProperty(requiredProp).build();
+ AppSearchSchema schema2 =
+ new AppSearchSchema.Builder("type2").addProperty(requiredProp).build();
+ AppSearchSchema schema3 =
+ new AppSearchSchema.Builder("type3").addProperty(requiredProp).build();
+
+ Migrator expectedMigrator1 = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+ Migrator expectedMigrator2 = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+ Migrator expectedMigrator3 = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return document;
+ }
+ };
+ Map<String, Migrator> migratorMap = new ArrayMap<>();
+ migratorMap.put("type1", expectedMigrator1);
+ migratorMap.put("type2", expectedMigrator2);
+
+ SetSchemaRequest request = new SetSchemaRequest.Builder()
+ .addSchemas(schema1, schema2, schema3)
+ .setForceOverride(/*forceOverride=*/ true)
+ .setMigrators(migratorMap)
+ .setMigrator("type3", expectedMigrator3)
+ .build();
+
+ assertThat(request.isForceOverride()).isTrue();
+ Map<String, Migrator> expectedMigratorMap = new ArrayMap<>();
+ expectedMigratorMap.put("type1", expectedMigrator1);
+ expectedMigratorMap.put("type2", expectedMigrator2);
+ expectedMigratorMap.put("type3", expectedMigrator3);
+ assertThat(request.getMigrators()).containsExactlyEntriesIn(expectedMigratorMap);
+ }
+
+ @Test
+ public void testInvalidSchemaReferences_fromDisplayedBySystem() {
+ IllegalArgumentException expected = assertThrows(IllegalArgumentException.class,
+ () -> new SetSchemaRequest.Builder().setSchemaTypeDisplayedBySystem(
+ "InvalidSchema", false).build());
+ assertThat(expected).hasMessageThat().contains("referenced, but were not added");
+ }
+
+ @Test
+ public void testInvalidSchemaReferences_fromPackageVisibility() {
+ IllegalArgumentException expected = assertThrows(IllegalArgumentException.class,
+ () -> new SetSchemaRequest.Builder().setSchemaTypeVisibilityForPackage(
+ "InvalidSchema", /*visible=*/ true, new PackageIdentifier(
+ "com.foo.package", /*sha256Certificate=*/ new byte[]{})).build());
+ assertThat(expected).hasMessageThat().contains("referenced, but were not added");
+ }
+
+ @Test
+ public void testSetSchemaTypeDisplayedBySystem_displayed() {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+
+ // By default, the schema is displayed.
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addSchemas(schema).build();
+ assertThat(request.getSchemasNotDisplayedBySystem()).isEmpty();
+
+ request = new SetSchemaRequest.Builder()
+ .addSchemas(schema).setSchemaTypeDisplayedBySystem("Schema", true).build();
+ assertThat(request.getSchemasNotDisplayedBySystem()).isEmpty();
+ }
+
+ @Test
+ public void testSetSchemaTypeDisplayedBySystem_notDisplayed() {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+ SetSchemaRequest request = new SetSchemaRequest.Builder()
+ .addSchemas(schema).setSchemaTypeDisplayedBySystem("Schema", false).build();
+ assertThat(request.getSchemasNotDisplayedBySystem()).containsExactly("Schema");
+ }
+
+ @Test
+ public void testSchemaTypeVisibilityForPackage_visible() {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+
+ // By default, the schema is not visible.
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addSchemas(schema).build();
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+
+ PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
+ new byte[]{100});
+
+ request =
+ new SetSchemaRequest.Builder().addSchemas(schema).setSchemaTypeVisibilityForPackage(
+ "Schema", /*visible=*/ true, packageIdentifier).build();
+ assertThat(request.getSchemasVisibleToPackages()).containsExactly(
+ "Schema", Collections.singleton(packageIdentifier));
+ }
+
+ @Test
+ public void testSchemaTypeVisibilityForPackage_notVisible() {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addSchemas(schema).setSchemaTypeVisibilityForPackage(
+ "Schema", /*visible=*/ false, new PackageIdentifier("com.package.foo",
+ /*sha256Certificate=*/ new byte[]{})).build();
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+ }
+
+ @Test
+ public void testSchemaTypeVisibilityForPackage_deduped() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+
+ PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
+ new byte[]{100});
+
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder()
+ .addSchemas(schema)
+ // Set it visible for "Schema"
+ .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
+ true, packageIdentifier)
+ // Set it visible for "Schema" again, which should be a no-op
+ .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
+ true, packageIdentifier)
+ .build();
+ assertThat(request.getSchemasVisibleToPackages()).containsExactly(
+ "Schema", Collections.singleton(packageIdentifier));
+ }
+
+ @Test
+ public void testSchemaTypeVisibilityForPackage_removed() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder()
+ .addSchemas(schema)
+ // First set it as visible
+ .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
+ true, new PackageIdentifier("com.package.foo",
+ /*sha256Certificate=*/ new byte[]{100}))
+ // Then make it not visible
+ .setSchemaTypeVisibilityForPackage("Schema", /*visible=*/
+ false, new PackageIdentifier("com.package.foo",
+ /*sha256Certificate=*/ new byte[]{100}))
+ .build();
+
+ // Nothing should be visible.
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+ }
+
+
+// @exportToFramework:startStrip()
+ @Document
+ static class Card {
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.Id
+ String mId;
+
+ @Document.StringProperty
+ (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
+ String mString;
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Card)) {
+ return false;
+ }
+ Card otherCard = (Card) other;
+ assertThat(otherCard.mNamespace).isEqualTo(this.mNamespace);
+ assertThat(otherCard.mId).isEqualTo(this.mId);
+ return true;
+ }
+ }
+
+ static class Spade {}
+
+ @Document
+ static class King extends Spade {
+ @Document.Id
+ String mId;
+
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.StringProperty
+ (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
+ String mString;
+ }
+
+ @Document
+ static class Queen extends Spade {
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.Id
+ String mId;
+
+ @Document.StringProperty
+ (indexingType = INDEXING_TYPE_PREFIXES, tokenizerType = TOKENIZER_TYPE_PLAIN)
+ String mString;
+ }
+
+ private static Collection<String> getSchemaTypesFromSetSchemaRequest(SetSchemaRequest request) {
+ HashSet<String> schemaTypes = new HashSet<>();
+ for (AppSearchSchema schema : request.getSchemas()) {
+ schemaTypes.add(schema.getSchemaType());
+ }
+ return schemaTypes;
+ }
+
+ @Test
+ public void testSetDocumentClassDisplayedBySystem_displayed() throws Exception {
+ // By default, the schema is displayed.
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(Card.class).build();
+ assertThat(request.getSchemasNotDisplayedBySystem()).isEmpty();
+
+ request =
+ new SetSchemaRequest.Builder().addDocumentClasses(
+ Card.class).setDocumentClassDisplayedBySystem(
+ Card.class, true).build();
+ assertThat(request.getSchemasNotDisplayedBySystem()).isEmpty();
+ }
+
+ @Test
+ public void testSetDocumentClassDisplayedBySystem_notDisplayed() throws Exception {
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(
+ Card.class).setDocumentClassDisplayedBySystem(
+ Card.class, false).build();
+ assertThat(request.getSchemasNotDisplayedBySystem()).containsExactly("Card");
+ }
+
+ @Test
+ public void testSetDocumentClassVisibilityForPackage_visible() throws Exception {
+ // By default, the schema is not visible.
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(Card.class).build();
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+
+ PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
+ new byte[]{100});
+ Map<String, Set<PackageIdentifier>> expectedVisibleToPackagesMap = new ArrayMap<>();
+ expectedVisibleToPackagesMap.put("Card", Collections.singleton(packageIdentifier));
+
+ request =
+ new SetSchemaRequest.Builder().addDocumentClasses(
+ Card.class).setDocumentClassVisibilityForPackage(
+ Card.class, /*visible=*/ true, packageIdentifier).build();
+ assertThat(request.getSchemasVisibleToPackages()).containsExactlyEntriesIn(
+ expectedVisibleToPackagesMap);
+ }
+
+ @Test
+ public void testSetDocumentClassVisibilityForPackage_notVisible() throws Exception {
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(
+ Card.class).setDocumentClassVisibilityForPackage(
+ Card.class, /*visible=*/ false,
+ new PackageIdentifier("com.package.foo", /*sha256Certificate=*/
+ new byte[]{})).build();
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+ }
+
+ @Test
+ public void testSetDocumentClassVisibilityForPackage_deduped() throws Exception {
+ // By default, the schema is not visible.
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(Card.class).build();
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+
+ PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo",
+ new byte[]{100});
+ Map<String, Set<PackageIdentifier>> expectedVisibleToPackagesMap = new ArrayMap<>();
+ expectedVisibleToPackagesMap.put("Card", Collections.singleton(packageIdentifier));
+
+ request =
+ new SetSchemaRequest.Builder()
+ .addDocumentClasses(Card.class)
+ .setDocumentClassVisibilityForPackage(Card.class, /*visible=*/
+ true, packageIdentifier)
+ .setDocumentClassVisibilityForPackage(Card.class, /*visible=*/
+ true, packageIdentifier)
+ .build();
+ assertThat(request.getSchemasVisibleToPackages()).containsExactlyEntriesIn(
+ expectedVisibleToPackagesMap);
+ }
+
+ @Test
+ public void testSetDocumentClassVisibilityForPackage_removed() throws Exception {
+ // By default, the schema is not visible.
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(Card.class).build();
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+
+ request =
+ new SetSchemaRequest.Builder()
+ .addDocumentClasses(Card.class)
+ // First set it as visible
+ .setDocumentClassVisibilityForPackage(Card.class, /*visible=*/
+ true, new PackageIdentifier("com.package.foo",
+ /*sha256Certificate=*/ new byte[]{100}))
+ // Then make it not visible
+ .setDocumentClassVisibilityForPackage(Card.class, /*visible=*/
+ false, new PackageIdentifier("com.package.foo",
+ /*sha256Certificate=*/ new byte[]{100}))
+ .build();
+
+ // Nothing should be visible.
+ assertThat(request.getSchemasVisibleToPackages()).isEmpty();
+ }
+
+ @Test
+ public void testAddDocumentClasses_byCollection() throws Exception {
+ Set<Class<? extends Spade>> cardClasses = ImmutableSet.of(Queen.class, King.class);
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(cardClasses)
+ .build();
+ assertThat(getSchemaTypesFromSetSchemaRequest(request)).containsExactly("Queen",
+ "King");
+ }
+
+ @Test
+ public void testAddDocumentClasses_byCollectionWithSeparateCalls() throws
+ Exception {
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().addDocumentClasses(ImmutableSet.of(Queen.class))
+ .addDocumentClasses(ImmutableSet.of(King.class)).build();
+ assertThat(getSchemaTypesFromSetSchemaRequest(request)).containsExactly("Queen",
+ "King");
+ }
+
+// @exportToFramework:endStrip()
+
+ @Test
+ public void testSetVersion() {
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+ () -> new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).setVersion(0).build());
+ assertThat(exception).hasMessageThat().contains("Version must be a positive number");
+ SetSchemaRequest request = new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchEmail.SCHEMA).setVersion(1).build();
+ assertThat(request.getVersion()).isEqualTo(1);
+ }
+
+ @Test
+ public void testSetVersion_emptyDb() {
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+ () -> new SetSchemaRequest.Builder().setVersion(135).build());
+ assertThat(exception).hasMessageThat().contains(
+ "Cannot set version to the request if schema is empty.");
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SetSchemaResponseCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SetSchemaResponseCtsTest.java
new file mode 100644
index 0000000..667658f
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SetSchemaResponseCtsTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.SetSchemaResponse;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class SetSchemaResponseCtsTest {
+ @Test
+ public void testRebuild() {
+ SetSchemaResponse.MigrationFailure failure1 = new SetSchemaResponse.MigrationFailure(
+ "namespace",
+ "failure1",
+ "schemaType",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+ SetSchemaResponse.MigrationFailure failure2 = new SetSchemaResponse.MigrationFailure(
+ "namespace",
+ "failure2",
+ "schemaType",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+
+ SetSchemaResponse.Builder builder = new SetSchemaResponse.Builder()
+ .addDeletedType("delete1")
+ .addIncompatibleType("incompatible1")
+ .addMigratedType("migrated1")
+ .addMigrationFailure(failure1);
+ SetSchemaResponse original = builder.build();
+ assertThat(original.getDeletedTypes()).containsExactly("delete1");
+ assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+ assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+ assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+ SetSchemaResponse rebuild = builder
+ .addDeletedType("delete2")
+ .addIncompatibleType("incompatible2")
+ .addMigratedType("migrated2")
+ .addMigrationFailure(failure2)
+ .build();
+
+ // rebuild won't effect the original object
+ assertThat(original.getDeletedTypes()).containsExactly("delete1");
+ assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+ assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+ assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+ assertThat(rebuild.getDeletedTypes()).containsExactly("delete1", "delete2");
+ assertThat(rebuild.getIncompatibleTypes()).containsExactly("incompatible1",
+ "incompatible2");
+ assertThat(rebuild.getMigratedTypes()).containsExactly("migrated1", "migrated2");
+ assertThat(rebuild.getMigrationFailures()).containsExactly(failure1, failure2);
+ }
+
+ @Test
+ public void testPluralAdds() {
+ SetSchemaResponse.MigrationFailure failure1 = new SetSchemaResponse.MigrationFailure(
+ "namespace",
+ "failure1",
+ "schemaType",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+
+ SetSchemaResponse.Builder builder = new SetSchemaResponse.Builder()
+ .addDeletedTypes(Arrays.asList("delete1"))
+ .addIncompatibleTypes(Arrays.asList("incompatible1"))
+ .addMigratedTypes(Arrays.asList("migrated1"))
+ .addMigrationFailures(Arrays.asList(failure1));
+ SetSchemaResponse singleEntries = builder.build();
+ assertThat(singleEntries.getDeletedTypes()).containsExactly("delete1");
+ assertThat(singleEntries.getIncompatibleTypes()).containsExactly("incompatible1");
+ assertThat(singleEntries.getMigratedTypes()).containsExactly("migrated1");
+ assertThat(singleEntries.getMigrationFailures()).containsExactly(failure1);
+
+ SetSchemaResponse.MigrationFailure failure2 = new SetSchemaResponse.MigrationFailure(
+ "namespace",
+ "failure2",
+ "schemaType",
+ AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+ SetSchemaResponse multiEntries = builder
+ .addDeletedTypes(Arrays.asList("delete2", "deleted3", "deleted4"))
+ .addIncompatibleTypes(Arrays.asList("incompatible2"))
+ .addMigratedTypes(Arrays.asList("migrated2", "migrate3"))
+ .addMigrationFailures(Arrays.asList(failure2))
+ .build();
+
+ assertThat(multiEntries.getDeletedTypes()).containsExactly("delete1", "delete2", "deleted3",
+ "deleted4");
+ assertThat(multiEntries.getIncompatibleTypes()).containsExactly("incompatible1",
+ "incompatible2");
+ assertThat(multiEntries.getMigratedTypes()).containsExactly("migrated1", "migrated2",
+ "migrate3");
+ assertThat(multiEntries.getMigrationFailures()).containsExactly(failure1, failure2);
+ }
+
+ @Test
+ public void testMigrationFailure() {
+ AppSearchResult<Void> expectedResult = AppSearchResult.newFailedResult(
+ AppSearchResult.RESULT_INTERNAL_ERROR, "This is errorMessage.");
+ SetSchemaResponse.MigrationFailure migrationFailure =
+ new SetSchemaResponse.MigrationFailure("testNamespace", "testId",
+ "testSchemaType", expectedResult);
+ assertThat(migrationFailure.getNamespace()).isEqualTo("testNamespace");
+ assertThat(migrationFailure.getSchemaType()).isEqualTo("testSchemaType");
+ assertThat(migrationFailure.getDocumentId()).isEqualTo("testId");
+ assertThat(migrationFailure.getAppSearchResult()).isEqualTo(expectedResult);
+ assertThat(migrationFailure.toString()).isEqualTo("MigrationFailure { schemaType:"
+ + " testSchemaType, namespace: testNamespace, documentId: testId, "
+ + "appSearchResult: [FAILURE(2)]: This is errorMessage.}");
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/StorageInfoCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/StorageInfoCtsTest.java
new file mode 100644
index 0000000..f4da5e3
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/StorageInfoCtsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.StorageInfo;
+
+import org.junit.Test;
+
+public class StorageInfoCtsTest {
+
+ @Test
+ public void testBuildStorageInfo() {
+ StorageInfo storageInfo =
+ new StorageInfo.Builder()
+ .setAliveDocumentsCount(10)
+ .setSizeBytes(1L)
+ .setAliveNamespacesCount(10)
+ .build();
+
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(10);
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(1L);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(10);
+ }
+
+ @Test
+ public void testBuildStorageInfo_withDefaults() {
+ StorageInfo storageInfo = new StorageInfo.Builder().build();
+
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(0);
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0L);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(0);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/customer/CustomerDocumentTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/customer/CustomerDocumentTest.java
new file mode 100644
index 0000000..c192d96
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/customer/CustomerDocumentTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.app.customer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.GenericDocument;
+
+import org.junit.Test;
+
+/**
+ * Tests that {@link GenericDocument} and {@link GenericDocument.Builder} are extendable by
+ * developers.
+ *
+ * <p>This class is intentionally in a different package than {@link GenericDocument} to make sure
+ * there are no package-private methods required for external developers to add custom types.
+ */
+public class CustomerDocumentTest {
+
+ private static final byte[] BYTE_ARRAY1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
+ private static final byte[] BYTE_ARRAY2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
+ private static final GenericDocument DOCUMENT_PROPERTIES1 = new GenericDocument
+ .Builder<>("namespace", "sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+ .build();
+ private static final GenericDocument DOCUMENT_PROPERTIES2 = new GenericDocument
+ .Builder<>("namespace", "sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+ .build();
+
+ @Test
+ public void testBuildCustomerDocument() {
+ CustomerDocument customerDocument = new CustomerDocument.Builder("namespace", "id1")
+ .setScore(1)
+ .setCreationTimestampMillis(0)
+ .setPropertyLong("longKey1", 1L, 2L, 3L)
+ .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
+ .setPropertyBoolean("booleanKey1", true, false, true)
+ .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
+ .setPropertyBytes("byteKey1", BYTE_ARRAY1, BYTE_ARRAY2)
+ .setPropertyDocument("documentKey1", DOCUMENT_PROPERTIES1, DOCUMENT_PROPERTIES2)
+ .build();
+
+ assertThat(customerDocument.getNamespace()).isEqualTo("namespace");
+ assertThat(customerDocument.getId()).isEqualTo("id1");
+ assertThat(customerDocument.getSchemaType()).isEqualTo("customerDocument");
+ assertThat(customerDocument.getScore()).isEqualTo(1);
+ assertThat(customerDocument.getCreationTimestampMillis()).isEqualTo(0L);
+ assertThat(customerDocument.getPropertyLongArray("longKey1")).asList()
+ .containsExactly(1L, 2L, 3L);
+ assertThat(customerDocument.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
+ .containsExactly(1.0, 2.0, 3.0);
+ assertThat(customerDocument.getPropertyBooleanArray("booleanKey1")).asList()
+ .containsExactly(true, false, true);
+ assertThat(customerDocument.getPropertyStringArray("stringKey1")).asList()
+ .containsExactly("test-value1", "test-value2", "test-value3");
+ assertThat(customerDocument.getPropertyBytesArray("byteKey1")).asList()
+ .containsExactly(BYTE_ARRAY1, BYTE_ARRAY2);
+ assertThat(customerDocument.getPropertyDocumentArray("documentKey1")).asList()
+ .containsExactly(DOCUMENT_PROPERTIES1, DOCUMENT_PROPERTIES2);
+ }
+
+ /**
+ * An example document type for test purposes, defined outside of
+ * {@link GenericDocument} (the way an external developer would define
+ * it).
+ */
+ private static class CustomerDocument extends GenericDocument {
+ private CustomerDocument(GenericDocument document) {
+ super(document);
+ }
+
+ public static class Builder extends GenericDocument.Builder<CustomerDocument.Builder> {
+ private Builder(@NonNull String namespace, @NonNull String id) {
+ super(namespace, id, "customerDocument");
+ }
+
+ @Override
+ @NonNull
+ public CustomerDocument build() {
+ return new CustomerDocument(super.build());
+ }
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/customer/EmailDocument.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/customer/EmailDocument.java
new file mode 100644
index 0000000..428781e
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/customer/EmailDocument.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.cts.app.customer;
+
+import androidx.appsearch.annotation.Document;
+import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
+
+@Document
+public final class EmailDocument {
+ @Document.Namespace
+ public String namespace;
+
+ @Document.Id
+ public String id;
+
+ @Document.StringProperty(indexingType = StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ public String subject;
+
+ @Document.StringProperty(indexingType = StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ public String body;
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/exceptions/AppSearchExceptionCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/exceptions/AppSearchExceptionCtsTest.java
new file mode 100644
index 0000000..a732033
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/exceptions/AppSearchExceptionCtsTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.cts.exceptions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.exceptions.AppSearchException;
+
+import org.junit.Test;
+
+public class AppSearchExceptionCtsTest {
+ @Test
+ public void testNoMessageException() {
+ AppSearchException e = new AppSearchException(AppSearchResult.RESULT_IO_ERROR);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_IO_ERROR);
+
+ AppSearchResult<?> result = e.toAppSearchResult();
+ assertThat(result.isSuccess()).isFalse();
+ assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_IO_ERROR);
+ assertThat(result.getErrorMessage()).isNull();
+ }
+
+ @Test
+ public void testExceptionWithMessage() {
+ AppSearchException e =
+ new AppSearchException(AppSearchResult.RESULT_NOT_FOUND, "ERROR!");
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ AppSearchResult<?> result = e.toAppSearchResult();
+ assertThat(result.isSuccess()).isFalse();
+ assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ assertThat(result.getErrorMessage()).isEqualTo("ERROR!");
+ }
+
+ @Test
+ public void testExceptionWithThrowable() {
+ IllegalArgumentException throwable = new IllegalArgumentException("You can't do that!");
+ AppSearchException e = new AppSearchException(AppSearchResult.RESULT_INVALID_ARGUMENT,
+ "ERROR!", throwable);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_INVALID_ARGUMENT);
+ assertThat(e.getCause()).isEqualTo(throwable);
+
+ AppSearchResult<?> result = e.toAppSearchResult();
+ assertThat(result.isSuccess()).isFalse();
+ assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_INVALID_ARGUMENT);
+ assertThat(result.getErrorMessage()).isEqualTo("ERROR!");
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/exceptions/IllegalSchemaExceptionTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/exceptions/IllegalSchemaExceptionTest.java
new file mode 100644
index 0000000..67a1234
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/exceptions/IllegalSchemaExceptionTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.exceptions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class IllegalSchemaExceptionTest {
+ @Test
+ public void testExceptionWithMessage() {
+ IllegalSchemaException e = new IllegalSchemaException("ERROR MESSAGE");
+ assertThat(e.getMessage()).isEqualTo("ERROR MESSAGE");
+ assertThat(e).isInstanceOf(IllegalArgumentException.class);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/util/BundleUtilTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/util/BundleUtilTest.java
index 389c3ee..55b7638 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/util/BundleUtilTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/util/BundleUtilTest.java
@@ -201,6 +201,29 @@
assertThat(BundleUtil.deepHashCode(b1)).isNotEqualTo(BundleUtil.deepHashCode(b2));
}
+ @Test
+ public void testDeepHashCode_differentKeys() {
+ Bundle[] inputs = new Bundle[2];
+ for (int i = 0; i < 2; i++) {
+ Bundle b = new Bundle();
+ b.putString("key" + i, "value");
+ inputs[i] = b;
+ }
+ assertThat(BundleUtil.deepHashCode(inputs[0]))
+ .isNotEqualTo(BundleUtil.deepHashCode(inputs[1]));
+ }
+
+ @Test
+ public void testDeepCopy() {
+ Bundle input = createThoroughBundle();
+ Bundle output = BundleUtil.deepCopy(input);
+ assertThat(input).isNotSameInstanceAs(output);
+ assertThat(BundleUtil.deepEquals(input, output)).isTrue();
+
+ output.getIntegerArrayList("integerArrayList").add(5);
+ assertThat(BundleUtil.deepEquals(input, output)).isFalse();
+ }
+
private static Bundle createThoroughBundle() {
Bundle toy1 = new Bundle();
toy1.putString("a", "a");
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/util/IndentingStringBuilderTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/util/IndentingStringBuilderTest.java
new file mode 100644
index 0000000..28ad13e
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/util/IndentingStringBuilderTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Test;
+
+public class IndentingStringBuilderTest {
+ @Test
+ public void testAppendIndentedStrings() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ stringBuilder
+ .increaseIndentLevel()
+ .append("\nIndentLevel1\nIndentLevel1\n")
+ .decreaseIndentLevel()
+ .append("IndentLevel0,\n");
+
+ String str = stringBuilder.toString();
+ String expectedString = "\n IndentLevel1\n IndentLevel1\nIndentLevel0,\n";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+
+ @Test
+ public void testDecreaseIndentLevel_throwsException() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+
+ Exception e = assertThrows(IllegalStateException.class,
+ () -> stringBuilder.decreaseIndentLevel());
+ assertThat(e).hasMessageThat().contains("Cannot set indent level below 0.");
+ }
+
+ @Test
+ public void testAppendIndentedObjects() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ Object stringProperty = "String";
+ Object longProperty = 1L;
+ Object booleanProperty = true;
+
+ stringBuilder
+ .append(stringProperty)
+ .append("\n")
+ .increaseIndentLevel()
+ .append(longProperty)
+ .append("\n")
+ .decreaseIndentLevel()
+ .append(booleanProperty);
+
+ String str = stringBuilder.toString();
+ String expectedString = "String\n 1\ntrue";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+
+ @Test
+ public void testAppendIndentedStrings_doesNotIndentLineBreak() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+
+ stringBuilder
+ .append("\n")
+ .increaseIndentLevel()
+ .append("\n\n")
+ .decreaseIndentLevel()
+ .append("\n");
+
+ String str = stringBuilder.toString();
+ String expectedString = "\n\n\n\n";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/AppSearchDocument.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/AppSearchDocument.java
deleted file mode 100644
index a4243eb..0000000
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/AppSearchDocument.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// @exportToFramework:skipFile()
-package androidx.appsearch.annotation;
-
-import androidx.appsearch.app.AppSearchSchema;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marks a class as a data class known to AppSearch.
- *
- * <p>Each field annotated with {@link Property @Property} will become an AppSearch searchable
- * property. Fields annotated with other annotations included here (like {@link Uri @Uri}) will have
- * the special behaviour described in that annotation. All other members (those which do not have
- * any of these annotations) will be ignored by AppSearch and will not be persisted or set.
- *
- * <p>Each AppSearch field, whether marked by {@link Property @Property} or by one of the other
- * annotations here, must meet at least one the following conditions:
- * <ol>
- * <li>There must be a getter named get<Fieldname> in the class (with package-private
- * visibility or greater), or
- * <li>The field itself must have package-private visibility or greater.
- * </ol>
- *
- * <p>The field must also meet at least one of the following conditions:
- * <ol>
- * <li>There must be a setter named set<Fieldname> in the class (with package-private
- * visibility or greater), or
- * <li>The field itself must be mutable (non-final) and have package-private visibility or
- * greater, or
- * <li>There must be a constructor that accepts all fields not meeting condition 1. and 2. as
- * parameters. That constructor must have package-private visibility or greater. It may
- * also accept fields that do meet conditions 1 and 2, in which case the constructor will be
- * used to populate those fields instead of methods 1 and 2.
- * </ol>
- *
- * <p>The class must also have exactly one member annotated with {@link Uri @Uri}.
- */
-@Documented
-@Retention(RetentionPolicy.CLASS)
-@Target(ElementType.TYPE)
-public @interface AppSearchDocument {
- /**
- * Marks a member field of a document as the document's URI.
- *
- * <p>Indexing a document with a particular {@link java.net.URI} replaces any existing
- * documents with the same URI in that namespace.
- *
- * <p>A document must have exactly one such field, and it must be of type {@link String} or
- * {@link android.net.Uri}.
- *
- * <p>See the class description of {@link AppSearchDocument} for other requirements (i.e. it
- * must be visible, or have a visible getter and setter, or be exposed through a visible
- * constructor).
- */
- @Documented
- @Retention(RetentionPolicy.CLASS)
- @Target(ElementType.FIELD)
- @interface Uri {}
-
- /**
- * Marks a member field of a document as the document's namespace.
- *
- * <p>The namespace is an arbitrary user-provided string that can be used to group documents
- * during querying or deletion. Indexing a document with a particular {@link java.net.URI}
- * replaces any existing documents with the same URI in that namespace.
- *
- * <p>This field is not required. If not present or not set, the document will be assigned to
- * the default namespace, {@link androidx.appsearch.app.GenericDocument#DEFAULT_NAMESPACE}.
- *
- * <p>If present, the field must be of type {@code String}.
- *
- * <p>See the class description of {@link AppSearchDocument} for other requirements (i.e. if
- * present it must be visible, or have a visible getter and setter, or be exposed through a
- * visible constructor).
- */
- @Documented
- @Retention(RetentionPolicy.CLASS)
- @Target(ElementType.FIELD)
- @interface Namespace {}
-
- /**
- * Marks a member field of a document as the document's creation timestamp.
- *
- * <p>The creation timestamp is used for document expiry (see {@link TtlMillis}) and as one
- * of the sort options for queries.
- *
- * <p>This field is not required. If not present or not set, the document will be assigned
- * the current timestamp as its creation timestamp.
- *
- * <p>If present, the field must be of type {@code long} or {@link Long}.
- *
- * <p>See the class description of {@link AppSearchDocument} for other requirements (i.e. if
- * present it must be visible, or have a visible getter and setter, or be exposed through a
- * visible constructor).
- */
- @Documented
- @Retention(RetentionPolicy.CLASS)
- @Target(ElementType.FIELD)
- @interface CreationTimestampMillis {}
-
- /**
- * Marks a member field of a document as the document's time-to-live (TTL).
- *
- * <p>The document will be automatically deleted {@link TtlMillis} milliseconds after
- * {@link CreationTimestampMillis}.
- *
- * <p>This field is not required. If not present or not set, the document will never expire.
- *
- * <p>If present, the field must be of type {@code long} or {@link Long}.
- *
- * <p>See the class description of {@link AppSearchDocument} for other requirements (i.e. if
- * present it must be visible, or have a visible getter and setter, or be exposed through a
- * visible constructor).
- */
- @Documented
- @Retention(RetentionPolicy.CLASS)
- @Target(ElementType.FIELD)
- @interface TtlMillis {}
-
- /**
- * Marks a member field of a document as the document's query-independent score.
- *
- * <p>The score is a query-independent measure of the document's quality, relative to other
- * documents of the same type. It is one of the sort options for queries.
- *
- * <p>This field is not required. If not present or not set, the document will have a score
- * of 0.
- *
- * <p>If present, the field must be of type {@code int} or {@link Integer}.
- *
- * <p>See the class description of {@link AppSearchDocument} for other requirements (i.e. if
- * present it must be visible, or have a visible getter and setter, or be exposed through a
- * visible constructor).
- */
- @Documented
- @Retention(RetentionPolicy.CLASS)
- @Target(ElementType.FIELD)
- @interface Score {}
-
- /**
- * Configures a member field of a class as a property known to AppSearch.
- *
- * <p>Properties contain the document's data. They may be indexed or non-indexed (the default).
- * Only indexed properties can be searched for in queries. There is a limit of
- * {@link androidx.appsearch.app.GenericDocument#getMaxIndexedProperties} indexed properties in
- * one document.
- */
- @Documented
- @Retention(RetentionPolicy.CLASS)
- @Target(ElementType.FIELD)
- @interface Property {
- /**
- * The name of this property. This string is used to query against this property.
- *
- * <p>If not specified, the name of the field in the code will be used instead.
- */
- String name() default "";
-
- /**
- * Configures how tokens should be extracted from this property.
- *
- * <p>If not specified, defaults to {@link
- * AppSearchSchema.PropertyConfig#TOKENIZER_TYPE_PLAIN} (the field will be tokenized
- * along word boundaries as plain text).
- */
- @AppSearchSchema.PropertyConfig.TokenizerType int tokenizerType()
- default AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN;
-
- /**
- * Configures how a property should be indexed so that it can be retrieved by queries.
- *
- * <p>If not specified, defaults to {@link
- * AppSearchSchema.PropertyConfig#INDEXING_TYPE_NONE} (the field will not be indexed and
- * cannot be queried).
- * TODO(b/171857731) renamed to TermMatchType when using String-specific indexing config.
- */
- @AppSearchSchema.PropertyConfig.IndexingType int indexingType()
- default AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
-
- /**
- * Configures whether this property must be specified for the document to be valid.
- *
- * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
- *
- * <p>Please make sure you understand the consequences of required fields on
- * {@link androidx.appsearch.app.AppSearchSession#setSchema schema migration} before setting
- * this attribute to {@code true}.
- */
- boolean required() default false;
- }
-
- /**
- * The schema name of this type.
- *
- * <p>This string is the key to which the complete schema definition is associated in the
- * AppSearch database. It can be specified to replace an existing type with a new definition.
- *
- * <p>If not specified, it will be automatically set to the simple name of the annotated class.
- */
- String name() default "";
-}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
new file mode 100644
index 0000000..527127f
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.annotation;
+
+import androidx.appsearch.app.AppSearchSchema;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a class as an entity known to AppSearch containing a data record.
+ *
+ * <p>Each field annotated with one of the Property annotations will become an AppSearch searchable
+ * property. Fields annotated with other annotations included here (like {@link Id @Id}) will have
+ * the special behaviour described in that annotation. All other members (those which do not have
+ * any of these annotations) will be ignored by AppSearch and will not be persisted or set.
+ *
+ * <p>Each AppSearch annotated field must meet at least one the following conditions:
+ * <ol>
+ * <li>There must be a getter named get<Fieldname> in the class (with package-private
+ * visibility or greater), or
+ * <li>The field itself must have package-private visibility or greater.
+ * </ol>
+ *
+ * <p>The field must also meet at least one of the following conditions:
+ * <ol>
+ * <li>There must be a setter named {@code set<FieldName>(arg)} in the class (with
+ * package-private visibility or greater), or
+ * <li>There must be a setter named {@code fieldname(arg)} in the class (with package-private
+ * visibility or greater), or
+ * <li>The field itself must be mutable (non-final) and have package-private visibility or
+ * greater, or
+ * <li>There must be a constructor that accepts all fields not meeting condition 1. and 2. as
+ * parameters. That constructor must have package-private visibility or greater. It may
+ * also accept fields that do meet conditions 1 and 2, in which case the constructor will be
+ * used to populate those fields instead of methods 1 and 2.
+ * </ol>
+ *
+ * <p>Fields may be named according to any of the following conventions:
+ * <ul>
+ * <li>exampleName
+ * <li>mExampleName
+ * <li>_exampleName
+ * <li>exampleName_
+ * </ul>
+ *
+ * <p>In all of the above cases, the default property name will be "exampleName", the allowed
+ * getters are {@code getExampleName()} or {@code exampleName()}, the allowed setters are {@code
+ * setExampleName(arg)} or {@code exampleName(arg)}, and the expected constructor parameter for
+ * the field is "exampleName".
+ *
+ * <p>The class must also have exactly one member annotated with {@link Id @Id}.
+ *
+ * <p>Properties contain the document's data. They may be indexed or non-indexed (the default).
+ * Only indexed properties can be searched for in queries. There is a limit of
+ * {@link androidx.appsearch.app.GenericDocument#getMaxIndexedProperties} indexed properties in
+ * one document.
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface Document {
+ /**
+ * The schema name of this type.
+ *
+ * <p>This string is the key to which the complete schema definition is associated in the
+ * AppSearch database. It can be specified to replace an existing type with a new definition.
+ *
+ * <p>If not specified, it will be automatically set to the simple name of the annotated class.
+ */
+ String name() default "";
+
+ /**
+ * Marks a member field of a document as the document's unique identifier (ID).
+ *
+ * <p>Indexing a document with a particular ID replaces any existing documents with the same
+ * ID in that namespace.
+ *
+ * <p>A document must have exactly one such field, and it must be of type {@link String}.
+ *
+ * <p>See the class description of {@link Document} for other requirements (i.e. it
+ * must be visible, or have a visible getter and setter, or be exposed through a visible
+ * constructor).
+ */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface Id {}
+
+ /**
+ * Marks a member field of a document as the document's namespace.
+ *
+ * <p>The namespace is an arbitrary user-provided string that can be used to group documents
+ * during querying or deletion. Indexing a document with a particular ID replaces any existing
+ * documents with the same ID in that namespace.
+ *
+ * <p>A document must have exactly one such field, and it must be of type {@link String}.
+ *
+ * <p>See the class description of {@link Document} for other requirements (i.e. if
+ * present it must be visible, or have a visible getter and setter, or be exposed through a
+ * visible constructor).
+ */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface Namespace {}
+
+ /**
+ * Marks a member field of a document as the document's creation timestamp.
+ *
+ * <p>The creation timestamp is used for document expiry (see {@link TtlMillis}) and as one
+ * of the sort options for queries.
+ *
+ * <p>This field is not required. If not present or not set, the document will be assigned
+ * the current timestamp as its creation timestamp.
+ *
+ * <p>If present, the field must be of type {@code long} or {@link Long}.
+ *
+ * <p>See the class description of {@link Document} for other requirements (i.e. if
+ * present it must be visible, or have a visible getter and setter, or be exposed through a
+ * visible constructor).
+ */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface CreationTimestampMillis {}
+
+ /**
+ * Marks a member field of a document as the document's time-to-live (TTL).
+ *
+ * <p>The document will be automatically deleted {@link TtlMillis} milliseconds after
+ * {@link CreationTimestampMillis}.
+ *
+ * <p>This field is not required. If not present or not set, the document will never expire.
+ *
+ * <p>If present, the field must be of type {@code long} or {@link Long}.
+ *
+ * <p>See the class description of {@link Document} for other requirements (i.e. if
+ * present it must be visible, or have a visible getter and setter, or be exposed through a
+ * visible constructor).
+ */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface TtlMillis {}
+
+ /**
+ * Marks a member field of a document as the document's query-independent score.
+ *
+ * <p>The score is a query-independent measure of the document's quality, relative to other
+ * documents of the same type. It is one of the sort options for queries.
+ *
+ * <p>This field is not required. If not present or not set, the document will have a score
+ * of 0.
+ *
+ * <p>If present, the field must be of type {@code int} or {@link Integer}.
+ *
+ * <p>See the class description of {@link Document} for other requirements (i.e. if
+ * present it must be visible, or have a visible getter and setter, or be exposed through a
+ * visible constructor).
+ */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface Score {}
+
+ /** Configures a string member field of a class as a property known to AppSearch. */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface StringProperty {
+ /**
+ * The name of this property. This string is used to query against this property.
+ *
+ * <p>If not specified, the name of the field in the code will be used instead.
+ */
+ String name() default "";
+
+ /**
+ * Configures how tokens should be extracted from this property.
+ *
+ * <p>If not specified, defaults to {@link
+ * AppSearchSchema.StringPropertyConfig#TOKENIZER_TYPE_PLAIN} (the field will be tokenized
+ * along word boundaries as plain text).
+ */
+ @AppSearchSchema.StringPropertyConfig.TokenizerType int tokenizerType()
+ default AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
+
+ /**
+ * Configures how a property should be indexed so that it can be retrieved by queries.
+ *
+ * <p>If not specified, defaults to {@link
+ * AppSearchSchema.StringPropertyConfig#INDEXING_TYPE_NONE} (the field will not be indexed
+ * and cannot be queried).
+ * TODO(b/171857731) renamed to TermMatchType when using String-specific indexing config.
+ */
+ @AppSearchSchema.StringPropertyConfig.IndexingType int indexingType()
+ default AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
+
+ /**
+ * Configures whether this property must be specified for the document to be valid.
+ *
+ * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
+ *
+ * <p>Please make sure you understand the consequences of required fields on
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema schema migration} before setting
+ * this attribute to {@code true}.
+ */
+ boolean required() default false;
+ }
+
+ /**
+ * Configures a member field of a class as a property known to AppSearch.
+ *
+ * <p>Field's data class is required to be annotated with {@link Document}.
+ */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface DocumentProperty {
+ /**
+ * The name of this property. This string is used to query against this property.
+ *
+ * <p>If not specified, the name of the field in the code will be used instead.
+ */
+ String name() default "";
+
+ /**
+ * Configures whether fields in the nested document should be indexed.
+ *
+ * <p>If false, the nested document's properties are not indexed regardless of its own
+ * schema.
+ */
+ boolean indexNestedProperties() default false;
+
+ /**
+ * Configures whether this property must be specified for the document to be valid.
+ *
+ * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
+ *
+ * <p>Please make sure you understand the consequences of required fields on
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema schema migration} before setting
+ * this attribute to {@code true}.
+ */
+ boolean required() default false;
+ }
+
+ /** Configures a 64-bit integer field of a class as a property known to AppSearch. */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface LongProperty {
+ /**
+ * The name of this property. This string is used to query against this property.
+ *
+ * <p>If not specified, the name of the field in the code will be used instead.
+ */
+ String name() default "";
+
+ /**
+ * Configures whether this property must be specified for the document to be valid.
+ *
+ * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
+ *
+ * <p>Please make sure you understand the consequences of required fields on
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema schema migration} before setting
+ * this attribute to {@code true}.
+ */
+ boolean required() default false;
+ }
+
+ /**
+ * Configures a double-precision decimal number field of a class as a property known to
+ * AppSearch.
+ */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface DoubleProperty {
+ /**
+ * The name of this property. This string is used to query against this property.
+ *
+ * <p>If not specified, the name of the field in the code will be used instead.
+ */
+ String name() default "";
+
+ /**
+ * Configures whether this property must be specified for the document to be valid.
+ *
+ * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
+ *
+ * <p>Please make sure you understand the consequences of required fields on
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema schema migration} before setting
+ * this attribute to {@code true}.
+ */
+ boolean required() default false;
+ }
+
+ /** Configures a boolean member field of a class as a property known to AppSearch. */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface BooleanProperty {
+ /**
+ * The name of this property. This string is used to query against this property.
+ *
+ * <p>If not specified, the name of the field in the code will be used instead.
+ */
+ String name() default "";
+
+ /**
+ * Configures whether this property must be specified for the document to be valid.
+ *
+ * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
+ *
+ * <p>Please make sure you understand the consequences of required fields on
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema schema migration} before setting
+ * this attribute to {@code true}.
+ */
+ boolean required() default false;
+ }
+
+ /** Configures a byte array member field of a class as a property known to AppSearch. */
+ @Documented
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @interface BytesProperty {
+ /**
+ * The name of this property. This string is used to query against this property.
+ *
+ * <p>If not specified, the name of the field in the code will be used instead.
+ */
+ String name() default "";
+
+ /**
+ * Configures whether this property must be specified for the document to be valid.
+ *
+ * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
+ *
+ * <p>Please make sure you understand the consequences of required fields on
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema schema migration} before setting
+ * this attribute to {@code true}.
+ */
+ boolean required() default false;
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBatchResult.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBatchResult.java
index 302545b..4b6ee7c 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBatchResult.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBatchResult.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// @exportToFramework:skipFile()
package androidx.appsearch.app;
import androidx.annotation.NonNull;
@@ -21,24 +20,39 @@
import androidx.collection.ArrayMap;
import androidx.core.util.Preconditions;
+import java.util.Collections;
import java.util.Map;
/**
- * Provides access to multiple {@link AppSearchResult}s from a batch operation accepting multiple
- * inputs.
+ * Provides results for AppSearch batch operations which encompass multiple documents.
*
- * @param <KeyType> The type of the keys for {@link #getSuccesses} and {@link #getFailures}.
- * @param <ValueType> The type of result objects associated with the keys.
+ * <p>Individual results of a batch operation are separated into two maps: one for successes and
+ * one for failures. For successes, {@link #getSuccesses()} will return a map of keys to
+ * instances of the value type. For failures, {@link #getFailures()} will return a map of keys to
+ * {@link AppSearchResult} objects.
+ *
+ * <p>Alternatively, {@link #getAll()} returns a map of keys to {@link AppSearchResult} objects for
+ * both successes and failures.
+ *
+ * @param <KeyType> The type of the keys for which the results will be reported.
+ * @param <ValueType> The type of the result objects for successful results.
+ *
+ * @see AppSearchSession#put
+ * @see AppSearchSession#getByDocumentId
+ * @see AppSearchSession#remove
*/
public final class AppSearchBatchResult<KeyType, ValueType> {
@NonNull private final Map<KeyType, ValueType> mSuccesses;
@NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures;
+ @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mAll;
AppSearchBatchResult(
@NonNull Map<KeyType, ValueType> successes,
- @NonNull Map<KeyType, AppSearchResult<ValueType>> failures) {
- mSuccesses = successes;
- mFailures = failures;
+ @NonNull Map<KeyType, AppSearchResult<ValueType>> failures,
+ @NonNull Map<KeyType, AppSearchResult<ValueType>> all) {
+ mSuccesses = Preconditions.checkNotNull(successes);
+ mFailures = Preconditions.checkNotNull(failures);
+ mAll = Preconditions.checkNotNull(all);
}
/** Returns {@code true} if this {@link AppSearchBatchResult} has no failures. */
@@ -47,25 +61,40 @@
}
/**
- * Returns a {@link Map} of all successful keys mapped to the successful
- * {@link AppSearchResult}s they produced.
+ * Returns a {@link Map} of keys mapped to instances of the value type for all successful
+ * individual results.
+ *
+ * <p>Example: {@link AppSearchSession#getByDocumentId} returns an {@link AppSearchBatchResult}.
+ * Each key (the document ID, of {@code String} type) will map to a {@link GenericDocument}
+ * object.
*
* <p>The values of the {@link Map} will not be {@code null}.
*/
@NonNull
public Map<KeyType, ValueType> getSuccesses() {
- return mSuccesses;
+ return Collections.unmodifiableMap(mSuccesses);
}
/**
- * Returns a {@link Map} of all failed keys mapped to the failed {@link AppSearchResult}s they
- * produced.
+ * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all
+ * failed individual results.
*
* <p>The values of the {@link Map} will not be {@code null}.
*/
@NonNull
public Map<KeyType, AppSearchResult<ValueType>> getFailures() {
- return mFailures;
+ return Collections.unmodifiableMap(mFailures);
+ }
+
+ /**
+ * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all
+ * individual results.
+ *
+ * <p>The values of the {@link Map} will not be {@code null}.
+ */
+ @NonNull
+ public Map<KeyType, AppSearchResult<ValueType>> getAll() {
+ return Collections.unmodifiableMap(mAll);
}
/**
@@ -87,54 +116,78 @@
/**
* Builder for {@link AppSearchBatchResult} objects.
*
- * @param <KeyType> The type of keys.
- * @param <ValueType> The type of result objects associated with the keys.
- * @hide
+ * @param <KeyType> The type of the keys for which the results will be reported.
+ * @param <ValueType> The type of the result objects for successful results.
*/
public static final class Builder<KeyType, ValueType> {
- private final Map<KeyType, ValueType> mSuccesses = new ArrayMap<>();
- private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();
+ private ArrayMap<KeyType, ValueType> mSuccesses = new ArrayMap<>();
+ private ArrayMap<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();
+ private ArrayMap<KeyType, AppSearchResult<ValueType>> mAll = new ArrayMap<>();
private boolean mBuilt = false;
/**
- * Associates the {@code key} with the given successful return value.
+ * Associates the {@code key} with the provided successful return value.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
+ *
+ * <p>This is a convenience function which is equivalent to
+ * {@code setResult(key, AppSearchResult.newSuccessfulResult(value))}.
+ *
+ * @param key The key to associate the result with; usually corresponds to some
+ * identifier from the input like an ID or name.
+ * @param value An optional value to associate with the successful result of the operation
+ * being performed.
*/
+ @SuppressWarnings("MissingGetterMatchingBuilder") // See getSuccesses
@NonNull
public Builder<KeyType, ValueType> setSuccess(
- @NonNull KeyType key, @Nullable ValueType result) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
+ @NonNull KeyType key, @Nullable ValueType value) {
Preconditions.checkNotNull(key);
- return setResult(key, AppSearchResult.newSuccessfulResult(result));
+ resetIfBuilt();
+ return setResult(key, AppSearchResult.newSuccessfulResult(value));
}
/**
- * Associates the {@code key} with the given failure code and error message.
+ * Associates the {@code key} with the provided failure code and error message.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
+ *
+ * <p>This is a convenience function which is equivalent to
+ * {@code setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage))}.
+ *
+ * @param key The key to associate the result with; usually corresponds to some
+ * identifier from the input like an ID or name.
+ * @param resultCode One of the constants documented in
+ * {@link AppSearchResult#getResultCode}.
+ * @param errorMessage An optional string describing the reason or nature of the failure.
*/
+ @SuppressWarnings("MissingGetterMatchingBuilder") // See getFailures
@NonNull
public Builder<KeyType, ValueType> setFailure(
@NonNull KeyType key,
@AppSearchResult.ResultCode int resultCode,
@Nullable String errorMessage) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
+ resetIfBuilt();
return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage));
}
/**
- * Associates the {@code key} with the given {@code result}.
+ * Associates the {@code key} with the provided {@code result}.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
+ *
+ * @param key The key to associate the result with; usually corresponds to some
+ * identifier from the input like an ID or name.
+ * @param result The result to associate with the key.
*/
+ @SuppressWarnings("MissingGetterMatchingBuilder") // See getAll
@NonNull
public Builder<KeyType, ValueType> setResult(
@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(result);
+ resetIfBuilt();
if (result.isSuccess()) {
mSuccesses.put(key, result.getResultValue());
mFailures.remove(key);
@@ -142,15 +195,26 @@
mFailures.put(key, result);
mSuccesses.remove(key);
}
+ mAll.put(key, result);
return this;
}
- /** Builds an {@link AppSearchBatchResult} from the contents of this {@link Builder}. */
+ /**
+ * Builds an {@link AppSearchBatchResult} object from the contents of this {@link Builder}.
+ */
@NonNull
public AppSearchBatchResult<KeyType, ValueType> build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
mBuilt = true;
- return new AppSearchBatchResult<>(mSuccesses, mFailures);
+ return new AppSearchBatchResult<>(mSuccesses, mFailures, mAll);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mSuccesses = new ArrayMap<>(mSuccesses);
+ mFailures = new ArrayMap<>(mFailures);
+ mAll = new ArrayMap<>(mAll);
+ mBuilt = false;
+ }
}
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchEmail.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchEmail.java
deleted file mode 100644
index 9f7aa0e..0000000
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchEmail.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app;
-
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
-
-/**
- * Encapsulates a {@link GenericDocument} that represent an email.
- *
- * <p>This class is a higher level implement of {@link GenericDocument}.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class AppSearchEmail extends GenericDocument {
- /** The name of the schema type for {@link AppSearchEmail} documents.*/
- public static final String SCHEMA_TYPE = "builtin:Email";
-
- private static final String KEY_FROM = "from";
- private static final String KEY_TO = "to";
- private static final String KEY_CC = "cc";
- private static final String KEY_BCC = "bcc";
- private static final String KEY_SUBJECT = "subject";
- private static final String KEY_BODY = "body";
-
- public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new PropertyConfig.Builder(KEY_FROM)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(new PropertyConfig.Builder(KEY_TO)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(new PropertyConfig.Builder(KEY_CC)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(new PropertyConfig.Builder(KEY_BCC)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(new PropertyConfig.Builder(KEY_SUBJECT)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(new PropertyConfig.Builder(KEY_BODY)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).build();
-
- /**
- * Creates a new {@link AppSearchEmail} from the contents of an existing
- * {@link GenericDocument}.
- *
- * @param document The {@link GenericDocument} containing the email content.
- */
- public AppSearchEmail(@NonNull GenericDocument document) {
- super(document);
- }
-
- /**
- * Gets the from address of {@link AppSearchEmail}.
- *
- * @return The subject of {@link AppSearchEmail} or {@code null} if it's not been set yet.
- */
- @Nullable
- public String getFrom() {
- return getPropertyString(KEY_FROM);
- }
-
- /**
- * Gets the destination addresses of {@link AppSearchEmail}.
- *
- * @return The destination addresses of {@link AppSearchEmail} or {@code null} if it's not
- * been set yet.
- */
- @Nullable
- public String[] getTo() {
- return getPropertyStringArray(KEY_TO);
- }
-
- /**
- * Gets the CC list of {@link AppSearchEmail}.
- *
- * @return The CC list of {@link AppSearchEmail} or {@code null} if it's not been set yet.
- */
- @Nullable
- public String[] getCc() {
- return getPropertyStringArray(KEY_CC);
- }
-
- /**
- * Gets the BCC list of {@link AppSearchEmail}.
- *
- * @return The BCC list of {@link AppSearchEmail} or {@code null} if it's not been set yet.
- */
- @Nullable
- public String[] getBcc() {
- return getPropertyStringArray(KEY_BCC);
- }
-
- /**
- * Gets the subject of {@link AppSearchEmail}.
- *
- * @return The value subject of {@link AppSearchEmail} or {@code null} if it's not been set yet.
- */
- @Nullable
- public String getSubject() {
- return getPropertyString(KEY_SUBJECT);
- }
-
- /**
- * Gets the body of {@link AppSearchEmail}.
- *
- * @return The body of {@link AppSearchEmail} or {@code null} if it's not been set yet.
- */
- @Nullable
- public String getBody() {
- return getPropertyString(KEY_BODY);
- }
-
- /**
- * The builder class for {@link AppSearchEmail}.
- */
- public static class Builder extends GenericDocument.Builder<AppSearchEmail.Builder> {
-
- /**
- * Creates a new {@link AppSearchEmail.Builder}
- *
- * @param uri The Uri of the Email.
- */
- public Builder(@NonNull String uri) {
- super(uri, SCHEMA_TYPE);
- }
-
- /**
- * Sets the from address of {@link AppSearchEmail}
- */
- @NonNull
- public AppSearchEmail.Builder setFrom(@NonNull String from) {
- setPropertyString(KEY_FROM, from);
- return this;
- }
-
- /**
- * Sets the destination address of {@link AppSearchEmail}
- */
- @NonNull
- public AppSearchEmail.Builder setTo(@NonNull String... to) {
- setPropertyString(KEY_TO, to);
- return this;
- }
-
- /**
- * Sets the CC list of {@link AppSearchEmail}
- */
- @NonNull
- public AppSearchEmail.Builder setCc(@NonNull String... cc) {
- setPropertyString(KEY_CC, cc);
- return this;
- }
-
- /**
- * Sets the BCC list of {@link AppSearchEmail}
- */
- @NonNull
- public AppSearchEmail.Builder setBcc(@NonNull String... bcc) {
- setPropertyString(KEY_BCC, bcc);
- return this;
- }
-
- /**
- * Sets the subject of {@link AppSearchEmail}
- */
- @NonNull
- public AppSearchEmail.Builder setSubject(@NonNull String subject) {
- setPropertyString(KEY_SUBJECT, subject);
- return this;
- }
-
- /**
- * Sets the body of {@link AppSearchEmail}
- */
- @NonNull
- public AppSearchEmail.Builder setBody(@NonNull String body) {
- setPropertyString(KEY_BODY, body);
- return this;
- }
-
- /** Builds the {@link AppSearchEmail} object. */
- @NonNull
- @Override
- public AppSearchEmail build() {
- return new AppSearchEmail(super.build());
- }
- }
-}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchResult.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchResult.java
index 75a1053..b204447 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchResult.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchResult.java
@@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// @exportToFramework:skipFile()
package androidx.appsearch.app;
+import android.util.Log;
+
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.core.util.ObjectsCompat;
+import androidx.core.util.Preconditions;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -33,6 +35,8 @@
* @param <ValueType> The type of result object for successful calls.
*/
public final class AppSearchResult<ValueType> {
+ private static final String TAG = "AppSearchResult";
+
/**
* Result codes from {@link AppSearchSession} methods.
* @hide
@@ -46,6 +50,7 @@
RESULT_OUT_OF_SPACE,
RESULT_NOT_FOUND,
RESULT_INVALID_SCHEMA,
+ RESULT_SECURITY_ERROR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResultCode {}
@@ -86,6 +91,9 @@
/** The caller supplied a schema which is invalid or incompatible with the previous schema. */
public static final int RESULT_INVALID_SCHEMA = 7;
+ /** The caller requested an operation it does not have privileges for. */
+ public static final int RESULT_SECURITY_ERROR = 8;
+
private final @ResultCode int mResultCode;
@Nullable private final ValueType mResultValue;
@Nullable private final String mErrorMessage;
@@ -168,7 +176,9 @@
/**
* Creates a new successful {@link AppSearchResult}.
- * @hide
+ *
+ * @param value An optional value to associate with the successful result of the operation
+ * being performed.
*/
@NonNull
public static <ValueType> AppSearchResult<ValueType> newSuccessfulResult(
@@ -178,7 +188,9 @@
/**
* Creates a new failed {@link AppSearchResult}.
- * @hide
+ *
+ * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}.
+ * @param errorMessage An optional string describing the reason or nature of the failure.
*/
@NonNull
public static <ValueType> AppSearchResult<ValueType> newFailedResult(
@@ -186,25 +198,52 @@
return new AppSearchResult<>(resultCode, /*resultValue=*/ null, errorMessage);
}
+ /**
+ * Creates a new failed {@link AppSearchResult} by a AppSearchResult in another type.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ public static <ValueType> AppSearchResult<ValueType> newFailedResult(
+ @NonNull AppSearchResult<?> otherFailedResult) {
+ Preconditions.checkState(!otherFailedResult.isSuccess(),
+ "Cannot convert a success result to a failed result");
+ return AppSearchResult.newFailedResult(
+ otherFailedResult.getResultCode(), otherFailedResult.getErrorMessage());
+ }
+
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
public static <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
@NonNull Throwable t) {
+ // Log for traceability. NOT_FOUND is logged at VERBOSE because this error can occur during
+ // the regular operation of the system (b/183550974). Everything else is logged at DEBUG.
+ if (t instanceof AppSearchException
+ && ((AppSearchException) t).getResultCode() == RESULT_NOT_FOUND) {
+ Log.v(TAG, "Converting throwable to failed result: " + t);
+ } else {
+ Log.d(TAG, "Converting throwable to failed result.", t);
+ }
+
if (t instanceof AppSearchException) {
return ((AppSearchException) t).toAppSearchResult();
}
+ String exceptionClass = t.getClass().getSimpleName();
@AppSearchResult.ResultCode int resultCode;
- if (t instanceof IllegalStateException) {
+ if (t instanceof IllegalStateException || t instanceof NullPointerException) {
resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
} else if (t instanceof IllegalArgumentException) {
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
} else if (t instanceof IOException) {
resultCode = AppSearchResult.RESULT_IO_ERROR;
+ } else if (t instanceof SecurityException) {
+ resultCode = AppSearchResult.RESULT_SECURITY_ERROR;
} else {
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
}
- return AppSearchResult.newFailedResult(resultCode, t.toString());
+ return AppSearchResult.newFailedResult(resultCode, exceptionClass + ": " + t.getMessage());
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSchema.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSchema.java
index aad7c19..7cb65e5 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSchema.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSchema.java
@@ -16,7 +16,6 @@
package androidx.appsearch.app;
-import android.annotation.SuppressLint;
import android.os.Bundle;
import androidx.annotation.IntDef;
@@ -25,6 +24,7 @@
import androidx.annotation.RestrictTo;
import androidx.appsearch.exceptions.IllegalSchemaException;
import androidx.appsearch.util.BundleUtil;
+import androidx.appsearch.util.IndentingStringBuilder;
import androidx.collection.ArraySet;
import androidx.core.util.ObjectsCompat;
import androidx.core.util.Preconditions;
@@ -32,6 +32,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -69,8 +70,45 @@
}
@Override
+ @NonNull
public String toString() {
- return mBundle.toString();
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendAppSearchSchemaString(stringBuilder);
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Appends a debugging string for the {@link AppSearchSchema} instance to the given string
+ * builder.
+ *
+ * @param builder the builder to append to.
+ */
+ private void appendAppSearchSchemaString(@NonNull IndentingStringBuilder builder) {
+ Preconditions.checkNotNull(builder);
+
+ builder.append("{\n");
+ builder.increaseIndentLevel();
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ builder.append("properties: [\n");
+
+ AppSearchSchema.PropertyConfig[] sortedProperties = getProperties()
+ .toArray(new AppSearchSchema.PropertyConfig[0]);
+ Arrays.sort(sortedProperties, (o1, o2) -> o1.getName().compareTo(o2.getName()));
+
+ for (int i = 0; i < sortedProperties.length; i++) {
+ AppSearchSchema.PropertyConfig propertyConfig = sortedProperties[i];
+ builder.increaseIndentLevel();
+ propertyConfig.appendPropertyConfigString(builder);
+ if (i != sortedProperties.length - 1) {
+ builder.append(",\n");
+ }
+ builder.decreaseIndentLevel();
+ }
+
+ builder.append("\n");
+ builder.append("]\n");
+ builder.decreaseIndentLevel();
+ builder.append("}");
}
/** Returns the name of this schema type, e.g. Email. */
@@ -94,7 +132,7 @@
}
List<PropertyConfig> ret = new ArrayList<>(propertyBundles.size());
for (int i = 0; i < propertyBundles.size(); i++) {
- ret.add(new PropertyConfig(propertyBundles.get(i)));
+ ret.add(PropertyConfig.fromBundle(propertyBundles.get(i)));
}
return ret;
}
@@ -122,7 +160,7 @@
/** Builder for {@link AppSearchSchema objects}. */
public static final class Builder {
private final String mSchemaType;
- private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
+ private ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
private final Set<String> mPropertyNames = new ArraySet<>();
private boolean mBuilt = false;
@@ -133,14 +171,10 @@
}
/** Adds a property to the given type. */
- // TODO(b/171360120): MissingGetterMatchingBuilder expects a method called getPropertys, but
- // we provide the (correct) method getProperties. Once the bug referenced in this TODO is
- // fixed, remove this SuppressLint.
- @SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(propertyConfig);
+ resetIfBuilt();
String name = propertyConfig.getName();
if (!mPropertyNames.add(name)) {
throw new IllegalSchemaException("Property defined more than once: " + name);
@@ -149,35 +183,34 @@
return this;
}
- /**
- * Constructs a new {@link AppSearchSchema} from the contents of this builder.
- *
- * <p>After calling this method, the builder must no longer be used.
- */
+ /** Constructs a new {@link AppSearchSchema} from the contents of this builder. */
@NonNull
public AppSearchSchema build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Bundle bundle = new Bundle();
bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mSchemaType);
bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles);
mBuilt = true;
return new AppSearchSchema(bundle);
}
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mPropertyBundles = new ArrayList<>(mPropertyBundles);
+ mBuilt = false;
+ }
+ }
}
/**
- * Configuration for a single property (field) of a document type.
+ * Common configuration for a single property (field) in a Document.
*
* <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be
* a property.
*/
- public static final class PropertyConfig {
- private static final String NAME_FIELD = "name";
- private static final String DATA_TYPE_FIELD = "dataType";
- private static final String SCHEMA_TYPE_FIELD = "schemaType";
- private static final String CARDINALITY_FIELD = "cardinality";
- private static final String INDEXING_TYPE_FIELD = "indexingType";
- private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
+ public abstract static class PropertyConfig {
+ static final String NAME_FIELD = "name";
+ static final String DATA_TYPE_FIELD = "dataType";
+ static final String CARDINALITY_FIELD = "cardinality";
/**
* Physical data-types of the contents of the property.
@@ -187,7 +220,7 @@
// com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
@IntDef(value = {
DATA_TYPE_STRING,
- DATA_TYPE_INT64,
+ DATA_TYPE_LONG,
DATA_TYPE_DOUBLE,
DATA_TYPE_BOOLEAN,
DATA_TYPE_BYTES,
@@ -196,18 +229,33 @@
@Retention(RetentionPolicy.SOURCE)
public @interface DataType {}
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int DATA_TYPE_STRING = 1;
- public static final int DATA_TYPE_INT64 = 2;
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public static final int DATA_TYPE_LONG = 2;
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int DATA_TYPE_DOUBLE = 3;
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int DATA_TYPE_BOOLEAN = 4;
- /** Unstructured BLOB. */
+ /**
+ * Unstructured BLOB.
+ * @hide
+ */
public static final int DATA_TYPE_BYTES = 5;
/**
* Indicates that the property is itself a {@link GenericDocument}, making it part of a
* hierarchical schema. Any property using this DataType MUST have a valid
* {@link PropertyConfig#getSchemaType}.
+ * @hide
*/
public static final int DATA_TYPE_DOCUMENT = 6;
@@ -234,6 +282,166 @@
/** Exactly one value [1]. */
public static final int CARDINALITY_REQUIRED = 3;
+ final Bundle mBundle;
+
+ @Nullable
+ private Integer mHashCode;
+
+ PropertyConfig(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendPropertyConfigString(stringBuilder);
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Appends a debug string for the {@link AppSearchSchema.PropertyConfig} instance to the
+ * given string builder.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendPropertyConfigString(@NonNull IndentingStringBuilder builder) {
+ Preconditions.checkNotNull(builder);
+
+ builder.append("{\n");
+ builder.increaseIndentLevel();
+ builder.append("name: \"").append(getName()).append("\",\n");
+
+ if (this instanceof AppSearchSchema.StringPropertyConfig) {
+ ((StringPropertyConfig) this)
+ .appendStringPropertyConfigFields(builder);
+ } else if (this instanceof AppSearchSchema.DocumentPropertyConfig) {
+ ((DocumentPropertyConfig) this)
+ .appendDocumentPropertyConfigFields(builder);
+ }
+
+ switch (getCardinality()) {
+ case AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED:
+ builder.append("cardinality: CARDINALITY_REPEATED,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL:
+ builder.append("cardinality: CARDINALITY_OPTIONAL,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED:
+ builder.append("cardinality: CARDINALITY_REQUIRED,\n");
+ break;
+ default:
+ builder.append("cardinality: CARDINALITY_UNKNOWN,\n");
+ }
+
+ switch (getDataType()) {
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
+ builder.append("dataType: DATA_TYPE_STRING,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_LONG:
+ builder.append("dataType: DATA_TYPE_LONG,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
+ builder.append("dataType: DATA_TYPE_DOUBLE,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
+ builder.append("dataType: DATA_TYPE_BOOLEAN,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
+ builder.append("dataType: DATA_TYPE_BYTES,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
+ builder.append("dataType: DATA_TYPE_DOCUMENT,\n");
+ break;
+ default:
+ builder.append("dataType: DATA_TYPE_UNKNOWN,\n");
+ }
+ builder.decreaseIndentLevel();
+ builder.append("}");
+ }
+
+ /** Returns the name of this property. */
+ @NonNull
+ public String getName() {
+ return mBundle.getString(NAME_FIELD, "");
+ }
+
+ /**
+ * Returns the type of data the property contains (e.g. string, int, bytes, etc).
+ *
+ * @hide
+ */
+ public @DataType int getDataType() {
+ return mBundle.getInt(DATA_TYPE_FIELD, -1);
+ }
+
+ /**
+ * Returns the cardinality of the property (whether it is optional, required or repeated).
+ */
+ public @Cardinality int getCardinality() {
+ return mBundle.getInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof PropertyConfig)) {
+ return false;
+ }
+ PropertyConfig otherProperty = (PropertyConfig) other;
+ return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
+ }
+
+ @Override
+ public int hashCode() {
+ if (mHashCode == null) {
+ mHashCode = BundleUtil.deepHashCode(mBundle);
+ }
+ return mHashCode;
+ }
+
+ /**
+ * Converts a {@link Bundle} into a {@link PropertyConfig} depending on its internal data
+ * type.
+ *
+ * <p>The bundle is not cloned.
+ *
+ * @throws IllegalArgumentException if the bundle does no contain a recognized
+ * value in its {@code DATA_TYPE_FIELD}.
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ public static PropertyConfig fromBundle(@NonNull Bundle propertyBundle) {
+ switch (propertyBundle.getInt(PropertyConfig.DATA_TYPE_FIELD)) {
+ case PropertyConfig.DATA_TYPE_STRING:
+ return new StringPropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_LONG:
+ return new LongPropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_DOUBLE:
+ return new DoublePropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_BOOLEAN:
+ return new BooleanPropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_BYTES:
+ return new BytesPropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_DOCUMENT:
+ return new DocumentPropertyConfig(propertyBundle);
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported property bundle of type "
+ + propertyBundle.getInt(PropertyConfig.DATA_TYPE_FIELD)
+ + "; contents: " + propertyBundle);
+ }
+ }
+ }
+
+ /** Configuration for a property of type String in a Document. */
+ public static final class StringPropertyConfig extends PropertyConfig {
+ private static final String INDEXING_TYPE_FIELD = "indexingType";
+ private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
+
/**
* Encapsulates the configurations on how AppSearch should query/index these terms.
* @hide
@@ -246,14 +454,7 @@
@Retention(RetentionPolicy.SOURCE)
public @interface IndexingType {}
- /**
- * Content in this property will not be tokenized or indexed.
- *
- * <p>Useful if the data type is not made up of terms (e.g.
- * {@link PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES}
- * type). None of the properties inside the nested property will be indexed regardless of
- * the value of {@code indexingType} for the nested properties.
- */
+ /** Content in this property will not be tokenized or indexed. */
public static final int INDEXING_TYPE_NONE = 0;
/**
@@ -286,55 +487,28 @@
public @interface TokenizerType {}
/**
- * It is only valid for tokenizer_type to be 'NONE' if the data type is
- * {@link PropertyConfig#DATA_TYPE_DOCUMENT}.
+ * This value indicates that no tokens should be extracted from this property.
+ *
+ * <p>It is only valid for tokenizer_type to be 'NONE' if {@link #getIndexingType} is
+ * {@link #INDEXING_TYPE_NONE}.
*/
public static final int TOKENIZER_TYPE_NONE = 0;
- /** Tokenization for plain text. */
+ /**
+ * Tokenization for plain text. This value indicates that tokens should be extracted from
+ * this property based on word breaks. Segments of whitespace and punctuation are not
+ * considered tokens.
+ *
+ * <p>Ex. A property with "foo bar. baz." will produce tokens for "foo", "bar" and "baz".
+ * The segments " " and "." will not be considered tokens.
+ *
+ * <p>It is only valid for tokenizer_type to be 'PLAIN' if {@link #getIndexingType} is
+ * {@link #INDEXING_TYPE_EXACT_TERMS} or {@link #INDEXING_TYPE_PREFIXES}.
+ */
public static final int TOKENIZER_TYPE_PLAIN = 1;
- final Bundle mBundle;
-
- @Nullable
- private Integer mHashCode;
-
- PropertyConfig(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
- }
-
- @Override
- public String toString() {
- return mBundle.toString();
- }
-
- /** Returns the name of this property. */
- @NonNull
- public String getName() {
- return mBundle.getString(NAME_FIELD, "");
- }
-
- /** Returns the type of data the property contains (e.g. string, int, bytes, etc). */
- public @DataType int getDataType() {
- return mBundle.getInt(DATA_TYPE_FIELD, -1);
- }
-
- /**
- * Returns the logical schema-type of the contents of this property.
- *
- * <p>Only set when {@link #getDataType} is set to {@link #DATA_TYPE_DOCUMENT}.
- * Otherwise, it is {@code null}.
- */
- @Nullable
- public String getSchemaType() {
- return mBundle.getString(SCHEMA_TYPE_FIELD);
- }
-
- /**
- * Returns the cardinality of the property (whether it is optional, required or repeated).
- */
- public @Cardinality int getCardinality() {
- return mBundle.getInt(CARDINALITY_FIELD, -1);
+ StringPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
}
/** Returns how the property is indexed. */
@@ -347,140 +521,405 @@
return mBundle.getInt(TOKENIZER_TYPE_FIELD);
}
- @Override
- public boolean equals(@Nullable Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof PropertyConfig)) {
- return false;
- }
- PropertyConfig otherProperty = (PropertyConfig) other;
- return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
- }
-
- @Override
- public int hashCode() {
- if (mHashCode == null) {
- mHashCode = BundleUtil.deepHashCode(mBundle);
- }
- return mHashCode;
- }
-
- /**
- * Builder for {@link PropertyConfig}.
- *
- * <p>The following properties must be set, or {@link PropertyConfig} construction will
- * fail:
- * <ul>
- * <li>dataType
- * <li>cardinality
- * </ul>
- *
- * <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType}
- * is also required.
- */
+ /** Builder for {@link StringPropertyConfig}. */
public static final class Builder {
- private final Bundle mBundle = new Bundle();
- private boolean mBuilt = false;
+ private final String mPropertyName;
+ private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+ private @IndexingType int mIndexingType = INDEXING_TYPE_NONE;
+ private @TokenizerType int mTokenizerType = TOKENIZER_TYPE_NONE;
- /** Creates a new {@link PropertyConfig.Builder}. */
+ /** Creates a new {@link StringPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
- mBundle.putString(NAME_FIELD, propertyName);
- }
-
- /**
- * Type of data the property contains (e.g. string, int, bytes, etc).
- *
- * <p>This property must be set.
- */
- @NonNull
- public PropertyConfig.Builder setDataType(@DataType int dataType) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkArgumentInRange(
- dataType, DATA_TYPE_STRING, DATA_TYPE_DOCUMENT, "dataType");
- mBundle.putInt(DATA_TYPE_FIELD, dataType);
- return this;
- }
-
- /**
- * The logical schema-type of the contents of this property.
- *
- * <p>Only required when {@link #setDataType} is set to
- * {@link #DATA_TYPE_DOCUMENT}. Otherwise, it is ignored.
- */
- @NonNull
- public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemaType);
- mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
- return this;
+ mPropertyName = Preconditions.checkNotNull(propertyName);
}
/**
* The cardinality of the property (whether it is optional, required or repeated).
*
- * <p>This property must be set.
+ * <p>If this method is not called, the default cardinality is
+ * {@link PropertyConfig#CARDINALITY_OPTIONAL}.
*/
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
- public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
+ public StringPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
Preconditions.checkArgumentInRange(
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
- mBundle.putInt(CARDINALITY_FIELD, cardinality);
+ mCardinality = cardinality;
return this;
}
/**
* Configures how a property should be indexed so that it can be retrieved by queries.
+ *
+ * <p>If this method is not called, the default indexing type is
+ * {@link StringPropertyConfig#INDEXING_TYPE_NONE}, so that it cannot be matched by
+ * queries.
*/
@NonNull
- public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
+ public StringPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
Preconditions.checkArgumentInRange(
indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType");
- mBundle.putInt(INDEXING_TYPE_FIELD, indexingType);
- return this;
- }
-
- /** Configures how this property should be tokenized (split into words). */
- @NonNull
- public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkArgumentInRange(
- tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType");
- mBundle.putInt(TOKENIZER_TYPE_FIELD, tokenizerType);
+ mIndexingType = indexingType;
return this;
}
/**
- * Constructs a new {@link PropertyConfig} from the contents of this builder.
+ * Configures how this property should be tokenized (split into words).
*
- * <p>After calling this method, the builder must no longer be used.
+ * <p>If this method is not called, the default indexing type is
+ * {@link StringPropertyConfig#TOKENIZER_TYPE_NONE}, so that it is not tokenized.
*
- * @throws IllegalSchemaException If the property is not correctly populated (e.g.
- * missing {@code dataType}).
+ * <p>This method must be called with a value other than
+ * {@link StringPropertyConfig#TOKENIZER_TYPE_NONE} if the property is indexed (i.e.
+ * if {@link #setIndexingType} has been called with a value other than
+ * {@link StringPropertyConfig#INDEXING_TYPE_NONE}).
*/
@NonNull
- public PropertyConfig build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
- // of partially reimplementing some of the validation Icing does here.
- if (!mBundle.containsKey(DATA_TYPE_FIELD)) {
- throw new IllegalSchemaException("Missing field: dataType");
- }
- if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()
- && mBundle.getInt(DATA_TYPE_FIELD) == DATA_TYPE_DOCUMENT) {
- throw new IllegalSchemaException(
- "Missing field: schemaType (required for configs with "
- + "dataType = DOCUMENT)");
- }
- if (!mBundle.containsKey(CARDINALITY_FIELD)) {
- throw new IllegalSchemaException("Missing field: cardinality");
- }
- mBuilt = true;
- return new PropertyConfig(mBundle);
+ public StringPropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
+ Preconditions.checkArgumentInRange(
+ tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType");
+ mTokenizerType = tokenizerType;
+ return this;
}
+
+ /**
+ * Constructs a new {@link StringPropertyConfig} from the contents of this builder.
+ */
+ @NonNull
+ public StringPropertyConfig build() {
+ if (mTokenizerType == TOKENIZER_TYPE_NONE) {
+ Preconditions.checkState(mIndexingType == INDEXING_TYPE_NONE, "Cannot set "
+ + "TOKENIZER_TYPE_NONE with an indexing type other than "
+ + "INDEXING_TYPE_NONE.");
+ } else {
+ Preconditions.checkState(mIndexingType != INDEXING_TYPE_NONE, "Cannot set "
+ + "TOKENIZER_TYPE_PLAIN with INDEXING_TYPE_NONE.");
+ }
+ Bundle bundle = new Bundle();
+ bundle.putString(NAME_FIELD, mPropertyName);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_STRING);
+ bundle.putInt(CARDINALITY_FIELD, mCardinality);
+ bundle.putInt(INDEXING_TYPE_FIELD, mIndexingType);
+ bundle.putInt(TOKENIZER_TYPE_FIELD, mTokenizerType);
+ return new StringPropertyConfig(bundle);
+ }
+ }
+
+ /**
+ * Appends a debug string for the {@link StringPropertyConfig} instance to the given
+ * string builder.
+ *
+ * <p>This appends fields specific to a {@link StringPropertyConfig} instance.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendStringPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
+ switch (getIndexingType()) {
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
+ builder.append("indexingType: INDEXING_TYPE_NONE,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
+ builder.append("indexingType: INDEXING_TYPE_EXACT_TERMS,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
+ builder.append("indexingType: INDEXING_TYPE_PREFIXES,\n");
+ break;
+ default:
+ builder.append("indexingType: INDEXING_TYPE_UNKNOWN,\n");
+ }
+
+ switch (getTokenizerType()) {
+ case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE:
+ builder.append("tokenizerType: TOKENIZER_TYPE_NONE,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN:
+ builder.append("tokenizerType: TOKENIZER_TYPE_PLAIN,\n");
+ break;
+ default:
+ builder.append("tokenizerType: TOKENIZER_TYPE_UNKNOWN,\n");
+ }
+ }
+ }
+
+ /** Configuration for a property containing a 64-bit integer. */
+ public static final class LongPropertyConfig extends PropertyConfig {
+ LongPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /** Builder for {@link LongPropertyConfig}. */
+ public static final class Builder {
+ private final String mPropertyName;
+ private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+
+ /** Creates a new {@link LongPropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mPropertyName = Preconditions.checkNotNull(propertyName);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>If this method is not called, the default cardinality is
+ * {@link PropertyConfig#CARDINALITY_OPTIONAL}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public LongPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mCardinality = cardinality;
+ return this;
+ }
+
+ /** Constructs a new {@link LongPropertyConfig} from the contents of this builder. */
+ @NonNull
+ public LongPropertyConfig build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(NAME_FIELD, mPropertyName);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_LONG);
+ bundle.putInt(CARDINALITY_FIELD, mCardinality);
+ return new LongPropertyConfig(bundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing a double-precision decimal number. */
+ public static final class DoublePropertyConfig extends PropertyConfig {
+ DoublePropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /** Builder for {@link DoublePropertyConfig}. */
+ public static final class Builder {
+ private final String mPropertyName;
+ private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+
+ /** Creates a new {@link DoublePropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mPropertyName = Preconditions.checkNotNull(propertyName);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>If this method is not called, the default cardinality is
+ * {@link PropertyConfig#CARDINALITY_OPTIONAL}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public DoublePropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mCardinality = cardinality;
+ return this;
+ }
+
+ /** Constructs a new {@link DoublePropertyConfig} from the contents of this builder. */
+ @NonNull
+ public DoublePropertyConfig build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(NAME_FIELD, mPropertyName);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOUBLE);
+ bundle.putInt(CARDINALITY_FIELD, mCardinality);
+ return new DoublePropertyConfig(bundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing a boolean. */
+ public static final class BooleanPropertyConfig extends PropertyConfig {
+ BooleanPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /** Builder for {@link BooleanPropertyConfig}. */
+ public static final class Builder {
+ private final String mPropertyName;
+ private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+
+ /** Creates a new {@link BooleanPropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mPropertyName = Preconditions.checkNotNull(propertyName);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>If this method is not called, the default cardinality is
+ * {@link PropertyConfig#CARDINALITY_OPTIONAL}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public BooleanPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mCardinality = cardinality;
+ return this;
+ }
+
+ /** Constructs a new {@link BooleanPropertyConfig} from the contents of this builder. */
+ @NonNull
+ public BooleanPropertyConfig build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(NAME_FIELD, mPropertyName);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BOOLEAN);
+ bundle.putInt(CARDINALITY_FIELD, mCardinality);
+ return new BooleanPropertyConfig(bundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing a byte array. */
+ public static final class BytesPropertyConfig extends PropertyConfig {
+ BytesPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /** Builder for {@link BytesPropertyConfig}. */
+ public static final class Builder {
+ private final String mPropertyName;
+ private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+
+ /** Creates a new {@link BytesPropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mPropertyName = Preconditions.checkNotNull(propertyName);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>If this method is not called, the default cardinality is
+ * {@link PropertyConfig#CARDINALITY_OPTIONAL}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public BytesPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mCardinality = cardinality;
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link BytesPropertyConfig} from the contents of this builder.
+ */
+ @NonNull
+ public BytesPropertyConfig build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(NAME_FIELD, mPropertyName);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BYTES);
+ bundle.putInt(CARDINALITY_FIELD, mCardinality);
+ return new BytesPropertyConfig(bundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing another Document. */
+ public static final class DocumentPropertyConfig extends PropertyConfig {
+ private static final String SCHEMA_TYPE_FIELD = "schemaType";
+ private static final String INDEX_NESTED_PROPERTIES_FIELD = "indexNestedProperties";
+
+ DocumentPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /** Returns the logical schema-type of the contents of this document property. */
+ @NonNull
+ public String getSchemaType() {
+ return Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+ }
+
+ /**
+ * Returns whether fields in the nested document should be indexed according to that
+ * document's schema.
+ *
+ * <p>If false, the nested document's properties are not indexed regardless of its own
+ * schema.
+ */
+ public boolean shouldIndexNestedProperties() {
+ return mBundle.getBoolean(INDEX_NESTED_PROPERTIES_FIELD);
+ }
+
+ /** Builder for {@link DocumentPropertyConfig}. */
+ public static final class Builder {
+ private final String mPropertyName;
+ private final String mSchemaType;
+ private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+ private boolean mShouldIndexNestedProperties = false;
+
+ /**
+ * Creates a new {@link DocumentPropertyConfig.Builder}.
+ *
+ * @param propertyName The logical name of the property in the schema, which will be
+ * used as the key for this property in
+ * {@link GenericDocument.Builder#setPropertyDocument}.
+ * @param schemaType The type of documents which will be stored in this property.
+ * Documents of different types cannot be mixed into a single
+ * property.
+ */
+ public Builder(@NonNull String propertyName, @NonNull String schemaType) {
+ mPropertyName = Preconditions.checkNotNull(propertyName);
+ mSchemaType = Preconditions.checkNotNull(schemaType);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>If this method is not called, the default cardinality is
+ * {@link PropertyConfig#CARDINALITY_OPTIONAL}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public DocumentPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mCardinality = cardinality;
+ return this;
+ }
+
+ /**
+ * Configures whether fields in the nested document should be indexed according to that
+ * document's schema.
+ *
+ * <p>If false, the nested document's properties are not indexed regardless of its own
+ * schema.
+ */
+ @NonNull
+ public DocumentPropertyConfig.Builder setShouldIndexNestedProperties(
+ boolean indexNestedProperties) {
+ mShouldIndexNestedProperties = indexNestedProperties;
+ return this;
+ }
+
+ /** Constructs a new {@link PropertyConfig} from the contents of this builder. */
+ @NonNull
+ public DocumentPropertyConfig build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(NAME_FIELD, mPropertyName);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT);
+ bundle.putInt(CARDINALITY_FIELD, mCardinality);
+ bundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, mShouldIndexNestedProperties);
+ bundle.putString(SCHEMA_TYPE_FIELD, mSchemaType);
+ return new DocumentPropertyConfig(bundle);
+ }
+ }
+
+ /**
+ * Appends a debug string for the {@link DocumentPropertyConfig} instance to the given
+ * string builder.
+ *
+ * <p>This appends fields specific to a {@link DocumentPropertyConfig} instance.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendDocumentPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
+ builder
+ .append("shouldIndexNestedProperties: ")
+ .append(shouldIndexNestedProperties())
+ .append(",\n");
+
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
}
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSession.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSession.java
index 76ce163..4c4c8c8 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSession.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSession.java
@@ -26,176 +26,201 @@
import java.util.Set;
/**
- * Represents a connection to an AppSearch storage system where {@link GenericDocument}s can be
- * placed and queried.
+ * Provides a connection to a single AppSearch database.
*
- * All implementations of this interface must be thread safe.
+ * <p>An {@link AppSearchSession} instance provides access to database operations such as setting
+ * a schema, adding documents, and searching.
+ *
+ * <p>Instances of this interface are usually obtained from a storage implementation, e.g.
+ * {@code LocalStorage.createSearchSession()} or {@code PlatformStorage.createSearchSession()}.
+ *
+ * <p>All implementations of this interface must be thread safe.
+ *
+ * @see GlobalSearchSession
*/
public interface AppSearchSession extends Closeable {
/**
- * Sets the schema that will be used by documents provided to the {@link #putDocuments} method.
+ * Sets the schema that represents the organizational structure of data within the AppSearch
+ * database.
*
- * <p>The schema provided here is compared to the stored copy of the schema previously supplied
- * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
- * types of schema modifications are always safe and are made without deleting any existing
- * documents:
- * <ul>
- * <li>Addition of new types
- * <li>Addition of new
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
- * type
- * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
- * </ul>
+ * <p>Upon creating an {@link AppSearchSession}, {@link #setSchema} should be called. If the
+ * schema needs to be updated, or it has not been previously set, then the provided schema
+ * will be saved and persisted to disk. Otherwise, {@link #setSchema} is handled efficiently
+ * as a no-op call.
*
- * <p>The following types of schema changes are not backwards-compatible:
- * <ul>
- * <li>Removal of an existing type
- * <li>Removal of a property from a type
- * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
- * <li>For properties of {@code Document} type, changing the schema type of
- * {@code Document}s of that property
- * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
- * <li>Adding a
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
- * </ul>
- * <p>Supplying a schema with such changes will, by default, result in this call completing its
- * future with an {@link androidx.appsearch.exceptions.AppSearchException} with a code of
- * {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
- * In this case the previously set schema will remain active.
- *
- * <p>If you need to make non-backwards-compatible changes as described above, you can set the
- * {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In this case,
- * instead of completing its future with an
- * {@link androidx.appsearch.exceptions.AppSearchException} with the
- * {@link AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
- * compatible with the new schema will be deleted and the incompatible schema will be applied.
- *
- * <p>It is a no-op to set the same schema as has been previously set; this is handled
- * efficiently.
- *
- * <p>By default, documents are visible on platform surfaces. To opt out, call {@code
- * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
- * visibility settings apply only to the schemas that are included in the {@code request}.
- * Visibility settings for a schema type do not apply or persist across
- * {@link SetSchemaRequest}s.
- *
- * @param request The schema update request.
- * @return The pending result of performing this operation.
+ * @param request the schema to set or update the AppSearch database to.
+ * @return a {@link ListenableFuture} which resolves to a {@link SetSchemaResponse} object.
*/
- // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
- // exposed.
@NonNull
- ListenableFuture<Void> setSchema(@NonNull SetSchemaRequest request);
+ ListenableFuture<SetSchemaResponse> setSchema(
+ @NonNull SetSchemaRequest request);
/**
* Retrieves the schema most recently successfully provided to {@link #setSchema}.
*
- * @return The pending result of performing this operation.
+ * @return The pending {@link GetSchemaResponse} of performing this operation.
*/
// This call hits disk; async API prevents us from treating these calls as properties.
@SuppressLint("KotlinPropertyAccess")
@NonNull
- ListenableFuture<Set<AppSearchSchema>> getSchema();
+ ListenableFuture<GetSchemaResponse> getSchema();
/**
- * Indexes documents into AppSearch.
+ * Retrieves the set of all namespaces in the current database with at least one document.
*
- * <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a
- * schema type previously registered via the {@link #setSchema} method.
- *
- * @param request {@link PutDocumentsRequest} containing documents to be indexed
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the URIs of the input documents. The values are
- * {@code null} if they were successfully indexed, or a failed {@link AppSearchResult}
- * otherwise.
+ * @return The pending result of performing this operation.
*/
@NonNull
- ListenableFuture<AppSearchBatchResult<String, Void>> putDocuments(
- @NonNull PutDocumentsRequest request);
+ ListenableFuture<Set<String>> getNamespaces();
/**
- * Retrieves {@link GenericDocument}s by URI.
+ * Indexes documents into the {@link AppSearchSession} database.
*
- * @param request {@link GetByUriRequest} containing URIs to be retrieved.
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the input URIs. The values are the returned
- * {@link GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise.
- * URIs that are not found will return a failed {@link AppSearchResult} with a result code
- * of {@link AppSearchResult#RESULT_NOT_FOUND}.
+ * <p>Each {@link GenericDocument} object must have a {@code schemaType} field set to an
+ * {@link AppSearchSchema} type that has been previously registered by calling the
+ * {@link #setSchema} method.
+ *
+ * @param request containing documents to be indexed.
+ * @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}.
+ * The keys of the returned {@link AppSearchBatchResult} are the IDs of the input documents.
+ * The values are either {@code null} if the corresponding document was successfully indexed,
+ * or a failed {@link AppSearchResult} otherwise.
*/
@NonNull
- ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByUri(
- @NonNull GetByUriRequest request);
+ ListenableFuture<AppSearchBatchResult<String, Void>> put(@NonNull PutDocumentsRequest request);
/**
- * Searches a document based on a given query string.
+ * Gets {@link GenericDocument} objects by document IDs in a namespace from the
+ * {@link AppSearchSession} database.
*
- * <p>Currently we support following features in the raw query format:
- * <ul>
- * <li>AND
- * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
- * ‘cat’”).
- * Example: hello world matches documents that have both ‘hello’ and ‘world’
- * <li>OR
- * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
- * ‘cat’”).
- * Example: dog OR puppy
- * <li>Exclusion
- * <p>Exclude a term (e.g. “match documents that do
- * not have the term ‘dog’”).
- * Example: -dog excludes the term ‘dog’
- * <li>Grouping terms
- * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
- * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
- * Example: (dog puppy) (cat kitten) two one group containing two terms.
- * <li>Property restricts
- * <p> Specifies which properties of a document to specifically match terms in (e.g.
- * “match documents where the ‘subject’ property contains ‘important’”).
- * Example: subject:important matches documents with the term ‘important’ in the
- * ‘subject’ property
- * <li>Schema type restricts
- * <p>This is similar to property restricts, but allows for restricts on top-level document
- * fields, such as schema_type. Clients should be able to limit their query to documents of
- * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
- * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
- * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
- * ‘Video’ schema type.
- * </ul>
- *
- * <p> This method is lightweight. The heavy work will be done in
- * {@link SearchResults#getNextPage()}.
- *
- * @param queryExpression Query String to search.
- * @param searchSpec Spec for setting filters, raw query etc.
- * @return The search result of performing this operation.
- */
- @NonNull
- SearchResults query(@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
-
- /**
- * Removes {@link GenericDocument}s from the index by URI.
- *
- * @param request Request containing URIs to be removed.
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the input URIs. The values are {@code null} on success,
- * or a failed {@link AppSearchResult} otherwise. URIs that are not found will return a
- * failed {@link AppSearchResult} with a result code of
+ * @param request a request containing a namespace and IDs to get documents for.
+ * @return A {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}.
+ * The keys of the {@link AppSearchBatchResult} represent the input document IDs from the
+ * {@link GetByDocumentIdRequest} object. The values are either the corresponding
+ * {@link GenericDocument} object for the ID on success, or an {@link AppSearchResult}
+ * object on failure. For example, if an ID is not found, the value for that ID will be set
+ * to an {@link AppSearchResult} object with result code:
* {@link AppSearchResult#RESULT_NOT_FOUND}.
*/
@NonNull
- ListenableFuture<AppSearchBatchResult<String, Void>> removeByUri(
- @NonNull RemoveByUriRequest request);
+ ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentId(
+ @NonNull GetByDocumentIdRequest request);
+
+ /**
+ * Retrieves documents from the open {@link AppSearchSession} that match a given query string
+ * and type of search provided.
+ *
+ * <p>Query strings can be empty, contain one term with no operators, or contain multiple
+ * terms and operators.
+ *
+ * <p>For query strings that are empty, all documents that match the {@link SearchSpec} will be
+ * returned.
+ *
+ * <p>For query strings with a single term and no operators, documents that match the
+ * provided query string and {@link SearchSpec} will be returned.
+ *
+ * <p>The following operators are supported:
+ *
+ * <ul>
+ * <li>AND (implicit)
+ * <p>AND is an operator that matches documents that contain <i>all</i>
+ * provided terms.
+ * <p><b>NOTE:</b> A space between terms is treated as an "AND" operator. Explicitly
+ * including "AND" in a query string will treat "AND" as a term, returning documents that
+ * also contain "AND".
+ * <p>Example: "apple AND banana" matches documents that contain the
+ * terms "apple", "and", "banana".
+ * <p>Example: "apple banana" matches documents that contain both "apple" and
+ * "banana".
+ * <p>Example: "apple banana cherry" matches documents that contain "apple", "banana", and
+ * "cherry".
+ *
+ * <li>OR
+ * <p>OR is an operator that matches documents that contain <i>any</i> provided term.
+ * <p>Example: "apple OR banana" matches documents that contain either "apple" or "banana".
+ * <p>Example: "apple OR banana OR cherry" matches documents that contain any of
+ * "apple", "banana", or "cherry".
+ *
+ * <li>Exclusion (-)
+ * <p>Exclusion (-) is an operator that matches documents that <i>do not</i> contain the
+ * provided term.
+ * <p>Example: "-apple" matches documents that do not contain "apple".
+ *
+ * <li>Grouped Terms
+ * <p>For queries that require multiple operators and terms, terms can be grouped into
+ * subqueries. Subqueries are contained within an open "(" and close ")" parenthesis.
+ * <p>Example: "(donut OR bagel) (coffee OR tea)" matches documents that contain
+ * either "donut" or "bagel" and either "coffee" or "tea".
+ *
+ * <li>Property Restricts
+ * <p>For queries that require a term to match a specific {@link AppSearchSchema}
+ * property of a document, a ":" must be included between the property name and the term.
+ * <p>Example: "subject:important" matches documents that contain the term "important" in
+ * the "subject" property.
+ * </ul>
+ *
+ * <p>Additional search specifications, such as filtering by {@link AppSearchSchema} type or
+ * adding projection, can be set by calling the corresponding {@link SearchSpec.Builder} setter.
+ *
+ * <p>This method is lightweight. The heavy work will be done in
+ * {@link SearchResults#getNextPage}.
+ *
+ * @param queryExpression query string to search.
+ * @param searchSpec spec for setting document filters, adding projection, setting term
+ * match type, etc.
+ * @return a {@link SearchResults} object for retrieved matched documents.
+ */
+ @NonNull
+ SearchResults search(@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
+
+ /**
+ * Reports usage of a particular document by namespace and ID.
+ *
+ * <p>A usage report represents an event in which a user interacted with or viewed a document.
+ *
+ * <p>For each call to {@link #reportUsage}, AppSearch updates usage count and usage recency
+ * metrics for that particular document. These metrics are used for ordering {@link #search}
+ * results by the {@link SearchSpec#RANKING_STRATEGY_USAGE_COUNT} and
+ * {@link SearchSpec#RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP} ranking strategies.
+ *
+ * <p>Reporting usage of a document is optional.
+ *
+ * @param request The usage reporting request.
+ * @return The pending result of performing this operation which resolves to {@code null} on
+ * success.
+ */
+ @NonNull
+ ListenableFuture<Void> reportUsage(@NonNull ReportUsageRequest request);
+
+ /**
+ * Removes {@link GenericDocument} objects by document IDs in a namespace from the
+ * {@link AppSearchSession} database.
+ *
+ * <p>Removed documents will no longer be surfaced by {@link #search} or
+ * {@link #getByDocumentId}
+ * calls.
+ *
+ * <p>Once the database crosses the document count or byte usage threshold, removed documents
+ * will be deleted from disk.
+ *
+ * @param request {@link RemoveByDocumentIdRequest} with IDs in a namespace to remove from the
+ * index.
+ * @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}.
+ * The keys of the {@link AppSearchBatchResult} represent the input IDs from the
+ * {@link RemoveByDocumentIdRequest} object. The values are either {@code null} on success,
+ * or a failed {@link AppSearchResult} otherwise. IDs that are not found will return a failed
+ * {@link AppSearchResult} with a result code of {@link AppSearchResult#RESULT_NOT_FOUND}.
+ */
+ @NonNull
+ ListenableFuture<AppSearchBatchResult<String, Void>> remove(
+ @NonNull RemoveByDocumentIdRequest request);
/**
* Removes {@link GenericDocument}s from the index by Query. Documents will be removed if they
* match the {@code queryExpression} in given namespaces and schemaTypes which is set via
- * {@link SearchSpec.Builder#addNamespace} and {@link SearchSpec.Builder#addSchemaType}.
+ * {@link SearchSpec.Builder#addFilterNamespaces} and
+ * {@link SearchSpec.Builder#addFilterSchemas}.
*
* <p> An empty {@code queryExpression} matches all documents.
*
@@ -209,8 +234,32 @@
* @return The pending result of performing this operation.
*/
@NonNull
- ListenableFuture<Void> removeByQuery(
- @NonNull String queryExpression, @NonNull SearchSpec searchSpec);
+ ListenableFuture<Void> remove(@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
+
+ /**
+ * Gets the storage info for this {@link AppSearchSession} database.
+ *
+ * <p>This may take time proportional to the number of documents and may be inefficient to
+ * call repeatedly.
+ *
+ * @return a {@link ListenableFuture} which resolves to a {@link StorageInfo} object.
+ */
+ @NonNull
+ ListenableFuture<StorageInfo> getStorageInfo();
+
+ /**
+ * Flush all schema and document updates, additions, and deletes to disk if possible.
+ *
+ * <p>The request is not guaranteed to be handled and may be ignored by some implementations of
+ * AppSearchSession.
+ *
+ * @return The pending result of performing this operation.
+ * {@link androidx.appsearch.exceptions.AppSearchException} with
+ * {@link AppSearchResult#RESULT_INTERNAL_ERROR} will be set to the future if we hit error when
+ * save to disk.
+ */
+ @NonNull
+ ListenableFuture<Void> requestFlush();
/**
* Closes the {@link AppSearchSession} to persist all schema and document updates, additions,
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
deleted file mode 100644
index 014b23b..0000000
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// @exportToFramework:skipFile()
-package androidx.appsearch.app;
-
-import androidx.annotation.NonNull;
-import androidx.appsearch.exceptions.AppSearchException;
-
-/**
- * An interface for factories which can convert between data classes and {@link GenericDocument}.
- *
- * @param <T> The type of data class this factory converts to and from {@link GenericDocument}.
- */
-public interface DataClassFactory<T> {
- /**
- * Returns the name of this schema type, e.g. {@code Email}.
- *
- * <p>This is the name used in queries for type restricts.
- */
- @NonNull
- String getSchemaType();
-
- /** Returns the schema for this data class. */
- @NonNull
- AppSearchSchema getSchema() throws AppSearchException;
-
- /**
- * Converts an instance of the data class into a {@link androidx.appsearch.app.GenericDocument}.
- */
- @NonNull
- GenericDocument toGenericDocument(@NonNull T dataClass) throws AppSearchException;
-
- /**
- * Converts a {@link androidx.appsearch.app.GenericDocument} into an instance of the data class.
- */
- @NonNull
- T fromGenericDocument(@NonNull GenericDocument genericDoc) throws AppSearchException;
-}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
deleted file mode 100644
index 3be56c6..0000000
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// @exportToFramework:skipFile()
-package androidx.appsearch.app;
-
-import androidx.annotation.AnyThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.appsearch.exceptions.AppSearchException;
-import androidx.core.util.Preconditions;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A registry which maintains instances of {@link androidx.appsearch.app.DataClassFactory}.
- * @hide
- */
-@AnyThread
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public final class DataClassFactoryRegistry {
- private static final String GEN_CLASS_PREFIX = "$$__AppSearch__";
-
- private static volatile DataClassFactoryRegistry sInstance = null;
-
- private final Map<Class<?>, DataClassFactory<?>> mFactories = new HashMap<>();
-
- private DataClassFactoryRegistry() {}
-
- /** Returns the singleton instance of {@link DataClassFactoryRegistry}. */
- @NonNull
- public static DataClassFactoryRegistry getInstance() {
- if (sInstance == null) {
- synchronized (DataClassFactoryRegistry.class) {
- if (sInstance == null) {
- sInstance = new DataClassFactoryRegistry();
- }
- }
- }
- return sInstance;
- }
-
- /**
- * Gets the {@link DataClassFactory} instance that can convert to and from objects of type
- * {@code T}.
- *
- * @throws AppSearchException if no factory for this data class could be found on the classpath
- */
- @NonNull
- @SuppressWarnings("unchecked")
- public <T> DataClassFactory<T> getOrCreateFactory(@NonNull Class<T> dataClass)
- throws AppSearchException {
- Preconditions.checkNotNull(dataClass);
- DataClassFactory<?> factory;
- synchronized (this) {
- factory = mFactories.get(dataClass);
- }
- if (factory == null) {
- factory = loadFactoryByReflection(dataClass);
- synchronized (this) {
- DataClassFactory<?> racingFactory = mFactories.get(dataClass);
- if (racingFactory == null) {
- mFactories.put(dataClass, factory);
- } else {
- // Another thread beat us to it
- factory = racingFactory;
- }
- }
- }
- return (DataClassFactory<T>) factory;
- }
-
- /**
- * Gets the {@link DataClassFactory} instance that can convert to and from objects of type
- * {@code T}.
- *
- * @throws AppSearchException if no factory for this data class could be found on the classpath
- */
- @NonNull
- @SuppressWarnings("unchecked")
- public <T> DataClassFactory<T> getOrCreateFactory(@NonNull T dataClass)
- throws AppSearchException {
- Preconditions.checkNotNull(dataClass);
- Class<?> clazz = dataClass.getClass();
- DataClassFactory<?> factory = getOrCreateFactory(clazz);
- return (DataClassFactory<T>) factory;
- }
-
- private DataClassFactory<?> loadFactoryByReflection(@NonNull Class<?> dataClass)
- throws AppSearchException {
- Package pkg = dataClass.getPackage();
- String simpleName = dataClass.getCanonicalName();
- if (simpleName == null) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- "Failed to find simple name for data class \"" + dataClass
- + "\". Perhaps it is anonymous?");
- }
-
- // Creates factory class name under the package.
- // For a class Foo annotated with @AppSearchDocument, we will generated a
- // $$__AppSearch__Foo.class under the package.
- // For an inner class Foo.Bar annotated with @AppSearchDocument, we will generated a
- // $$__AppSearch__Foo$$__Bar.class under the package.
- String packageName = "";
- if (pkg != null) {
- packageName = pkg.getName() + ".";
- simpleName = simpleName.substring(packageName.length()).replace(".", "$$__");
- }
- String factoryClassName = packageName + GEN_CLASS_PREFIX + simpleName;
-
- Class<?> factoryClass;
- try {
- factoryClass = Class.forName(factoryClassName);
- } catch (ClassNotFoundException e) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- "Failed to find data class converter \"" + factoryClassName
- + "\". Perhaps the annotation processor was not run or the class was "
- + "proguarded out?",
- e);
- }
- Object instance;
- try {
- instance = factoryClass.getDeclaredConstructor().newInstance();
- } catch (Exception e) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- "Failed to construct data class converter \"" + factoryClassName + "\"",
- e);
- }
- return (DataClassFactory<?>) instance;
- }
-}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DocumentClassFactory.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DocumentClassFactory.java
new file mode 100644
index 0000000..bd03221
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DocumentClassFactory.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.exceptions.AppSearchException;
+
+/**
+ * An interface for factories which can convert between instances of classes annotated with
+ * \@{@link androidx.appsearch.annotation.Document} and instances of {@link GenericDocument}.
+ *
+ * @param <T> The document class type this factory converts to and from {@link GenericDocument}.
+ */
+public interface DocumentClassFactory<T> {
+ /**
+ * Returns the name of this schema type, e.g. {@code Email}.
+ *
+ * <p>This is the name used in queries for type restricts.
+ */
+ @NonNull
+ String getSchemaName();
+
+ /** Returns the schema for this document class. */
+ @NonNull
+ AppSearchSchema getSchema() throws AppSearchException;
+
+ /**
+ * Converts an instance of the class annotated with
+ * \@{@link androidx.appsearch.annotation.Document} into a
+ * {@link androidx.appsearch.app.GenericDocument}.
+ */
+ @NonNull
+ GenericDocument toGenericDocument(@NonNull T document) throws AppSearchException;
+
+ /**
+ * Converts a {@link androidx.appsearch.app.GenericDocument} into an instance of the document
+ * class.
+ */
+ @NonNull
+ T fromGenericDocument(@NonNull GenericDocument genericDoc) throws AppSearchException;
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DocumentClassFactoryRegistry.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DocumentClassFactoryRegistry.java
new file mode 100644
index 0000000..6ce9a9b6
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DocumentClassFactoryRegistry.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.app;
+
+import androidx.annotation.AnyThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.core.util.Preconditions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A registry which maintains instances of {@link DocumentClassFactory}.
+ * @hide
+ */
+@AnyThread
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class DocumentClassFactoryRegistry {
+ private static final String GEN_CLASS_PREFIX = "$$__AppSearch__";
+
+ private static volatile DocumentClassFactoryRegistry sInstance = null;
+
+ private final Map<Class<?>, DocumentClassFactory<?>> mFactories = new HashMap<>();
+
+ private DocumentClassFactoryRegistry() {}
+
+ /** Returns the singleton instance of {@link DocumentClassFactoryRegistry}. */
+ @NonNull
+ public static DocumentClassFactoryRegistry getInstance() {
+ if (sInstance == null) {
+ synchronized (DocumentClassFactoryRegistry.class) {
+ if (sInstance == null) {
+ sInstance = new DocumentClassFactoryRegistry();
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * Gets the {@link DocumentClassFactory} instance that can convert to and from objects of type
+ * {@code T}.
+ *
+ * @throws AppSearchException if no factory for this document class could be found on the
+ * classpath
+ */
+ @NonNull
+ @SuppressWarnings("unchecked")
+ public <T> DocumentClassFactory<T> getOrCreateFactory(@NonNull Class<T> documentClass)
+ throws AppSearchException {
+ Preconditions.checkNotNull(documentClass);
+ DocumentClassFactory<?> factory;
+ synchronized (this) {
+ factory = mFactories.get(documentClass);
+ }
+ if (factory == null) {
+ factory = loadFactoryByReflection(documentClass);
+ synchronized (this) {
+ DocumentClassFactory<?> racingFactory = mFactories.get(documentClass);
+ if (racingFactory == null) {
+ mFactories.put(documentClass, factory);
+ } else {
+ // Another thread beat us to it
+ factory = racingFactory;
+ }
+ }
+ }
+ return (DocumentClassFactory<T>) factory;
+ }
+
+ /**
+ * Gets the {@link DocumentClassFactory} instance that can convert to and from objects of type
+ * {@code T}.
+ *
+ * @throws AppSearchException if no factory for this document class could be found on the
+ * classpath
+ */
+ @NonNull
+ @SuppressWarnings("unchecked")
+ public <T> DocumentClassFactory<T> getOrCreateFactory(@NonNull T documentClass)
+ throws AppSearchException {
+ Preconditions.checkNotNull(documentClass);
+ Class<?> clazz = documentClass.getClass();
+ DocumentClassFactory<?> factory = getOrCreateFactory(clazz);
+ return (DocumentClassFactory<T>) factory;
+ }
+
+ private DocumentClassFactory<?> loadFactoryByReflection(@NonNull Class<?> documentClass)
+ throws AppSearchException {
+ Package pkg = documentClass.getPackage();
+ String simpleName = documentClass.getCanonicalName();
+ if (simpleName == null) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Failed to find simple name for document class \"" + documentClass
+ + "\". Perhaps it is anonymous?");
+ }
+
+ // Creates factory class name under the package.
+ // For a class Foo annotated with @Document, we will generated a
+ // $$__AppSearch__Foo.class under the package.
+ // For an inner class Foo.Bar annotated with @Document, we will generated a
+ // $$__AppSearch__Foo$$__Bar.class under the package.
+ String packageName = "";
+ if (pkg != null) {
+ packageName = pkg.getName() + ".";
+ simpleName = simpleName.substring(packageName.length()).replace(".", "$$__");
+ }
+ String factoryClassName = packageName + GEN_CLASS_PREFIX + simpleName;
+
+ Class<?> factoryClass;
+ try {
+ factoryClass = Class.forName(factoryClassName);
+ } catch (ClassNotFoundException e) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Failed to find document class converter \"" + factoryClassName
+ + "\". Perhaps the annotation processor was not run or the class was "
+ + "proguarded out?",
+ e);
+ }
+ Object instance;
+ try {
+ instance = factoryClass.getDeclaredConstructor().newInstance();
+ } catch (Exception e) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Failed to construct document class converter \"" + factoryClassName + "\"",
+ e);
+ }
+ return (DocumentClassFactory<?>) instance;
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
index 77d3918..d9ab886 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
@@ -18,49 +18,46 @@
import android.annotation.SuppressLint;
import android.os.Bundle;
+import android.os.Parcelable;
import android.util.Log;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.Document;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.util.BundleUtil;
+import androidx.appsearch.util.IndentingStringBuilder;
import androidx.core.util.Preconditions;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.Set;
/**
* Represents a document unit.
*
- * <p>Documents are constructed via {@link GenericDocument.Builder}.
+ * <p>Documents contain structured data conforming to their {@link AppSearchSchema} type.
+ * Each document is uniquely identified by a namespace and a String ID within that namespace.
*
- * @see AppSearchSession#putDocuments
- * @see AppSearchSession#getByUri
- * @see AppSearchSession#query
+ * <!--@exportToFramework:ifJetpack()-->
+ * <p>Documents are constructed either by using the {@link GenericDocument.Builder} or providing
+ * an annotated {@link Document} data class.
+ * <!--@exportToFramework:else()
+ * <p>Documents are constructed by using the {@link GenericDocument.Builder}.
+ * -->
+ *
+ * @see AppSearchSession#put
+ * @see AppSearchSession#getByDocumentId
+ * @see AppSearchSession#search
*/
public class GenericDocument {
private static final String TAG = "AppSearchGenericDocumen";
- /** The default empty namespace. */
- public static final String DEFAULT_NAMESPACE = "";
-
- /**
- * The maximum number of elements in a repeatable field. Will reject the request if exceed
- * this limit.
- */
- private static final int MAX_REPEATED_PROPERTY_LENGTH = 100;
-
- /**
- * The maximum {@link String#length} of a {@link String} field. Will reject the request if
- * {@link String}s longer than this.
- */
- private static final int MAX_STRING_LENGTH = 20_000;
-
/** The maximum number of indexed properties a document can have. */
private static final int MAX_INDEXED_PROPERTIES = 16;
@@ -73,7 +70,7 @@
private static final String PROPERTIES_FIELD = "properties";
private static final String BYTE_ARRAY_FIELD = "byteArray";
private static final String SCHEMA_TYPE_FIELD = "schemaType";
- private static final String URI_FIELD = "uri";
+ private static final String ID_FIELD = "id";
private static final String SCORE_FIELD = "score";
private static final String TTL_MILLIS_FIELD = "ttlMillis";
private static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis";
@@ -82,24 +79,51 @@
/**
* The maximum number of indexed properties a document can have.
*
- * <p>Indexed properties are properties where the
- * {@link AppSearchSchema.PropertyConfig#getIndexingType()} constant is anything other than
- * {@link AppSearchSchema.PropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
+ * <p>Indexed properties are properties which are strings where the
+ * {@link AppSearchSchema.StringPropertyConfig#getIndexingType} value is anything other
+ * than {@link AppSearchSchema.StringPropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
*/
public static int getMaxIndexedProperties() {
return MAX_INDEXED_PROPERTIES;
}
- /** Contains {@link GenericDocument} basic information (uri, schemaType etc). */
+// @exportToFramework:startStrip()
+
+ /**
+ * Converts an instance of a class annotated with \@{@link Document} into an instance of
+ * {@link GenericDocument}.
+ *
+ * @param document An instance of a class annotated with \@{@link Document}.
+ * @return an instance of {@link GenericDocument} produced by converting {@code document}.
+ * @throws AppSearchException if no generated conversion class exists on the classpath for the
+ * given document class or an unexpected error occurs during
+ * conversion.
+ * @see GenericDocument#toDocumentClass
+ */
+ @NonNull
+ public static GenericDocument fromDocumentClass(@NonNull Object document)
+ throws AppSearchException {
+ Preconditions.checkNotNull(document);
+ DocumentClassFactoryRegistry registry = DocumentClassFactoryRegistry.getInstance();
+ DocumentClassFactory<Object> factory = registry.getOrCreateFactory(document);
+ return factory.toGenericDocument(document);
+ }
+// @exportToFramework:endStrip()
+
+ /**
+ * Contains all {@link GenericDocument} information in a packaged format.
+ *
+ * <p>Keys are the {@code *_FIELD} constants in this class.
+ */
@NonNull
final Bundle mBundle;
- /** Contains all properties in {@link GenericDocument} to support getting properties via keys */
+ /** Contains all properties in {@link GenericDocument} to support getting properties via name */
@NonNull
private final Bundle mProperties;
@NonNull
- private final String mUri;
+ private final String mId;
@NonNull
private final String mSchemaType;
private final long mCreationTimestampMillis;
@@ -107,11 +131,10 @@
private Integer mHashCode;
/**
- * Rebuilds a {@link GenericDocument} by the a bundle.
+ * Rebuilds a {@link GenericDocument} from a bundle.
*
- * @param bundle Contains {@link GenericDocument} basic information (uri, schemaType etc) and
- * a properties bundle contains all properties in {@link GenericDocument} to
- * support getting properties via keys.
+ * @param bundle Packaged {@link GenericDocument} data, such as the result of
+ * {@link #getBundle}.
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -119,7 +142,7 @@
Preconditions.checkNotNull(bundle);
mBundle = bundle;
mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
- mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
+ mId = Preconditions.checkNotNull(mBundle.getString(ID_FIELD));
mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
mCreationTimestampMillis = mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD,
System.currentTimeMillis());
@@ -145,19 +168,19 @@
return mBundle;
}
- /** Returns the URI of the {@link GenericDocument}. */
+ /** Returns the unique identifier of the {@link GenericDocument}. */
@NonNull
- public String getUri() {
- return mUri;
+ public String getId() {
+ return mId;
}
/** Returns the namespace of the {@link GenericDocument}. */
@NonNull
public String getNamespace() {
- return mBundle.getString(NAMESPACE_FIELD, DEFAULT_NAMESPACE);
+ return mBundle.getString(NAMESPACE_FIELD, /*defaultValue=*/ "");
}
- /** Returns the schema type of the {@link GenericDocument}. */
+ /** Returns the {@link AppSearchSchema} type of the {@link GenericDocument}. */
@NonNull
public String getSchemaType() {
return mSchemaType;
@@ -168,19 +191,20 @@
*
* <p>The value is in the {@link System#currentTimeMillis} time base.
*/
+ /*@exportToFramework:CurrentTimeMillisLong*/
public long getCreationTimestampMillis() {
return mCreationTimestampMillis;
}
/**
- * Returns the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
+ * Returns the TTL (time-to-live) of the {@link GenericDocument}, in milliseconds.
*
* <p>The TTL is measured against {@link #getCreationTimestampMillis}. At the timestamp of
* {@code creationTimestampMillis + ttlMillis}, measured in the {@link System#currentTimeMillis}
* time base, the document will be auto-deleted.
*
* <p>The default value is 0, which means the document is permanent and won't be auto-deleted
- * until the app is uninstalled.
+ * until the app is uninstalled or {@link AppSearchSession#remove} is called.
*/
public long getTtlMillis() {
return mBundle.getLong(TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
@@ -190,12 +214,12 @@
* Returns the score of the {@link GenericDocument}.
*
* <p>The score is a query-independent measure of the document's quality, relative to
- * other {@link GenericDocument}s of the same type.
+ * other {@link GenericDocument} objects of the same {@link AppSearchSchema} type.
*
* <p>Results may be sorted by score using {@link SearchSpec.Builder#setRankingStrategy}.
* Documents with higher scores are considered better than documents with lower scores.
*
- * <p>Any nonnegative integer can be used a score.
+ * <p>Any non-negative integer can be used a score.
*/
public int getScore() {
return mBundle.getInt(SCORE_FIELD, DEFAULT_SCORE);
@@ -208,133 +232,506 @@
}
/**
- * Retrieves the property value with the given key as {@link Object}.
+ * Retrieves the property value with the given path as {@link Object}.
*
- * @param key The key to look for.
- * @return The entry with the given key as an object or {@code null} if there is no such key.
+ * <p>A path can be a simple property name, such as those returned by {@link #getPropertyNames}.
+ * It may also be a dot-delimited path through the nested document hierarchy, with nested
+ * {@link GenericDocument} properties accessed via {@code '.'} and repeated properties
+ * optionally indexed into via {@code [n]}.
+ *
+ * <p>For example, given the following {@link GenericDocument}:
+ * <pre>
+ * (Message) {
+ * from: "sender@example.com"
+ * to: [{
+ * name: "Albert Einstein"
+ * email: "einstein@example.com"
+ * }, {
+ * name: "Marie Curie"
+ * email: "curie@example.com"
+ * }]
+ * tags: ["important", "inbox"]
+ * subject: "Hello"
+ * }
+ * </pre>
+ *
+ * <p>Here are some example paths and their results:
+ * <ul>
+ * <li>{@code "from"} returns {@code "sender@example.com"} as a {@link String} array with
+ * one element
+ * <li>{@code "to"} returns the two nested documents containing contact information as a
+ * {@link GenericDocument} array with two elements
+ * <li>{@code "to[1]"} returns the second nested document containing Marie Curie's
+ * contact information as a {@link GenericDocument} array with one element
+ * <li>{@code "to[1].email"} returns {@code "curie@example.com"}
+ * <li>{@code "to[100].email"} returns {@code null} as this particular document does not
+ * have that many elements in its {@code "to"} array.
+ * <li>{@code "to.email"} aggregates emails across all nested documents that have them,
+ * returning {@code ["einstein@example.com", "curie@example.com"]} as a {@link String}
+ * array with two elements.
+ * </ul>
+ *
+ * <p>If you know the expected type of the property you are retrieving, it is recommended to use
+ * one of the typed versions of this method instead, such as {@link #getPropertyString} or
+ * {@link #getPropertyStringArray}.
+ *
+ * @param path The path to look for.
+ * @return The entry with the given path as an object or {@code null} if there is no such path.
+ * The returned object will be one of the following types: {@code String[]}, {@code long[]},
+ * {@code double[]}, {@code boolean[]}, {@code byte[][]}, {@code GenericDocument[]}.
*/
@Nullable
- public Object getProperty(@NonNull String key) {
- Preconditions.checkNotNull(key);
- Object property = mProperties.get(key);
- if (property instanceof ArrayList) {
- return getPropertyBytesArray(key);
- } else if (property instanceof Bundle[]) {
- return getPropertyDocumentArray(key);
+ public Object getProperty(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ Object rawValue = getRawPropertyFromRawDocument(path, mBundle);
+
+ // Unpack the raw value into the types the user expects, if required.
+ if (rawValue instanceof Bundle) {
+ // getRawPropertyFromRawDocument may return a document as a bare Bundle as a performance
+ // optimization for lookups.
+ GenericDocument document = new GenericDocument((Bundle) rawValue);
+ return new GenericDocument[]{document};
}
- return property;
+
+ if (rawValue instanceof List) {
+ // byte[][] fields are packed into List<Bundle> where each Bundle contains just a single
+ // entry: BYTE_ARRAY_FIELD -> byte[].
+ @SuppressWarnings("unchecked")
+ List<Bundle> bundles = (List<Bundle>) rawValue;
+ if (bundles.size() == 0) {
+ return null;
+ }
+ byte[][] bytes = new byte[bundles.size()][];
+ for (int i = 0; i < bundles.size(); i++) {
+ Bundle bundle = bundles.get(i);
+ if (bundle == null) {
+ Log.e(TAG, "The inner bundle is null at " + i + ", for path: " + path);
+ continue;
+ }
+ byte[] innerBytes = bundle.getByteArray(BYTE_ARRAY_FIELD);
+ if (innerBytes == null) {
+ Log.e(TAG, "The bundle at " + i + " contains a null byte[].");
+ continue;
+ }
+ bytes[i] = innerBytes;
+ }
+ return bytes;
+ }
+
+ if (rawValue instanceof Parcelable[]) {
+ // The underlying Bundle of nested GenericDocuments is packed into a Parcelable array.
+ // We must unpack it into GenericDocument instances.
+ Parcelable[] bundles = (Parcelable[]) rawValue;
+ if (bundles.length == 0) {
+ return null;
+ }
+ GenericDocument[] documents = new GenericDocument[bundles.length];
+ for (int i = 0; i < bundles.length; i++) {
+ if (bundles[i] == null) {
+ Log.e(TAG, "The inner bundle is null at " + i + ", for path: " + path);
+ continue;
+ }
+ if (!(bundles[i] instanceof Bundle)) {
+ Log.e(TAG, "The inner element at " + i + " is a " + bundles[i].getClass()
+ + ", not a Bundle for path: " + path);
+ continue;
+ }
+ documents[i] = new GenericDocument((Bundle) bundles[i]);
+ }
+ return documents;
+ }
+
+ // Otherwise the raw property is the same as the final property and needs no transformation.
+ return rawValue;
}
/**
- * Retrieves a {@link String} value by key.
+ * Looks up a property path within the given document bundle.
*
- * @param key The key to look for.
- * @return The first {@link String} associated with the given key or {@code null} if there is
- * no such key or the value is of a different type.
+ * <p>The return value may be any of GenericDocument's internal repeated storage types
+ * (String[], long[], double[], boolean[], ArrayList<Bundle>, Parcelable[]).
*/
@Nullable
- public String getPropertyString(@NonNull String key) {
- Preconditions.checkNotNull(key);
- String[] propertyArray = getPropertyStringArray(key);
+ private static Object getRawPropertyFromRawDocument(
+ @NonNull String path, @NonNull Bundle documentBundle) {
+ Preconditions.checkNotNull(path);
+ Preconditions.checkNotNull(documentBundle);
+ Bundle properties = Preconditions.checkNotNull(documentBundle.getBundle(PROPERTIES_FIELD));
+
+ // Determine whether the path is just a raw property name with no control characters
+ int controlIdx = -1;
+ boolean controlIsIndex = false;
+ for (int i = 0; i < path.length(); i++) {
+ char c = path.charAt(i);
+ if (c == '[' || c == '.') {
+ controlIdx = i;
+ controlIsIndex = c == '[';
+ break;
+ }
+ }
+
+ // Look up the value of the first path element
+ Object firstElementValue;
+ if (controlIdx == -1) {
+ firstElementValue = properties.get(path);
+ } else {
+ String name = path.substring(0, controlIdx);
+ firstElementValue = properties.get(name);
+ }
+
+ // If the path has no further elements, we're done.
+ if (firstElementValue == null || controlIdx == -1) {
+ return firstElementValue;
+ }
+
+ // At this point, for a path like "recipients[0]", firstElementValue contains the value of
+ // "recipients". If the first element of the path is an indexed value, we now update
+ // firstElementValue to contain "recipients[0]" instead.
+ String remainingPath;
+ if (!controlIsIndex) {
+ // Remaining path is everything after the .
+ remainingPath = path.substring(controlIdx + 1);
+ } else {
+ int endBracketIdx = path.indexOf(']', controlIdx);
+ if (endBracketIdx == -1) {
+ throw new IllegalArgumentException("Malformed path (no ending ']'): " + path);
+ }
+ if (endBracketIdx + 1 < path.length() && path.charAt(endBracketIdx + 1) != '.') {
+ throw new IllegalArgumentException(
+ "Malformed path (']' not followed by '.'): " + path);
+ }
+ String indexStr = path.substring(controlIdx + 1, endBracketIdx);
+ int index = Integer.parseInt(indexStr);
+ if (index < 0) {
+ throw new IllegalArgumentException("Path index less than 0: " + path);
+ }
+
+ // Remaining path is everything after the [n]
+ if (endBracketIdx + 1 < path.length()) {
+ // More path remains, and we've already checked that charAt(endBracketIdx+1) == .
+ remainingPath = path.substring(endBracketIdx + 2);
+ } else {
+ // No more path remains.
+ remainingPath = null;
+ }
+
+ // Extract the right array element
+ Object extractedValue = null;
+ if (firstElementValue instanceof String[]) {
+ String[] stringValues = (String[]) firstElementValue;
+ if (index < stringValues.length) {
+ extractedValue = Arrays.copyOfRange(stringValues, index, index + 1);
+ }
+ } else if (firstElementValue instanceof long[]) {
+ long[] longValues = (long[]) firstElementValue;
+ if (index < longValues.length) {
+ extractedValue = Arrays.copyOfRange(longValues, index, index + 1);
+ }
+ } else if (firstElementValue instanceof double[]) {
+ double[] doubleValues = (double[]) firstElementValue;
+ if (index < doubleValues.length) {
+ extractedValue = Arrays.copyOfRange(doubleValues, index, index + 1);
+ }
+ } else if (firstElementValue instanceof boolean[]) {
+ boolean[] booleanValues = (boolean[]) firstElementValue;
+ if (index < booleanValues.length) {
+ extractedValue = Arrays.copyOfRange(booleanValues, index, index + 1);
+ }
+ } else if (firstElementValue instanceof List) {
+ @SuppressWarnings("unchecked")
+ List<Bundle> bundles = (List<Bundle>) firstElementValue;
+ if (index < bundles.size()) {
+ extractedValue = bundles.subList(index, index + 1);
+ }
+ } else if (firstElementValue instanceof Parcelable[]) {
+ // Special optimization: to avoid creating new singleton arrays for traversing paths
+ // we return the bare document Bundle in this particular case.
+ Parcelable[] bundles = (Parcelable[]) firstElementValue;
+ if (index < bundles.length) {
+ extractedValue = (Bundle) bundles[index];
+ }
+ } else {
+ throw new IllegalStateException("Unsupported value type: " + firstElementValue);
+ }
+ firstElementValue = extractedValue;
+ }
+
+ // If we are at the end of the path or there are no deeper elements in this document, we
+ // have nothing to recurse into.
+ if (firstElementValue == null || remainingPath == null) {
+ return firstElementValue;
+ }
+
+ // More of the path remains; recursively evaluate it
+ if (firstElementValue instanceof Bundle) {
+ return getRawPropertyFromRawDocument(remainingPath, (Bundle) firstElementValue);
+ } else if (firstElementValue instanceof Parcelable[]) {
+ Parcelable[] parcelables = (Parcelable[]) firstElementValue;
+ if (parcelables.length == 1) {
+ return getRawPropertyFromRawDocument(remainingPath, (Bundle) parcelables[0]);
+ }
+
+ // Slowest path: we're collecting values across repeated nested docs. (Example: given a
+ // path like recipient.name, where recipient is a repeated field, we return a string
+ // array where each recipient's name is an array element).
+ //
+ // Performance note: Suppose that we have a property path "a.b.c" where the "a"
+ // property has N document values and each containing a "b" property with M document
+ // values and each of those containing a "c" property with an int array.
+ //
+ // We'll allocate a new ArrayList for each of the "b" properties, add the M int arrays
+ // from the "c" properties to it and then we'll allocate an int array in
+ // flattenAccumulator before returning that (1 + M allocation per "b" property).
+ //
+ // When we're on the "a" properties, we'll allocate an ArrayList and add the N
+ // flattened int arrays returned from the "b" properties to the list. Then we'll
+ // allocate an int array in flattenAccumulator (1 + N ("b" allocs) allocations per "a").
+ // So this implementation could incur 1 + N + NM allocs.
+ //
+ // However, we expect the vast majority of getProperty calls to be either for direct
+ // property names (not paths) or else property paths returned from snippetting, which
+ // always refer to exactly one property value and don't aggregate across repeated
+ // values. The implementation is optimized for these two cases, requiring no additional
+ // allocations. So we've decided that the above performance characteristics are OK for
+ // the less used path.
+ List<Object> accumulator = new ArrayList<>(parcelables.length);
+ for (int i = 0; i < parcelables.length; i++) {
+ Object value =
+ getRawPropertyFromRawDocument(remainingPath, (Bundle) parcelables[i]);
+ if (value != null) {
+ accumulator.add(value);
+ }
+ }
+ return flattenAccumulator(accumulator);
+ } else {
+ Log.e(TAG, "Failed to apply path to document; no nested value found: " + path);
+ return null;
+ }
+ }
+
+ /**
+ * Combines accumulated repeated properties from multiple documents into a single array.
+ *
+ * @param accumulator List containing objects of the following types: {@code String[]},
+ * {@code long[]}, {@code double[]}, {@code boolean[]}, {@code List<Bundle>},
+ * or {@code Parcelable[]}.
+ * @return The result of concatenating each individual list element into a larger array/list of
+ * the same type.
+ */
+ @Nullable
+ private static Object flattenAccumulator(@NonNull List<Object> accumulator) {
+ if (accumulator.isEmpty()) {
+ return null;
+ }
+ Object first = accumulator.get(0);
+ if (first instanceof String[]) {
+ int length = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ length += ((String[]) accumulator.get(i)).length;
+ }
+ String[] result = new String[length];
+ int total = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ String[] castValue = (String[]) accumulator.get(i);
+ System.arraycopy(castValue, 0, result, total, castValue.length);
+ total += castValue.length;
+ }
+ return result;
+ }
+ if (first instanceof long[]) {
+ int length = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ length += ((long[]) accumulator.get(i)).length;
+ }
+ long[] result = new long[length];
+ int total = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ long[] castValue = (long[]) accumulator.get(i);
+ System.arraycopy(castValue, 0, result, total, castValue.length);
+ total += castValue.length;
+ }
+ return result;
+ }
+ if (first instanceof double[]) {
+ int length = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ length += ((double[]) accumulator.get(i)).length;
+ }
+ double[] result = new double[length];
+ int total = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ double[] castValue = (double[]) accumulator.get(i);
+ System.arraycopy(castValue, 0, result, total, castValue.length);
+ total += castValue.length;
+ }
+ return result;
+ }
+ if (first instanceof boolean[]) {
+ int length = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ length += ((boolean[]) accumulator.get(i)).length;
+ }
+ boolean[] result = new boolean[length];
+ int total = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ boolean[] castValue = (boolean[]) accumulator.get(i);
+ System.arraycopy(castValue, 0, result, total, castValue.length);
+ total += castValue.length;
+ }
+ return result;
+ }
+ if (first instanceof List) {
+ int length = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ length += ((List<?>) accumulator.get(i)).size();
+ }
+ List<Bundle> result = new ArrayList<>(length);
+ for (int i = 0; i < accumulator.size(); i++) {
+ @SuppressWarnings("unchecked")
+ List<Bundle> castValue = (List<Bundle>) accumulator.get(i);
+ result.addAll(castValue);
+ }
+ return result;
+ }
+ if (first instanceof Parcelable[]) {
+ int length = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ length += ((Parcelable[]) accumulator.get(i)).length;
+ }
+ Parcelable[] result = new Parcelable[length];
+ int total = 0;
+ for (int i = 0; i < accumulator.size(); i++) {
+ Parcelable[] castValue = (Parcelable[]) accumulator.get(i);
+ System.arraycopy(castValue, 0, result, total, castValue.length);
+ total += castValue.length;
+ }
+ return result;
+ }
+ throw new IllegalStateException("Unexpected property type: " + first);
+ }
+
+ /**
+ * Retrieves a {@link String} property by path.
+ *
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The first {@link String} associated with the given path or {@code null} if there is
+ * no such value or the value is of a different type.
+ */
+ @Nullable
+ public String getPropertyString(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ String[] propertyArray = getPropertyStringArray(path);
if (propertyArray == null || propertyArray.length == 0) {
return null;
}
- warnIfSinglePropertyTooLong("String", key, propertyArray.length);
+ warnIfSinglePropertyTooLong("String", path, propertyArray.length);
return propertyArray[0];
}
/**
- * Retrieves a {@code long} value by key.
+ * Retrieves a {@code long} property by path.
*
- * @param key The key to look for.
- * @return The first {@code long} associated with the given key or default value {@code 0} if
- * there is no such key or the value is of a different type.
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The first {@code long} associated with the given path or default value {@code 0} if
+ * there is no such value or the value is of a different type.
*/
- public long getPropertyLong(@NonNull String key) {
- Preconditions.checkNotNull(key);
- long[] propertyArray = getPropertyLongArray(key);
+ public long getPropertyLong(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ long[] propertyArray = getPropertyLongArray(path);
if (propertyArray == null || propertyArray.length == 0) {
return 0;
}
- warnIfSinglePropertyTooLong("Long", key, propertyArray.length);
+ warnIfSinglePropertyTooLong("Long", path, propertyArray.length);
return propertyArray[0];
}
/**
- * Retrieves a {@code double} value by key.
+ * Retrieves a {@code double} property by path.
*
- * @param key The key to look for.
- * @return The first {@code double} associated with the given key or default value {@code 0.0}
- * if there is no such key or the value is of a different type.
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The first {@code double} associated with the given path or default value {@code 0.0}
+ * if there is no such value or the value is of a different type.
*/
- public double getPropertyDouble(@NonNull String key) {
- Preconditions.checkNotNull(key);
- double[] propertyArray = getPropertyDoubleArray(key);
+ public double getPropertyDouble(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ double[] propertyArray = getPropertyDoubleArray(path);
if (propertyArray == null || propertyArray.length == 0) {
return 0.0;
}
- warnIfSinglePropertyTooLong("Double", key, propertyArray.length);
+ warnIfSinglePropertyTooLong("Double", path, propertyArray.length);
return propertyArray[0];
}
/**
- * Retrieves a {@code boolean} value by key.
+ * Retrieves a {@code boolean} property by path.
*
- * @param key The key to look for.
- * @return The first {@code boolean} associated with the given key or default value
- * {@code false} if there is no such key or the value is of a different type.
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The first {@code boolean} associated with the given path or default value
+ * {@code false} if there is no such value or the value is of a different type.
*/
- public boolean getPropertyBoolean(@NonNull String key) {
- Preconditions.checkNotNull(key);
- boolean[] propertyArray = getPropertyBooleanArray(key);
+ public boolean getPropertyBoolean(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ boolean[] propertyArray = getPropertyBooleanArray(path);
if (propertyArray == null || propertyArray.length == 0) {
return false;
}
- warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length);
+ warnIfSinglePropertyTooLong("Boolean", path, propertyArray.length);
return propertyArray[0];
}
/**
- * Retrieves a {@code byte[]} value by key.
+ * Retrieves a {@code byte[]} property by path.
*
- * @param key The key to look for.
- * @return The first {@code byte[]} associated with the given key or {@code null} if there is
- * no such key or the value is of a different type.
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The first {@code byte[]} associated with the given path or {@code null} if there is
+ * no such value or the value is of a different type.
*/
@Nullable
- public byte[] getPropertyBytes(@NonNull String key) {
- Preconditions.checkNotNull(key);
- byte[][] propertyArray = getPropertyBytesArray(key);
+ public byte[] getPropertyBytes(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ byte[][] propertyArray = getPropertyBytesArray(path);
if (propertyArray == null || propertyArray.length == 0) {
return null;
}
- warnIfSinglePropertyTooLong("ByteArray", key, propertyArray.length);
+ warnIfSinglePropertyTooLong("ByteArray", path, propertyArray.length);
return propertyArray[0];
}
/**
- * Retrieves a {@link GenericDocument} value by key.
+ * Retrieves a {@link GenericDocument} property by path.
*
- * @param key The key to look for.
- * @return The first {@link GenericDocument} associated with the given key or {@code null} if
- * there is no such key or the value is of a different type.
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The first {@link GenericDocument} associated with the given path or {@code null} if
+ * there is no such value or the value is of a different type.
*/
@Nullable
- public GenericDocument getPropertyDocument(@NonNull String key) {
- Preconditions.checkNotNull(key);
- GenericDocument[] propertyArray = getPropertyDocumentArray(key);
+ public GenericDocument getPropertyDocument(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ GenericDocument[] propertyArray = getPropertyDocumentArray(path);
if (propertyArray == null || propertyArray.length == 0) {
return null;
}
- warnIfSinglePropertyTooLong("Document", key, propertyArray.length);
+ warnIfSinglePropertyTooLong("Document", path, propertyArray.length);
return propertyArray[0];
}
/** Prints a warning to logcat if the given propertyLength is greater than 1. */
private static void warnIfSinglePropertyTooLong(
- @NonNull String propertyType, @NonNull String key, int propertyLength) {
+ @NonNull String propertyType, @NonNull String path, int propertyLength) {
if (propertyLength > 1) {
- Log.w(TAG, "The value for \"" + key + "\" contains " + propertyLength
+ Log.w(TAG, "The value for \"" + path + "\" contains " + propertyLength
+ " elements. Only the first one will be returned from "
+ "getProperty" + propertyType + "(). Try getProperty" + propertyType
+ "Array().");
@@ -342,158 +739,168 @@
}
/**
- * Retrieves a repeated {@code String} property by key.
+ * Retrieves a repeated {@code String} property by path.
*
- * @param key The key to look for.
- * @return The {@code String[]} associated with the given key, or {@code null} if no value is
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The {@code String[]} associated with the given path, or {@code null} if no value is
* set or the value is of a different type.
*/
@Nullable
- public String[] getPropertyStringArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
- return getAndCastPropertyArray(key, String[].class);
+ public String[] getPropertyStringArray(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ Object value = getProperty(path);
+ return safeCastProperty(path, value, String[].class);
}
/**
- * Retrieves a repeated {@link String} property by key.
+ * Retrieves a repeated {@code long[]} property by path.
*
- * @param key The key to look for.
- * @return The {@code long[]} associated with the given key, or {@code null} if no value is
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The {@code long[]} associated with the given path, or {@code null} if no value is
* set or the value is of a different type.
*/
@Nullable
- public long[] getPropertyLongArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
- return getAndCastPropertyArray(key, long[].class);
+ public long[] getPropertyLongArray(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ Object value = getProperty(path);
+ return safeCastProperty(path, value, long[].class);
}
/**
- * Retrieves a repeated {@code double} property by key.
+ * Retrieves a repeated {@code double} property by path.
*
- * @param key The key to look for.
- * @return The {@code double[]} associated with the given key, or {@code null} if no value is
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The {@code double[]} associated with the given path, or {@code null} if no value is
* set or the value is of a different type.
*/
@Nullable
- public double[] getPropertyDoubleArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
- return getAndCastPropertyArray(key, double[].class);
+ public double[] getPropertyDoubleArray(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ Object value = getProperty(path);
+ return safeCastProperty(path, value, double[].class);
}
/**
- * Retrieves a repeated {@code boolean} property by key.
+ * Retrieves a repeated {@code boolean} property by path.
*
- * @param key The key to look for.
- * @return The {@code boolean[]} associated with the given key, or {@code null} if no value
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The {@code boolean[]} associated with the given path, or {@code null} if no value
* is set or the value is of a different type.
*/
@Nullable
- public boolean[] getPropertyBooleanArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
- return getAndCastPropertyArray(key, boolean[].class);
+ public boolean[] getPropertyBooleanArray(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ Object value = getProperty(path);
+ return safeCastProperty(path, value, boolean[].class);
}
/**
- * Retrieves a {@code byte[][]} property by key.
+ * Retrieves a {@code byte[][]} property by path.
*
- * @param key The key to look for.
- * @return The {@code byte[][]} associated with the given key, or {@code null} if no value is
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The {@code byte[][]} associated with the given path, or {@code null} if no value is
* set or the value is of a different type.
*/
@SuppressLint("ArrayReturn")
@Nullable
- @SuppressWarnings("unchecked")
- public byte[][] getPropertyBytesArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
- ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
- if (bundles == null || bundles.size() == 0) {
- return null;
- }
- byte[][] bytes = new byte[bundles.size()][];
- for (int i = 0; i < bundles.size(); i++) {
- Bundle bundle = bundles.get(i);
- if (bundle == null) {
- Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
- continue;
- }
- byte[] innerBytes = bundle.getByteArray(BYTE_ARRAY_FIELD);
- if (innerBytes == null) {
- Log.e(TAG, "The bundle at " + i + " contains a null byte[].");
- continue;
- }
- bytes[i] = innerBytes;
- }
- return bytes;
+ public byte[][] getPropertyBytesArray(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ Object value = getProperty(path);
+ return safeCastProperty(path, value, byte[][].class);
}
/**
- * Retrieves a repeated {@link GenericDocument} property by key.
+ * Retrieves a repeated {@link GenericDocument} property by path.
*
- * @param key The key to look for.
- * @return The {@link GenericDocument}[] associated with the given key, or {@code null} if no
+ * <p>See {@link #getProperty} for a detailed description of the path syntax.
+ *
+ * @param path The path to look for.
+ * @return The {@link GenericDocument}[] associated with the given path, or {@code null} if no
* value is set or the value is of a different type.
*/
@SuppressLint("ArrayReturn")
@Nullable
- public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
- Bundle[] bundles = getAndCastPropertyArray(key, Bundle[].class);
- if (bundles == null || bundles.length == 0) {
- return null;
- }
- GenericDocument[] documents = new GenericDocument[bundles.length];
- for (int i = 0; i < bundles.length; i++) {
- if (bundles[i] == null) {
- Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
- continue;
- }
- documents[i] = new GenericDocument(bundles[i]);
- }
- return documents;
+ public GenericDocument[] getPropertyDocumentArray(@NonNull String path) {
+ Preconditions.checkNotNull(path);
+ Object value = getProperty(path);
+ return safeCastProperty(path, value, GenericDocument[].class);
}
/**
- * Gets a repeated property of the given key, and casts it to the given class type, which
- * must be an array class type.
+ * Casts a repeated property to the provided type, logging an error and returning {@code null}
+ * if the cast fails.
+ *
+ * @param path Path to the property within the document. Used for logging.
+ * @param value Value of the property
+ * @param tClass Class to cast the value into
*/
@Nullable
- private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) {
- Object value = mProperties.get(key);
+ private static <T> T safeCastProperty(
+ @NonNull String path, @Nullable Object value, @NonNull Class<T> tClass) {
if (value == null) {
return null;
}
try {
return tClass.cast(value);
} catch (ClassCastException e) {
- Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e);
+ Log.w(TAG, "Error casting to requested type for path \"" + path + "\"", e);
return null;
}
}
// @exportToFramework:startStrip()
+
/**
- * Converts this GenericDocument into an instance of the provided data class.
+ * Converts this GenericDocument into an instance of the provided document class.
*
- * <p>It is the developer's responsibility to ensure the right kind of data class is being
+ * <p>It is the developer's responsibility to ensure the right kind of document class is being
* supplied here, either by structuring the application code to ensure the document type is
* known, or by checking the return value of {@link #getSchemaType}.
*
- * <p>Document properties are identified by String keys and any that are found are assigned into
- * fields of the given data class, so the most likely outcome of supplying the wrong data class
- * would be an empty or partially populated result.
+ * <p>Document properties are identified by {@code String} names. Any that are found are
+ * assigned into fields of the given document class. As such, the most likely outcome of
+ * supplying the wrong document class would be an empty or partially populated result.
*
- * @param dataClass a class annotated with
- * {@link androidx.appsearch.annotation.AppSearchDocument}.
+ * @param documentClass a class annotated with {@link Document}
+ * @return an instance of the document class after being converted from a
+ * {@link GenericDocument}
+ * @throws AppSearchException if no factory for this document class could be found on the
+ * classpath.
+ * @see GenericDocument#fromDocumentClass
*/
@NonNull
- public <T> T toDataClass(@NonNull Class<T> dataClass) throws AppSearchException {
- Preconditions.checkNotNull(dataClass);
- DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
- DataClassFactory<T> factory = registry.getOrCreateFactory(dataClass);
+ public <T> T toDocumentClass(@NonNull Class<T> documentClass) throws AppSearchException {
+ Preconditions.checkNotNull(documentClass);
+ DocumentClassFactoryRegistry registry = DocumentClassFactoryRegistry.getInstance();
+ DocumentClassFactory<T> factory = registry.getOrCreateFactory(documentClass);
return factory.fromGenericDocument(this);
}
// @exportToFramework:endStrip()
+ /**
+ * Copies the contents of this {@link GenericDocument} into a new
+ * {@link GenericDocument.Builder}.
+ *
+ * <p>The returned builder is a deep copy whose data is separate from this document.
+ * <!--@exportToFramework:hide-->
+ */
+ // TODO(b/171882200): Expose this API in Android T
+ @NonNull
+ public GenericDocument.Builder<GenericDocument.Builder<?>> toBuilder() {
+ Bundle clonedBundle = BundleUtil.deepCopy(mBundle);
+ return new GenericDocument.Builder<>(clonedBundle);
+ }
+
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
@@ -517,64 +924,100 @@
@Override
@NonNull
public String toString() {
- return bundleToString(mBundle).toString();
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendGenericDocumentString(stringBuilder);
+ return stringBuilder.toString();
}
- @SuppressWarnings("unchecked")
- private static StringBuilder bundleToString(Bundle bundle) {
- StringBuilder stringBuilder = new StringBuilder();
- try {
- final Set<String> keySet = bundle.keySet();
- String[] keys = keySet.toArray(new String[0]);
- // Sort keys to make output deterministic. We need a custom comparator to handle
- // nulls (arbitrarily putting them first, similar to Comparator.nullsFirst, which is
- // only available since N).
- Arrays.sort(
- keys,
- (@Nullable String s1, @Nullable String s2) -> {
- if (s1 == null) {
- return s2 == null ? 0 : -1;
- } else if (s2 == null) {
- return 1;
- } else {
- return s1.compareTo(s2);
- }
- });
- for (String key : keys) {
- stringBuilder.append("{ key: '").append(key).append("' value: ");
- Object valueObject = bundle.get(key);
- if (valueObject == null) {
- stringBuilder.append("<null>");
- } else if (valueObject instanceof Bundle) {
- stringBuilder.append(bundleToString((Bundle) valueObject));
- } else if (valueObject.getClass().isArray()) {
- stringBuilder.append("[ ");
- for (int i = 0; i < Array.getLength(valueObject); i++) {
- Object element = Array.get(valueObject, i);
- stringBuilder.append("'");
- if (element instanceof Bundle) {
- stringBuilder.append(bundleToString((Bundle) element));
- } else {
- stringBuilder.append(Array.get(valueObject, i));
- }
- stringBuilder.append("' ");
- }
- stringBuilder.append("]");
- } else if (valueObject instanceof ArrayList) {
- for (Bundle innerBundle : (ArrayList<Bundle>) valueObject) {
- stringBuilder.append(bundleToString(innerBundle));
- }
- } else {
- stringBuilder.append(valueObject.toString());
- }
- stringBuilder.append(" } ");
+ /**
+ * Appends a debug string for the {@link GenericDocument} instance to the given string builder.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendGenericDocumentString(@NonNull IndentingStringBuilder builder) {
+ Preconditions.checkNotNull(builder);
+
+ builder.append("{\n");
+ builder.increaseIndentLevel();
+
+ builder.append("namespace: \"").append(getNamespace()).append("\",\n");
+ builder.append("id: \"").append(getId()).append("\",\n");
+ builder.append("score: ").append(getScore()).append(",\n");
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ builder
+ .append("creationTimestampMillis: ")
+ .append(getCreationTimestampMillis())
+ .append(",\n");
+ builder.append("timeToLiveMillis: ").append(getTtlMillis()).append(",\n");
+
+ builder.append("properties: {\n");
+
+ String[] sortedProperties = getPropertyNames().toArray(new String[0]);
+ Arrays.sort(sortedProperties);
+
+ for (int i = 0; i < sortedProperties.length; i++) {
+ Object property = getProperty(sortedProperties[i]);
+ builder.increaseIndentLevel();
+ appendPropertyString(sortedProperties[i], property, builder);
+ if (i != sortedProperties.length - 1) {
+ builder.append(",\n");
}
- } catch (RuntimeException e) {
- // Catch any exceptions here since corrupt Bundles can throw different types of
- // exceptions (e.g. b/38445840 & b/68937025).
- stringBuilder.append("<error>");
+ builder.decreaseIndentLevel();
}
- return stringBuilder;
+
+ builder.append("\n");
+ builder.append("}");
+
+ builder.decreaseIndentLevel();
+ builder.append("\n");
+ builder.append("}");
+ }
+
+ /**
+ * Appends a debug string for the given document property to the given string builder.
+ *
+ * @param propertyName name of property to create string for.
+ * @param property property object to create string for.
+ * @param builder the builder to append to.
+ */
+ private void appendPropertyString(@NonNull String propertyName, @NonNull Object property,
+ @NonNull IndentingStringBuilder builder) {
+ Preconditions.checkNotNull(propertyName);
+ Preconditions.checkNotNull(property);
+ Preconditions.checkNotNull(builder);
+
+ builder.append("\"").append(propertyName).append("\": [");
+ if (property instanceof GenericDocument[]) {
+ GenericDocument[] documentValues = (GenericDocument[]) property;
+ for (int i = 0; i < documentValues.length; ++i) {
+ builder.append("\n");
+ builder.increaseIndentLevel();
+ documentValues[i].appendGenericDocumentString(builder);
+ if (i != documentValues.length - 1) {
+ builder.append(",");
+ }
+ builder.append("\n");
+ builder.decreaseIndentLevel();
+ }
+ builder.append("]");
+ } else {
+ int propertyArrLength = Array.getLength(property);
+ for (int i = 0; i < propertyArrLength; i++) {
+ Object propertyElement = Array.get(property, i);
+ if (propertyElement instanceof String) {
+ builder.append("\"").append((String) propertyElement).append("\"");
+ } else if (propertyElement instanceof byte[]) {
+ builder.append(Arrays.toString((byte[]) propertyElement));
+ } else {
+ builder.append(propertyElement.toString());
+ }
+ if (i != propertyArrLength - 1) {
+ builder.append(", ");
+ } else {
+ builder.append("]");
+ }
+ }
+ }
}
/**
@@ -586,73 +1029,126 @@
// GenericDocument.
@SuppressLint("StaticFinalBuilder")
public static class Builder<BuilderType extends Builder> {
-
- private final Bundle mProperties = new Bundle();
- private final Bundle mBundle = new Bundle();
+ private Bundle mBundle;
+ private Bundle mProperties;
private final BuilderType mBuilderTypeInstance;
private boolean mBuilt = false;
/**
- * Create a new {@link GenericDocument.Builder}.
+ * Creates a new {@link GenericDocument.Builder}.
*
- * @param uri The uri of {@link GenericDocument}.
- * @param schemaType The schema type of the {@link GenericDocument}. The passed-in
- * {@code schemaType} must be defined using
+ * <p>Document IDs are unique within a namespace.
+ *
+ * <p>The number of namespaces per app should be kept small for efficiency reasons.
+ *
+ * @param namespace the namespace to set for the {@link GenericDocument}.
+ * @param id the unique identifier for the {@link GenericDocument} in its namespace.
+ * @param schemaType the {@link AppSearchSchema} type of the {@link GenericDocument}. The
+ * provided {@code schemaType} must be defined using
* {@link AppSearchSession#setSchema} prior
* to inserting a document of this {@code schemaType} into the
* AppSearch index using
- * {@link AppSearchSession#putDocuments}. Otherwise, the document will be
- * rejected by {@link AppSearchSession#putDocuments}.
+ * {@link AppSearchSession#put}.
+ * Otherwise, the document will be rejected by
+ * {@link AppSearchSession#put} with result code
+ * {@link AppSearchResult#RESULT_NOT_FOUND}.
*/
@SuppressWarnings("unchecked")
- public Builder(@NonNull String uri, @NonNull String schemaType) {
- Preconditions.checkNotNull(uri);
+ public Builder(@NonNull String namespace, @NonNull String id, @NonNull String schemaType) {
+ Preconditions.checkNotNull(namespace);
+ Preconditions.checkNotNull(id);
Preconditions.checkNotNull(schemaType);
+
+ mBundle = new Bundle();
mBuilderTypeInstance = (BuilderType) this;
- mBundle.putString(GenericDocument.URI_FIELD, uri);
+ mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
+ mBundle.putString(GenericDocument.ID_FIELD, id);
mBundle.putString(GenericDocument.SCHEMA_TYPE_FIELD, schemaType);
- mBundle.putString(GenericDocument.NAMESPACE_FIELD, DEFAULT_NAMESPACE);
- // Set current timestamp for creation timestamp by default.
- mBundle.putLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD,
- System.currentTimeMillis());
mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
mBundle.putInt(GenericDocument.SCORE_FIELD, DEFAULT_SCORE);
+
+ mProperties = new Bundle();
mBundle.putBundle(PROPERTIES_FIELD, mProperties);
}
/**
- * Sets the app-defined namespace this Document resides in. No special values are
- * reserved or understood by the infrastructure.
+ * Creates a new {@link GenericDocument.Builder} from the given Bundle.
*
- * <p>URIs are unique within a namespace.
+ * <p>The bundle is NOT copied.
+ */
+ @SuppressWarnings("unchecked")
+ Builder(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ mProperties = mBundle.getBundle(PROPERTIES_FIELD);
+ mBuilderTypeInstance = (BuilderType) this;
+ }
+
+ /**
+ * Sets the app-defined namespace this document resides in, changing the value provided
+ * in the constructor. No special values are reserved or understood by the infrastructure.
+ *
+ * <p>Document IDs are unique within a namespace.
*
* <p>The number of namespaces per app should be kept small for efficiency reasons.
+ * <!--@exportToFramework:hide-->
*/
@NonNull
public BuilderType setNamespace(@NonNull String namespace) {
+ Preconditions.checkNotNull(namespace);
+ resetIfBuilt();
mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
return mBuilderTypeInstance;
}
/**
+ * Sets the ID of this document, changing the value provided in the constructor. No
+ * special values are reserved or understood by the infrastructure.
+ *
+ * <p>Document IDs are unique within a namespace.
+ * <!--@exportToFramework:hide-->
+ */
+ @NonNull
+ public BuilderType setId(@NonNull String id) {
+ Preconditions.checkNotNull(id);
+ resetIfBuilt();
+ mBundle.putString(GenericDocument.ID_FIELD, id);
+ return mBuilderTypeInstance;
+ }
+
+ /**
+ * Sets the schema type of this document, changing the value provided in the constructor.
+ *
+ * <p>To successfully index a document, the schema type must match the name of an
+ * {@link AppSearchSchema} object previously provided to {@link AppSearchSession#setSchema}.
+ * <!--@exportToFramework:hide-->
+ */
+ @NonNull
+ public BuilderType setSchemaType(@NonNull String schemaType) {
+ Preconditions.checkNotNull(schemaType);
+ resetIfBuilt();
+ mBundle.putString(GenericDocument.SCHEMA_TYPE_FIELD, schemaType);
+ return mBuilderTypeInstance;
+ }
+
+ /**
* Sets the score of the {@link GenericDocument}.
*
* <p>The score is a query-independent measure of the document's quality, relative to
- * other {@link GenericDocument}s of the same type.
+ * other {@link GenericDocument} objects of the same {@link AppSearchSchema} type.
*
* <p>Results may be sorted by score using {@link SearchSpec.Builder#setRankingStrategy}.
* Documents with higher scores are considered better than documents with lower scores.
*
- * <p>Any nonnegative integer can be used a score.
+ * <p>Any non-negative integer can be used a score. By default, scores are set to 0.
*
- * @throws IllegalArgumentException If the provided value is negative.
+ * @param score any non-negative {@code int} representing the document's score.
*/
@NonNull
public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
if (score < 0) {
throw new IllegalArgumentException("Document score cannot be negative.");
}
+ resetIfBuilt();
mBundle.putInt(GenericDocument.SCORE_FIELD, score);
return mBuilderTypeInstance;
}
@@ -660,36 +1156,41 @@
/**
* Sets the creation timestamp of the {@link GenericDocument}, in milliseconds.
*
- * <p>Should be set using a value obtained from the {@link System#currentTimeMillis} time
- * base.
+ * <p>This should be set using a value obtained from the {@link System#currentTimeMillis}
+ * time base.
+ *
+ * <p>If this method is not called, this will be set to the time the object is built.
+ *
+ * @param creationTimestampMillis a creation timestamp in milliseconds.
*/
@NonNull
- public BuilderType setCreationTimestampMillis(long creationTimestampMillis) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBundle.putLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD,
- creationTimestampMillis);
+ public BuilderType setCreationTimestampMillis(
+ /*@exportToFramework:CurrentTimeMillisLong*/ long creationTimestampMillis) {
+ resetIfBuilt();
+ mBundle.putLong(
+ GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD, creationTimestampMillis);
return mBuilderTypeInstance;
}
/**
- * Sets the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
+ * Sets the TTL (time-to-live) of the {@link GenericDocument}, in milliseconds.
*
* <p>The TTL is measured against {@link #getCreationTimestampMillis}. At the timestamp of
* {@code creationTimestampMillis + ttlMillis}, measured in the
* {@link System#currentTimeMillis} time base, the document will be auto-deleted.
*
* <p>The default value is 0, which means the document is permanent and won't be
- * auto-deleted until the app is uninstalled.
+ * auto-deleted until the app is uninstalled or {@link AppSearchSession#remove} is
+ * called.
*
- * @param ttlMillis A non-negative duration in milliseconds.
- * @throws IllegalArgumentException If the provided value is negative.
+ * @param ttlMillis a non-negative duration in milliseconds.
*/
@NonNull
public BuilderType setTtlMillis(long ttlMillis) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
if (ttlMillis < 0) {
throw new IllegalArgumentException("Document ttlMillis cannot be negative.");
}
+ resetIfBuilt();
mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, ttlMillis);
return mBuilderTypeInstance;
}
@@ -698,15 +1199,19 @@
* Sets one or multiple {@code String} values for a property, replacing its previous
* values.
*
- * @param key The key associated with the {@code values}.
- * @param values The {@code String} values of the property.
+ * @param name the name associated with the {@code values}. Must match the name
+ * for this property as given in
+ * {@link AppSearchSchema.PropertyConfig#getName}.
+ * @param values the {@code String} values of the property.
+ * @throws IllegalArgumentException if no values are provided, or if a passed in
+ * {@code String} is {@code null}.
*/
@NonNull
- public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ public BuilderType setPropertyString(@NonNull String name, @NonNull String... values) {
+ Preconditions.checkNotNull(name);
Preconditions.checkNotNull(values);
- putInPropertyBundle(key, values);
+ resetIfBuilt();
+ putInPropertyBundle(name, values);
return mBuilderTypeInstance;
}
@@ -714,15 +1219,17 @@
* Sets one or multiple {@code boolean} values for a property, replacing its previous
* values.
*
- * @param key The key associated with the {@code values}.
- * @param values The {@code boolean} values of the property.
+ * @param name the name associated with the {@code values}. Must match the name
+ * for this property as given in
+ * {@link AppSearchSchema.PropertyConfig#getName}.
+ * @param values the {@code boolean} values of the property.
*/
@NonNull
- public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ public BuilderType setPropertyBoolean(@NonNull String name, @NonNull boolean... values) {
+ Preconditions.checkNotNull(name);
Preconditions.checkNotNull(values);
- putInPropertyBundle(key, values);
+ resetIfBuilt();
+ putInPropertyBundle(name, values);
return mBuilderTypeInstance;
}
@@ -730,15 +1237,17 @@
* Sets one or multiple {@code long} values for a property, replacing its previous
* values.
*
- * @param key The key associated with the {@code values}.
- * @param values The {@code long} values of the property.
+ * @param name the name associated with the {@code values}. Must match the name
+ * for this property as given in
+ * {@link AppSearchSchema.PropertyConfig#getName}.
+ * @param values the {@code long} values of the property.
*/
@NonNull
- public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ public BuilderType setPropertyLong(@NonNull String name, @NonNull long... values) {
+ Preconditions.checkNotNull(name);
Preconditions.checkNotNull(values);
- putInPropertyBundle(key, values);
+ resetIfBuilt();
+ putInPropertyBundle(name, values);
return mBuilderTypeInstance;
}
@@ -746,30 +1255,36 @@
* Sets one or multiple {@code double} values for a property, replacing its previous
* values.
*
- * @param key The key associated with the {@code values}.
- * @param values The {@code double} values of the property.
+ * @param name the name associated with the {@code values}. Must match the name
+ * for this property as given in
+ * {@link AppSearchSchema.PropertyConfig#getName}.
+ * @param values the {@code double} values of the property.
*/
@NonNull
- public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ public BuilderType setPropertyDouble(@NonNull String name, @NonNull double... values) {
+ Preconditions.checkNotNull(name);
Preconditions.checkNotNull(values);
- putInPropertyBundle(key, values);
+ resetIfBuilt();
+ putInPropertyBundle(name, values);
return mBuilderTypeInstance;
}
/**
* Sets one or multiple {@code byte[]} for a property, replacing its previous values.
*
- * @param key The key associated with the {@code values}.
- * @param values The {@code byte[]} of the property.
+ * @param name the name associated with the {@code values}. Must match the name
+ * for this property as given in
+ * {@link AppSearchSchema.PropertyConfig#getName}.
+ * @param values the {@code byte[]} of the property.
+ * @throws IllegalArgumentException if no values are provided, or if a passed in
+ * {@code byte[]} is {@code null}.
*/
@NonNull
- public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ public BuilderType setPropertyBytes(@NonNull String name, @NonNull byte[]... values) {
+ Preconditions.checkNotNull(name);
Preconditions.checkNotNull(values);
- putInPropertyBundle(key, values);
+ resetIfBuilt();
+ putInPropertyBundle(name, values);
return mBuilderTypeInstance;
}
@@ -777,47 +1292,59 @@
* Sets one or multiple {@link GenericDocument} values for a property, replacing its
* previous values.
*
- * @param key The key associated with the {@code values}.
- * @param values The {@link GenericDocument} values of the property.
+ * @param name the name associated with the {@code values}. Must match the name
+ * for this property as given in
+ * {@link AppSearchSchema.PropertyConfig#getName}.
+ * @param values the {@link GenericDocument} values of the property.
+ * @throws IllegalArgumentException if no values are provided, or if a passed in
+ * {@link GenericDocument} is {@code null}.
*/
@NonNull
public BuilderType setPropertyDocument(
- @NonNull String key, @NonNull GenericDocument... values) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
+ @NonNull String name, @NonNull GenericDocument... values) {
+ Preconditions.checkNotNull(name);
Preconditions.checkNotNull(values);
- putInPropertyBundle(key, values);
+ resetIfBuilt();
+ putInPropertyBundle(name, values);
return mBuilderTypeInstance;
}
- private void putInPropertyBundle(@NonNull String key, @NonNull String[] values)
+ /**
+ * Clears the value for the property with the given name.
+ *
+ * <p>Note that this method does not support property paths.
+ *
+ * @param name The name of the property to clear.
+ * <!--@exportToFramework:hide-->
+ */
+ @NonNull
+ public BuilderType clearProperty(@NonNull String name) {
+ Preconditions.checkNotNull(name);
+ resetIfBuilt();
+ mProperties.remove(name);
+ return mBuilderTypeInstance;
+ }
+
+ private void putInPropertyBundle(@NonNull String name, @NonNull String[] values)
throws IllegalArgumentException {
- validateRepeatedPropertyLength(key, values.length);
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("The String at " + i + " is null.");
- } else if (values[i].length() > MAX_STRING_LENGTH) {
- throw new IllegalArgumentException("The String at " + i + " length is: "
- + values[i].length() + ", which exceeds length limit: "
- + MAX_STRING_LENGTH + ".");
}
}
- mProperties.putStringArray(key, values);
+ mProperties.putStringArray(name, values);
}
- private void putInPropertyBundle(@NonNull String key, @NonNull boolean[] values) {
- validateRepeatedPropertyLength(key, values.length);
- mProperties.putBooleanArray(key, values);
+ private void putInPropertyBundle(@NonNull String name, @NonNull boolean[] values) {
+ mProperties.putBooleanArray(name, values);
}
- private void putInPropertyBundle(@NonNull String key, @NonNull double[] values) {
- validateRepeatedPropertyLength(key, values.length);
- mProperties.putDoubleArray(key, values);
+ private void putInPropertyBundle(@NonNull String name, @NonNull double[] values) {
+ mProperties.putDoubleArray(name, values);
}
- private void putInPropertyBundle(@NonNull String key, @NonNull long[] values) {
- validateRepeatedPropertyLength(key, values.length);
- mProperties.putLongArray(key, values);
+ private void putInPropertyBundle(@NonNull String name, @NonNull long[] values) {
+ mProperties.putLongArray(name, values);
}
/**
@@ -826,8 +1353,7 @@
* <p>Bundle doesn't support for two dimension array byte[][], we are converting byte[][]
* into ArrayList<Bundle>, and each elements will contain a one dimension byte[].
*/
- private void putInPropertyBundle(@NonNull String key, @NonNull byte[][] values) {
- validateRepeatedPropertyLength(key, values.length);
+ private void putInPropertyBundle(@NonNull String name, @NonNull byte[][] values) {
ArrayList<Bundle> bundles = new ArrayList<>(values.length);
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
@@ -837,38 +1363,38 @@
bundle.putByteArray(BYTE_ARRAY_FIELD, values[i]);
bundles.add(bundle);
}
- mProperties.putParcelableArrayList(key, bundles);
+ mProperties.putParcelableArrayList(name, bundles);
}
- private void putInPropertyBundle(@NonNull String key, @NonNull GenericDocument[] values) {
- validateRepeatedPropertyLength(key, values.length);
- Bundle[] documentBundles = new Bundle[values.length];
+ private void putInPropertyBundle(@NonNull String name, @NonNull GenericDocument[] values) {
+ Parcelable[] documentBundles = new Parcelable[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("The document at " + i + " is null.");
}
documentBundles[i] = values[i].mBundle;
}
- mProperties.putParcelableArray(key, documentBundles);
- }
-
- private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
- if (length == 0) {
- throw new IllegalArgumentException("The input array is empty.");
- } else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
- throw new IllegalArgumentException(
- "Repeated property \"" + key + "\" has length " + length
- + ", which exceeds the limit of "
- + MAX_REPEATED_PROPERTY_LENGTH);
- }
+ mProperties.putParcelableArray(name, documentBundles);
}
/** Builds the {@link GenericDocument} object. */
@NonNull
public GenericDocument build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
mBuilt = true;
+ // Set current timestamp for creation timestamp by default.
+ if (mBundle.getLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD, -1) == -1) {
+ mBundle.putLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD,
+ System.currentTimeMillis());
+ }
return new GenericDocument(mBundle);
}
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mBundle = BundleUtil.deepCopy(mBundle);
+ mProperties = mBundle.getBundle(PROPERTIES_FIELD);
+ mBuilt = false;
+ }
+ }
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByDocumentIdRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByDocumentIdRequest.java
new file mode 100644
index 0000000..d9bfc0d
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByDocumentIdRequest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.collection.ArrayMap;
+import androidx.collection.ArraySet;
+import androidx.core.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to retrieve documents by namespace and IDs from the
+ * {@link AppSearchSession} database.
+ *
+ * @see AppSearchSession#getByDocumentId
+ */
+public final class GetByDocumentIdRequest {
+ /**
+ * Schema type to be used in
+ * {@link GetByDocumentIdRequest.Builder#addProjection}
+ * to apply property paths to all results, excepting any types that have had their own, specific
+ * property paths set.
+ */
+ public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
+ private final String mNamespace;
+ private final Set<String> mIds;
+ private final Map<String, List<String>> mTypePropertyPathsMap;
+
+ GetByDocumentIdRequest(@NonNull String namespace, @NonNull Set<String> ids, @NonNull Map<String,
+ List<String>> typePropertyPathsMap) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mIds = Preconditions.checkNotNull(ids);
+ mTypePropertyPathsMap = Preconditions.checkNotNull(typePropertyPathsMap);
+ }
+
+ /** Returns the namespace attached to the request. */
+ @NonNull
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ /** Returns the set of document IDs attached to the request. */
+ @NonNull
+ public Set<String> getIds() {
+ return Collections.unmodifiableSet(mIds);
+ }
+
+ /**
+ * Returns a map from schema type to property paths to be used for projection.
+ *
+ * <p>If the map is empty, then all properties will be retrieved for all results.
+ *
+ * <p>Calling this function repeatedly is inefficient. Prefer to retain the Map returned
+ * by this function, rather than calling it multiple times.
+ */
+ @NonNull
+ public Map<String, List<String>> getProjections() {
+ Map<String, List<String>> copy = new ArrayMap<>();
+ for (Map.Entry<String, List<String>> entry : mTypePropertyPathsMap.entrySet()) {
+ copy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
+ }
+ return copy;
+ }
+
+ /**
+ * Returns a map from schema type to property paths to be used for projection.
+ *
+ * <p>If the map is empty, then all properties will be retrieved for all results.
+ *
+ * <p>A more efficient version of {@link #getProjections}, but it returns a modifiable map.
+ * This is not meant to be unhidden and should only be used by internal classes.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ public Map<String, List<String>> getProjectionsInternal() {
+ return mTypePropertyPathsMap;
+ }
+
+ /** Builder for {@link GetByDocumentIdRequest} objects. */
+ public static final class Builder {
+ private final String mNamespace;
+ private ArraySet<String> mIds = new ArraySet<>();
+ private ArrayMap<String, List<String>> mProjectionTypePropertyPaths = new ArrayMap<>();
+ private boolean mBuilt = false;
+
+ /** Creates a {@link GetByDocumentIdRequest.Builder} instance. */
+ public Builder(@NonNull String namespace) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ }
+
+ /** Adds one or more document IDs to the request. */
+ @NonNull
+ public Builder addIds(@NonNull String... ids) {
+ Preconditions.checkNotNull(ids);
+ resetIfBuilt();
+ return addIds(Arrays.asList(ids));
+ }
+
+ /** Adds a collection of IDs to the request. */
+ @NonNull
+ public Builder addIds(@NonNull Collection<String> ids) {
+ Preconditions.checkNotNull(ids);
+ resetIfBuilt();
+ mIds.addAll(ids);
+ return this;
+ }
+
+ /**
+ * Adds property paths for the specified type to be used for projection. If property
+ * paths are added for a type, then only the properties referred to will be retrieved for
+ * results of that type. If a property path that is specified isn't present in a result,
+ * it will be ignored for that result. Property paths cannot be null.
+ *
+ * <p>If no property paths are added for a particular type, then all properties of
+ * results of that type will be retrieved.
+ *
+ * <p>If property path is added for the
+ * {@link GetByDocumentIdRequest#PROJECTION_SCHEMA_TYPE_WILDCARD}, then those property paths
+ * will apply to all results, excepting any types that have their own, specific property
+ * paths set.
+ *
+ * @see SearchSpec.Builder#addProjection
+ */
+ @NonNull
+ public Builder addProjection(
+ @NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
+ Preconditions.checkNotNull(schemaType);
+ Preconditions.checkNotNull(propertyPaths);
+ resetIfBuilt();
+ List<String> propertyPathsList = new ArrayList<>(propertyPaths.size());
+ for (String propertyPath : propertyPaths) {
+ Preconditions.checkNotNull(propertyPath);
+ propertyPathsList.add(propertyPath);
+ }
+ mProjectionTypePropertyPaths.put(schemaType, propertyPathsList);
+ return this;
+ }
+
+ /** Builds a new {@link GetByDocumentIdRequest}. */
+ @NonNull
+ public GetByDocumentIdRequest build() {
+ mBuilt = true;
+ return new GetByDocumentIdRequest(mNamespace, mIds, mProjectionTypePropertyPaths);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mIds = new ArraySet<>(mIds);
+ // No need to clone each propertyPathsList inside mProjectionTypePropertyPaths since
+ // the builder only replaces it, never adds to it. So even if the builder is used
+ // again, the previous one will remain with the object.
+ mProjectionTypePropertyPaths = new ArrayMap<>(mProjectionTypePropertyPaths);
+ mBuilt = false;
+ }
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByUriRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByUriRequest.java
deleted file mode 100644
index 9461790..0000000
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByUriRequest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app;
-
-import androidx.annotation.NonNull;
-import androidx.collection.ArraySet;
-import androidx.core.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Encapsulates a request to retrieve documents by namespace and URI.
- *
- * @see AppSearchSession#getByUri
- */
-public final class GetByUriRequest {
- private final String mNamespace;
- private final Set<String> mUris;
-
- GetByUriRequest(@NonNull String namespace, @NonNull Set<String> uris) {
- mNamespace = namespace;
- mUris = uris;
- }
-
- /** Returns the namespace to get documents from. */
- @NonNull
- public String getNamespace() {
- return mNamespace;
- }
-
- /** Returns the URIs to get from the namespace. */
- @NonNull
- public Set<String> getUris() {
- return Collections.unmodifiableSet(mUris);
- }
-
- /** Builder for {@link GetByUriRequest} objects. */
- public static final class Builder {
- private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
- private final Set<String> mUris = new ArraySet<>();
- private boolean mBuilt = false;
-
- /**
- * Sets which namespace these documents will be retrieved from.
- *
- * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
- */
- @NonNull
- public Builder setNamespace(@NonNull String namespace) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(namespace);
- mNamespace = namespace;
- return this;
- }
-
- /** Adds one or more URIs to the request. */
- @NonNull
- public Builder addUri(@NonNull String... uris) {
- Preconditions.checkNotNull(uris);
- return addUri(Arrays.asList(uris));
- }
-
- /** Adds one or more URIs to the request. */
- @NonNull
- public Builder addUri(@NonNull Collection<String> uris) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uris);
- mUris.addAll(uris);
- return this;
- }
-
- /** Builds a new {@link GetByUriRequest}. */
- @NonNull
- public GetByUriRequest build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBuilt = true;
- return new GetByUriRequest(mNamespace, mUris);
- }
- }
-}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetSchemaResponse.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetSchemaResponse.java
new file mode 100644
index 0000000..03c1f21
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetSchemaResponse.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import android.os.Bundle;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.collection.ArraySet;
+import androidx.core.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+/** The response class of {@link AppSearchSession#getSchema} */
+public final class GetSchemaResponse {
+ private static final String VERSION_FIELD = "version";
+ private static final String SCHEMAS_FIELD = "schemas";
+
+ private final Bundle mBundle;
+
+ GetSchemaResponse(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ }
+
+ /**
+ * Returns the {@link Bundle} populated by this builder.
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public Bundle getBundle() {
+ return mBundle;
+ }
+
+ /**
+ * Returns the overall database schema version.
+ *
+ * <p>If the database is empty, 0 will be returned.
+ */
+ @IntRange(from = 0)
+ public int getVersion() {
+ return mBundle.getInt(VERSION_FIELD);
+ }
+
+ /**
+ * Return the schemas most recently successfully provided to
+ * {@link AppSearchSession#setSchema}.
+ *
+ * <p>It is inefficient to call this method repeatedly.
+ */
+ @NonNull
+ public Set<AppSearchSchema> getSchemas() {
+ ArrayList<Bundle> schemaBundles = mBundle.getParcelableArrayList(SCHEMAS_FIELD);
+ Set<AppSearchSchema> schemas = new ArraySet<>(schemaBundles.size());
+ for (int i = 0; i < schemaBundles.size(); i++) {
+ schemas.add(new AppSearchSchema(schemaBundles.get(i)));
+ }
+ return schemas;
+ }
+
+ /** Builder for {@link GetSchemaResponse} objects. */
+ public static final class Builder {
+ private int mVersion = 0;
+ private ArrayList<Bundle> mSchemaBundles = new ArrayList<>();
+ private boolean mBuilt = false;
+
+ /**
+ * Sets the database overall schema version.
+ *
+ * <p>Default version is 0
+ */
+ @NonNull
+ public Builder setVersion(@IntRange(from = 0) int version) {
+ resetIfBuilt();
+ mVersion = version;
+ return this;
+ }
+
+ /** Adds one {@link AppSearchSchema} to the schema list. */
+ @NonNull
+ public Builder addSchema(@NonNull AppSearchSchema schema) {
+ Preconditions.checkNotNull(schema);
+ resetIfBuilt();
+ mSchemaBundles.add(schema.getBundle());
+ return this;
+ }
+
+ /** Builds a {@link GetSchemaResponse} object. */
+ @NonNull
+ public GetSchemaResponse build() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(VERSION_FIELD, mVersion);
+ bundle.putParcelableArrayList(SCHEMAS_FIELD, mSchemaBundles);
+ mBuilt = true;
+ return new GetSchemaResponse(bundle);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mSchemaBundles = new ArrayList<>(mSchemaBundles);
+ mBuilt = false;
+ }
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GlobalSearchSession.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GlobalSearchSession.java
index fc35552..8b7dbe9 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GlobalSearchSession.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GlobalSearchSession.java
@@ -18,54 +18,66 @@
import androidx.annotation.NonNull;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.Closeable;
+
/**
- * This class provides global access to the centralized AppSearch index maintained by the system.
+ * Provides a connection to all AppSearch databases the querying application has been
+ * granted access to.
*
- * <p>Apps can retrieve indexed documents through the query API.
+ * <p>All implementations of this interface must be thread safe.
+ *
+ * @see AppSearchSession
*/
-public interface GlobalSearchSession {
+public interface GlobalSearchSession extends Closeable {
/**
- * Searches across all documents in the storage based on a given query string.
+ * Retrieves documents from all AppSearch databases that the querying application has access to.
*
- * <p>Currently we support following features in the raw query format:
- * <ul>
- * <li>AND
- * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
- * ‘cat’”).
- * Example: hello world matches documents that have both ‘hello’ and ‘world’
- * <li>OR
- * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
- * ‘cat’”).
- * Example: dog OR puppy
- * <li>Exclusion
- * <p>Exclude a term (e.g. “match documents that do
- * not have the term ‘dog’”).
- * Example: -dog excludes the term ‘dog’
- * <li>Grouping terms
- * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
- * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
- * Example: (dog puppy) (cat kitten) two one group containing two terms.
- * <li>Property restricts
- * <p> Specifies which properties of a document to specifically match terms in (e.g.
- * “match documents where the ‘subject’ property contains ‘important’”).
- * Example: subject:important matches documents with the term ‘important’ in the
- * ‘subject’ property
- * <li>Schema type restricts
- * <p>This is similar to property restricts, but allows for restricts on top-level document
- * fields, such as schema_type. Clients should be able to limit their query to documents of
- * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
- * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
- * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
- * ‘Video’ schema type.
- * </ul>
+ * <p>Applications can be granted access to documents by specifying
+ * {@link SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage}, or
+ * {@link SetSchemaRequest.Builder#setDocumentClassVisibilityForPackage} when building a schema.
*
- * <p> This method is lightweight. The heavy work will be done in
- * {@link SearchResults#getNextPage()}.
+ * <p>Document access can also be granted to system UIs by specifying
+ * {@link SetSchemaRequest.Builder#setSchemaTypeDisplayedBySystem}, or
+ * {@link SetSchemaRequest.Builder#setDocumentClassDisplayedBySystem}
+ * when building a schema.
*
- * @param queryExpression Query String to search.
- * @param searchSpec Spec for setting filters, raw query etc.
- * @return The search result of performing this operation.
+ * <p>See {@link AppSearchSession#search} for a detailed explanation on
+ * forming a query string.
+ *
+ * <p>This method is lightweight. The heavy work will be done in
+ * {@link SearchResults#getNextPage}.
+ *
+ * @param queryExpression query string to search.
+ * @param searchSpec spec for setting document filters, adding projection, setting term
+ * match type, etc.
+ * @return a {@link SearchResults} object for retrieved matched documents.
*/
@NonNull
- SearchResults query(@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
+ SearchResults search(@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
+
+ /**
+ * Reports that a particular document has been used from a system surface.
+ *
+ * <p>See {@link AppSearchSession#reportUsage} for a general description of document usage, as
+ * well as an API that can be used by the app itself.
+ *
+ * <p>Usage reported via this method is accounted separately from usage reported via
+ * {@link AppSearchSession#reportUsage} and may be accessed using the constants
+ * {@link SearchSpec#RANKING_STRATEGY_SYSTEM_USAGE_COUNT} and
+ * {@link SearchSpec#RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP}.
+ *
+ * @return The pending result of performing this operation which resolves to {@code null} on
+ * success. The pending result will be completed with an
+ * {@link androidx.appsearch.exceptions.AppSearchException} with a code of
+ * {@link AppSearchResult#RESULT_SECURITY_ERROR} if this API is invoked by an app which
+ * is not part of the system.
+ */
+ @NonNull
+ ListenableFuture<Void> reportSystemUsage(@NonNull ReportSystemUsageRequest request);
+
+ /** Closes the {@link GlobalSearchSession}. */
+ @Override
+ void close();
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/Migrator.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/Migrator.java
new file mode 100644
index 0000000..b47735b
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/Migrator.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.WorkerThread;
+
+/**
+ * A migrator class to translate {@link GenericDocument} from different version of
+ * {@link AppSearchSchema}
+ *
+ * <p>Make non-backwards-compatible changes will delete all stored documents in old schema. You
+ * can save your documents by setting {@link Migrator} via the
+ * {@link SetSchemaRequest.Builder#setMigrator} for each type and target version you want to save.
+ *
+ * <p>{@link #onDowngrade} or {@link #onUpgrade} will be triggered if the version number of the
+ * schema stored in AppSearch is different with the version in the request.
+ *
+ * <p>If any error or Exception occurred in the {@link #onDowngrade} or {@link #onUpgrade}, all the
+ * setSchema request will be rejected unless the schema changes are backwards-compatible, and stored
+ * documents won't have any observable changes.
+ */
+public abstract class Migrator {
+ /**
+ * Returns {@code true} if this migrator's source type needs to be migrated to update from
+ * currentVersion to finalVersion.
+ *
+ * <p>Migration won't be triggered if currentVersion is equal to finalVersion even if
+ * {@link #shouldMigrate} return true;
+ */
+ public abstract boolean shouldMigrate(int currentVersion, int finalVersion);
+
+ /**
+ * Migrates {@link GenericDocument} to a newer version of {@link AppSearchSchema}.
+ *
+ * <p>This method will be invoked only if the {@link SetSchemaRequest} is setting a
+ * higher version number than the current {@link AppSearchSchema} saved in AppSearch.
+ *
+ * <p>If this {@link Migrator} is provided to cover a compatible schema change via
+ * {@link AppSearchSession#setSchema}, documents under the old version won't be removed
+ * unless you use the same document ID.
+ *
+ * <p>This method will be invoked on the background worker thread provided via
+ * {@link AppSearchSession#setSchema}.
+ *
+ * @param currentVersion The current version of the document's schema.
+ * @param finalVersion The final version that documents need to be migrated to.
+ * @param document The {@link GenericDocument} need to be translated to new version.
+ * @return A {@link GenericDocument} in new version.
+ */
+ @WorkerThread
+ @NonNull
+ public abstract GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document);
+
+ /**
+ * Migrates {@link GenericDocument} to an older version of {@link AppSearchSchema}.
+ *
+ * <p>This method will be invoked only if the {@link SetSchemaRequest} is setting a
+ * lower version number than the current {@link AppSearchSchema} saved in AppSearch.
+ *
+ * <p>If this {@link Migrator} is provided to cover a compatible schema change via
+ * {@link AppSearchSession#setSchema}, documents under the old version won't be removed
+ * unless you use the same document ID.
+ *
+ * <p>This method will be invoked on the background worker thread.
+ *
+ * @param currentVersion The current version of the document's schema.
+ * @param finalVersion The final version that documents need to be migrated to.
+ * @param document The {@link GenericDocument} need to be translated to new version.
+ * @return A {@link GenericDocument} in new version.
+ */
+ @WorkerThread
+ @NonNull
+ public abstract GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document);
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/PackageIdentifier.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/PackageIdentifier.java
index 17d6fae..5d54f23 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/PackageIdentifier.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/PackageIdentifier.java
@@ -16,16 +16,19 @@
package androidx.appsearch.app;
-import androidx.annotation.NonNull;
-import androidx.core.util.ObjectsCompat;
-import androidx.core.util.Preconditions;
+import android.os.Bundle;
-import java.util.Arrays;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.util.BundleUtil;
+import androidx.core.util.Preconditions;
/** This class represents a uniquely identifiable package. */
public class PackageIdentifier {
- private final String mPackageName;
- private final byte[] mSha256Certificate;
+ private static final String PACKAGE_NAME_FIELD = "packageName";
+ private static final String SHA256_CERTIFICATE_FIELD = "sha256Certificate";
+
+ private final Bundle mBundle;
/**
* Creates a unique identifier for a package.
@@ -34,18 +37,32 @@
* @param sha256Certificate SHA256 certificate digest of the package.
*/
public PackageIdentifier(@NonNull String packageName, @NonNull byte[] sha256Certificate) {
- mPackageName = Preconditions.checkNotNull(packageName);
- mSha256Certificate = Preconditions.checkNotNull(sha256Certificate);
+ mBundle = new Bundle();
+ mBundle.putString(PACKAGE_NAME_FIELD, packageName);
+ mBundle.putByteArray(SHA256_CERTIFICATE_FIELD, sha256Certificate);
+ }
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public PackageIdentifier(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ }
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ public Bundle getBundle() {
+ return mBundle;
}
@NonNull
public String getPackageName() {
- return mPackageName;
+ return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
}
@NonNull
public byte[] getSha256Certificate() {
- return mSha256Certificate;
+ return Preconditions.checkNotNull(mBundle.getByteArray(SHA256_CERTIFICATE_FIELD));
}
@Override
@@ -57,12 +74,11 @@
return false;
}
final PackageIdentifier other = (PackageIdentifier) obj;
- return this.mPackageName.equals(other.mPackageName)
- && Arrays.equals(this.mSha256Certificate, other.mSha256Certificate);
+ return BundleUtil.deepEquals(mBundle, other.mBundle);
}
@Override
public int hashCode() {
- return ObjectsCompat.hash(mPackageName, Arrays.hashCode(mSha256Certificate));
+ return BundleUtil.deepHashCode(mBundle);
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/PutDocumentsRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/PutDocumentsRequest.java
index 17d424e..4d4a000 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/PutDocumentsRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/PutDocumentsRequest.java
@@ -29,9 +29,15 @@
import java.util.List;
/**
- * Encapsulates a request to index a document into an {@link AppSearchSession} database.
+ * Encapsulates a request to index documents into an {@link AppSearchSession} database.
*
- * <p>@see AppSearchSession#putDocuments
+ * <!--@exportToFramework:ifJetpack()-->
+ * <p>Documents added to the request can be instances of classes annotated with
+ * {@link androidx.appsearch.annotation.Document} or instances of
+ * {@link GenericDocument}.
+ * <!--@exportToFramework:else()-->
+ *
+ * @see AppSearchSession#put
*/
public final class PutDocumentsRequest {
private final List<GenericDocument> mDocuments;
@@ -40,95 +46,90 @@
mDocuments = documents;
}
- /** Returns the documents that are part of this request. */
+ /** Returns a list of {@link GenericDocument} objects that are part of this request. */
@NonNull
- public List<GenericDocument> getDocuments() {
+ public List<GenericDocument> getGenericDocuments() {
return Collections.unmodifiableList(mDocuments);
}
- /**
- * Builder for {@link PutDocumentsRequest} objects.
- *
- * <p>Once {@link #build} is called, the instance can no longer be used.
- */
+ /** Builder for {@link PutDocumentsRequest} objects. */
public static final class Builder {
- private final List<GenericDocument> mDocuments = new ArrayList<>();
+ private ArrayList<GenericDocument> mDocuments = new ArrayList<>();
private boolean mBuilt = false;
/** Adds one or more {@link GenericDocument} objects to the request. */
- @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
@NonNull
- public Builder addGenericDocument(@NonNull GenericDocument... documents) {
+ public Builder addGenericDocuments(@NonNull GenericDocument... documents) {
Preconditions.checkNotNull(documents);
- return addGenericDocument(Arrays.asList(documents));
+ resetIfBuilt();
+ return addGenericDocuments(Arrays.asList(documents));
}
/** Adds a collection of {@link GenericDocument} objects to the request. */
- @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
@NonNull
- public Builder addGenericDocument(
+ public Builder addGenericDocuments(
@NonNull Collection<? extends GenericDocument> documents) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(documents);
+ resetIfBuilt();
mDocuments.addAll(documents);
return this;
}
// @exportToFramework:startStrip()
/**
- * Adds one or more annotated {@link androidx.appsearch.annotation.AppSearchDocument}
+ * Adds one or more annotated {@link androidx.appsearch.annotation.Document}
* documents to the request.
*
- * @param dataClasses annotated
- * {@link androidx.appsearch.annotation.AppSearchDocument} documents.
- * @throws AppSearchException if an error occurs converting a data class into a
+ * @param documents annotated
+ * {@link androidx.appsearch.annotation.Document} documents.
+ * @throws AppSearchException if an error occurs converting a document class into a
* {@link GenericDocument}.
*/
- @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
+ // Merged list available from getGenericDocuments()
+ @SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder addDataClass(@NonNull Object... dataClasses) throws AppSearchException {
- Preconditions.checkNotNull(dataClasses);
- return addDataClass(Arrays.asList(dataClasses));
+ public Builder addDocuments(@NonNull Object... documents) throws AppSearchException {
+ Preconditions.checkNotNull(documents);
+ resetIfBuilt();
+ return addDocuments(Arrays.asList(documents));
}
/**
* Adds a collection of annotated
- * {@link androidx.appsearch.annotation.AppSearchDocument} documents to the request.
+ * {@link androidx.appsearch.annotation.Document} documents to the request.
*
- * @param dataClasses annotated
- * {@link androidx.appsearch.annotation.AppSearchDocument} documents.
- * @throws AppSearchException if an error occurs converting a data class into a
+ * @param documents annotated
+ * {@link androidx.appsearch.annotation.Document} documents.
+ * @throws AppSearchException if an error occurs converting a document into a
* {@link GenericDocument}.
*/
- @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
+ // Merged list available from getGenericDocuments()
+ @SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder addDataClass(@NonNull Collection<?> dataClasses)
- throws AppSearchException {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(dataClasses);
- List<GenericDocument> genericDocuments = new ArrayList<>(dataClasses.size());
- for (Object dataClass : dataClasses) {
- GenericDocument genericDocument = toGenericDocument(dataClass);
+ public Builder addDocuments(@NonNull Collection<?> documents) throws AppSearchException {
+ Preconditions.checkNotNull(documents);
+ resetIfBuilt();
+ List<GenericDocument> genericDocuments = new ArrayList<>(documents.size());
+ for (Object document : documents) {
+ GenericDocument genericDocument = GenericDocument.fromDocumentClass(document);
genericDocuments.add(genericDocument);
}
- return addGenericDocument(genericDocuments);
- }
-
- @NonNull
- private static <T> GenericDocument toGenericDocument(@NonNull T dataClass)
- throws AppSearchException {
- DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
- DataClassFactory<T> factory = registry.getOrCreateFactory(dataClass);
- return factory.toGenericDocument(dataClass);
+ return addGenericDocuments(genericDocuments);
}
// @exportToFramework:endStrip()
/** Creates a new {@link PutDocumentsRequest} object. */
@NonNull
public PutDocumentsRequest build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
mBuilt = true;
return new PutDocumentsRequest(mDocuments);
}
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mDocuments = new ArrayList<>(mDocuments);
+ mBuilt = false;
+ }
+ }
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByDocumentIdRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByDocumentIdRequest.java
new file mode 100644
index 0000000..addb96a
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByDocumentIdRequest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.collection.ArraySet;
+import androidx.core.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to remove documents by namespace and IDs from the
+ * {@link AppSearchSession} database.
+ *
+ * @see AppSearchSession#remove
+ */
+public final class RemoveByDocumentIdRequest {
+ private final String mNamespace;
+ private final Set<String> mIds;
+
+ RemoveByDocumentIdRequest(String namespace, Set<String> ids) {
+ mNamespace = namespace;
+ mIds = ids;
+ }
+
+ /** Returns the namespace to remove documents from. */
+ @NonNull
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ /** Returns the set of document IDs attached to the request. */
+ @NonNull
+ public Set<String> getIds() {
+ return Collections.unmodifiableSet(mIds);
+ }
+
+ /** Builder for {@link RemoveByDocumentIdRequest} objects. */
+ public static final class Builder {
+ private final String mNamespace;
+ private ArraySet<String> mIds = new ArraySet<>();
+ private boolean mBuilt = false;
+
+ /** Creates a {@link RemoveByDocumentIdRequest.Builder} instance. */
+ public Builder(@NonNull String namespace) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ }
+
+ /** Adds one or more document IDs to the request. */
+ @NonNull
+ public Builder addIds(@NonNull String... ids) {
+ Preconditions.checkNotNull(ids);
+ resetIfBuilt();
+ return addIds(Arrays.asList(ids));
+ }
+
+ /** Adds a collection of IDs to the request. */
+ @NonNull
+ public Builder addIds(@NonNull Collection<String> ids) {
+ Preconditions.checkNotNull(ids);
+ resetIfBuilt();
+ mIds.addAll(ids);
+ return this;
+ }
+
+ /** Builds a new {@link RemoveByDocumentIdRequest}. */
+ @NonNull
+ public RemoveByDocumentIdRequest build() {
+ mBuilt = true;
+ return new RemoveByDocumentIdRequest(mNamespace, mIds);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mIds = new ArraySet<>(mIds);
+ mBuilt = false;
+ }
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByUriRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByUriRequest.java
deleted file mode 100644
index ed7cad9..0000000
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByUriRequest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.app;
-
-import androidx.annotation.NonNull;
-import androidx.collection.ArraySet;
-import androidx.core.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Encapsulates a request to remove documents by namespace and URI.
- *
- * @see AppSearchSession#removeByUri
- */
-public final class RemoveByUriRequest {
- private final String mNamespace;
- private final Set<String> mUris;
-
- RemoveByUriRequest(String namespace, Set<String> uris) {
- mNamespace = namespace;
- mUris = uris;
- }
-
- /** Returns the namespace to remove documents from. */
- @NonNull
- public String getNamespace() {
- return mNamespace;
- }
-
- /** Returns the URIs of documents to remove from the namespace. */
- @NonNull
- public Set<String> getUris() {
- return Collections.unmodifiableSet(mUris);
- }
-
- /** Builder for {@link RemoveByUriRequest} objects. */
- public static final class Builder {
- private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
- private final Set<String> mUris = new ArraySet<>();
- private boolean mBuilt = false;
-
- /**
- * Sets which namespace these documents will be removed from.
- *
- * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
- */
- @NonNull
- public Builder setNamespace(@NonNull String namespace) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(namespace);
- mNamespace = namespace;
- return this;
- }
-
- /** Adds one or more URIs to the request. */
- @NonNull
- public Builder addUri(@NonNull String... uris) {
- Preconditions.checkNotNull(uris);
- return addUri(Arrays.asList(uris));
- }
-
- /** Adds one or more URIs to the request. */
- @NonNull
- public Builder addUri(@NonNull Collection<String> uris) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uris);
- mUris.addAll(uris);
- return this;
- }
-
- /** Builds a new {@link RemoveByUriRequest}. */
- @NonNull
- public RemoveByUriRequest build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBuilt = true;
- return new RemoveByUriRequest(mNamespace, mUris);
- }
- }
-}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
new file mode 100644
index 0000000..db26931
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Preconditions;
+
+/**
+ * A request to report usage of a document owned by another app from a system UI surface.
+ *
+ * <p>Usage reported in this way is measured separately from usage reported via
+ * {@link AppSearchSession#reportUsage}.
+ *
+ * <p>See {@link GlobalSearchSession#reportSystemUsage} for a detailed description of usage
+ * reporting.
+ */
+public final class ReportSystemUsageRequest {
+ private final String mPackageName;
+ private final String mDatabase;
+ private final String mNamespace;
+ private final String mDocumentId;
+ private final long mUsageTimestampMillis;
+
+ ReportSystemUsageRequest(
+ @NonNull String packageName,
+ @NonNull String database,
+ @NonNull String namespace,
+ @NonNull String documentId,
+ long usageTimestampMillis) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabase = Preconditions.checkNotNull(database);
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mDocumentId = Preconditions.checkNotNull(documentId);
+ mUsageTimestampMillis = usageTimestampMillis;
+ }
+
+ /** Returns the package name of the app which owns the document that was used. */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns the database in which the document that was used resides. */
+ @NonNull
+ public String getDatabaseName() {
+ return mDatabase;
+ }
+
+ /** Returns the namespace of the document that was used. */
+ @NonNull
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ /** Returns the ID of document that was used. */
+ @NonNull
+ public String getDocumentId() {
+ return mDocumentId;
+ }
+
+ /**
+ * Returns the timestamp in milliseconds of the usage report (the time at which the document
+ * was used).
+ *
+ * <p>The value is in the {@link System#currentTimeMillis} time base.
+ */
+ /*@exportToFramework:CurrentTimeMillisLong*/
+ public long getUsageTimestampMillis() {
+ return mUsageTimestampMillis;
+ }
+
+ /** Builder for {@link ReportSystemUsageRequest} objects. */
+ public static final class Builder {
+ private final String mPackageName;
+ private final String mDatabase;
+ private final String mNamespace;
+ private final String mDocumentId;
+ private Long mUsageTimestampMillis;
+
+ /**
+ * Creates a {@link ReportSystemUsageRequest.Builder} instance.
+ *
+ * @param packageName The package name of the app which owns the document that was used
+ * (e.g. from {@link SearchResult#getPackageName}).
+ * @param databaseName The database in which the document that was used resides (e.g. from
+ * {@link SearchResult#getDatabaseName}).
+ * @param namespace The namespace of the document that was used (e.g. from
+ * {@link GenericDocument#getNamespace}.
+ * @param documentId The ID of document that was used (e.g. from
+ * {@link GenericDocument#getId}.
+ */
+ public Builder(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull String namespace,
+ @NonNull String documentId) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabase = Preconditions.checkNotNull(databaseName);
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mDocumentId = Preconditions.checkNotNull(documentId);
+ }
+
+ /**
+ * Sets the timestamp in milliseconds of the usage report (the time at which the document
+ * was used).
+ *
+ * <p>The value is in the {@link System#currentTimeMillis} time base.
+ *
+ * <p>If unset, this defaults to the current timestamp at the time that the
+ * {@link ReportSystemUsageRequest} is constructed.
+ */
+ @NonNull
+ public ReportSystemUsageRequest.Builder setUsageTimestampMillis(
+ /*@exportToFramework:CurrentTimeMillisLong*/ long usageTimestampMillis) {
+ mUsageTimestampMillis = usageTimestampMillis;
+ return this;
+ }
+
+ /** Builds a new {@link ReportSystemUsageRequest}. */
+ @NonNull
+ public ReportSystemUsageRequest build() {
+ if (mUsageTimestampMillis == null) {
+ mUsageTimestampMillis = System.currentTimeMillis();
+ }
+ return new ReportSystemUsageRequest(
+ mPackageName, mDatabase, mNamespace, mDocumentId, mUsageTimestampMillis);
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
new file mode 100644
index 0000000..25edaf4
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Preconditions;
+
+/**
+ * A request to report usage of a document.
+ *
+ * <p>See {@link AppSearchSession#reportUsage} for a detailed description of usage reporting.
+ *
+ * @see AppSearchSession#reportUsage
+ */
+public final class ReportUsageRequest {
+ private final String mNamespace;
+ private final String mDocumentId;
+ private final long mUsageTimestampMillis;
+
+ ReportUsageRequest(
+ @NonNull String namespace, @NonNull String documentId, long usageTimestampMillis) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mDocumentId = Preconditions.checkNotNull(documentId);
+ mUsageTimestampMillis = usageTimestampMillis;
+ }
+
+ /** Returns the namespace of the document that was used. */
+ @NonNull
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ /** Returns the ID of document that was used. */
+ @NonNull
+ public String getDocumentId() {
+ return mDocumentId;
+ }
+
+ /**
+ * Returns the timestamp in milliseconds of the usage report (the time at which the document
+ * was used).
+ *
+ * <p>The value is in the {@link System#currentTimeMillis} time base.
+ */
+ /*@exportToFramework:CurrentTimeMillisLong*/
+ public long getUsageTimestampMillis() {
+ return mUsageTimestampMillis;
+ }
+
+ /** Builder for {@link ReportUsageRequest} objects. */
+ public static final class Builder {
+ private final String mNamespace;
+ private final String mDocumentId;
+ private Long mUsageTimestampMillis;
+
+ /**
+ * Creates a new {@link ReportUsageRequest.Builder} instance.
+ *
+ * @param namespace The namespace of the document that was used (e.g. from
+ * {@link GenericDocument#getNamespace}.
+ * @param documentId The ID of document that was used (e.g. from
+ * {@link GenericDocument#getId}.
+ */
+ public Builder(@NonNull String namespace, @NonNull String documentId) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mDocumentId = Preconditions.checkNotNull(documentId);
+ }
+
+ /**
+ * Sets the timestamp in milliseconds of the usage report (the time at which the document
+ * was used).
+ *
+ * <p>The value is in the {@link System#currentTimeMillis} time base.
+ *
+ * <p>If unset, this defaults to the current timestamp at the time that the
+ * {@link ReportUsageRequest} is constructed.
+ */
+ @NonNull
+ public ReportUsageRequest.Builder setUsageTimestampMillis(
+ /*@exportToFramework:CurrentTimeMillisLong*/ long usageTimestampMillis) {
+ mUsageTimestampMillis = usageTimestampMillis;
+ return this;
+ }
+
+ /** Builds a new {@link ReportUsageRequest}. */
+ @NonNull
+ public ReportUsageRequest build() {
+ if (mUsageTimestampMillis == null) {
+ mUsageTimestampMillis = System.currentTimeMillis();
+ }
+ return new ReportUsageRequest(mNamespace, mDocumentId, mUsageTimestampMillis);
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResult.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResult.java
index dcddb5e..0ce8f77 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResult.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResult.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.exceptions.AppSearchException;
import androidx.core.util.ObjectsCompat;
import androidx.core.util.Preconditions;
@@ -32,9 +33,9 @@
*
* <p>This allows clients to obtain:
* <ul>
- * <li>The document which matched, using {@link #getDocument}
+ * <li>The document which matched, using {@link #getGenericDocument}
* <li>Information about which properties in the document matched, and "snippet" information
- * containing textual summaries of the document's matches, using {@link #getMatches}
+ * containing textual summaries of the document's matches, using {@link #getMatchInfos}
* </ul>
*
* <p>"Snippet" refers to a substring of text from the content of document that is returned as a
@@ -43,17 +44,11 @@
* @see SearchResults
*/
public final class SearchResult {
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String DOCUMENT_FIELD = "document";
-
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String MATCHES_FIELD = "matches";
-
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String PACKAGE_NAME_FIELD = "packageName";
+ static final String DOCUMENT_FIELD = "document";
+ static final String MATCH_INFOS_FIELD = "matchInfos";
+ static final String PACKAGE_NAME_FIELD = "packageName";
+ static final String DATABASE_NAME_FIELD = "databaseName";
+ static final String RANKING_SIGNAL_FIELD = "rankingSignal";
@NonNull
private final Bundle mBundle;
@@ -64,7 +59,7 @@
/** Cache of the inflated matches. Comes from inflating mMatchBundles at first use. */
@Nullable
- private List<MatchInfo> mMatches;
+ private List<MatchInfo> mMatchInfos;
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -79,13 +74,30 @@
return mBundle;
}
+// @exportToFramework:startStrip()
+ /**
+ * Contains the matching document, converted to the given document class.
+ *
+ * <p>This is equivalent to calling {@code getGenericDocument().toDocumentClass(T.class)}.
+ *
+ * @return Document object which matched the query.
+ * @throws AppSearchException if no factory for this document class could be found on the
+ * classpath.
+ */
+ @NonNull
+ public <T> T getDocument(@NonNull Class<T> documentClass) throws AppSearchException {
+ Preconditions.checkNotNull(documentClass);
+ return getGenericDocument().toDocumentClass(documentClass);
+ }
+// @exportToFramework:endStrip()
+
/**
* Contains the matching {@link GenericDocument}.
*
* @return Document object which matched the query.
*/
@NonNull
- public GenericDocument getDocument() {
+ public GenericDocument getGenericDocument() {
if (mDocument == null) {
mDocument = new GenericDocument(
Preconditions.checkNotNull(mBundle.getBundle(DOCUMENT_FIELD)));
@@ -94,7 +106,8 @@
}
/**
- * Contains a list of Snippets that matched the request.
+ * Returns a list of {@link MatchInfo}s providing information about how the document in
+ * {@link #getGenericDocument} matched the query.
*
* @return List of matches based on {@link SearchSpec}. If snippeting is disabled using
* {@link SearchSpec.Builder#setSnippetCount} or
@@ -102,17 +115,17 @@
* value, this method returns an empty list.
*/
@NonNull
- public List<MatchInfo> getMatches() {
- if (mMatches == null) {
+ public List<MatchInfo> getMatchInfos() {
+ if (mMatchInfos == null) {
List<Bundle> matchBundles =
- Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
- mMatches = new ArrayList<>(matchBundles.size());
+ Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCH_INFOS_FIELD));
+ mMatchInfos = new ArrayList<>(matchBundles.size());
for (int i = 0; i < matchBundles.size(); i++) {
- MatchInfo matchInfo = new MatchInfo(getDocument(), matchBundles.get(i));
- mMatches.add(matchInfo);
+ MatchInfo matchInfo = new MatchInfo(matchBundles.get(i), getGenericDocument());
+ mMatchInfos.add(matchInfo);
}
}
- return mMatches;
+ return mMatchInfos;
}
/**
@@ -126,6 +139,133 @@
}
/**
+ * Contains the database name that stored the {@link GenericDocument}.
+ *
+ * @return Name of the database within which the document is stored
+ */
+ @NonNull
+ public String getDatabaseName() {
+ return Preconditions.checkNotNull(mBundle.getString(DATABASE_NAME_FIELD));
+ }
+
+ /**
+ * Returns the ranking signal of the {@link GenericDocument}, according to the
+ * ranking strategy set in {@link SearchSpec.Builder#setRankingStrategy(int)}.
+ *
+ * The meaning of the ranking signal and its value is determined by the selected ranking
+ * strategy:
+ * <ul>
+ * <li>{@link SearchSpec#RANKING_STRATEGY_NONE} - this value will be 0</li>
+ * <li>{@link SearchSpec#RANKING_STRATEGY_DOCUMENT_SCORE} - the value returned by calling
+ * {@link GenericDocument#getScore()} on the document returned by
+ * {@link #getGenericDocument()}</li>
+ * <li>{@link SearchSpec#RANKING_STRATEGY_CREATION_TIMESTAMP} - the value returned by calling
+ * {@link GenericDocument#getCreationTimestampMillis()} on the document returned by
+ * {@link #getGenericDocument()}</li>
+ * <li>{@link SearchSpec#RANKING_STRATEGY_RELEVANCE_SCORE} - an arbitrary double value where
+ * a higher value means more relevant</li>
+ * <li>{@link SearchSpec#RANKING_STRATEGY_USAGE_COUNT} - the number of times usage has been
+ * reported for the document returned by {@link #getGenericDocument()}</li>
+ * <li>{@link SearchSpec#RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP} - the timestamp of the
+ * most recent usage that has been reported for the document returned by
+ * {@link #getGenericDocument()}</li>
+ * </ul>
+ *
+ * @return Ranking signal of the document
+ */
+ public double getRankingSignal() {
+ return mBundle.getDouble(RANKING_SIGNAL_FIELD);
+ }
+
+ /** Builder for {@link SearchResult} objects. */
+ public static final class Builder {
+ private final String mPackageName;
+ private final String mDatabaseName;
+ private ArrayList<Bundle> mMatchInfoBundles = new ArrayList<>();
+ private GenericDocument mGenericDocument;
+ private double mRankingSignal;
+ private boolean mBuilt = false;
+
+ /**
+ * Constructs a new builder for {@link SearchResult} objects.
+ *
+ * @param packageName the package name the matched document belongs to
+ * @param databaseName the database name the matched document belongs to.
+ */
+ public Builder(@NonNull String packageName, @NonNull String databaseName) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabaseName = Preconditions.checkNotNull(databaseName);
+ }
+
+// @exportToFramework:startStrip()
+ /**
+ * Sets the document which matched.
+ *
+ * @param document An instance of a class annotated with
+ * {@link androidx.appsearch.annotation.Document}.
+ *
+ * @throws AppSearchException if an error occurs converting a document class into a
+ * {@link GenericDocument}.
+ */
+ @NonNull
+ public Builder setDocument(@NonNull Object document) throws AppSearchException {
+ Preconditions.checkNotNull(document);
+ resetIfBuilt();
+ return setGenericDocument(GenericDocument.fromDocumentClass(document));
+ }
+// @exportToFramework:endStrip()
+
+ /** Sets the document which matched. */
+ @NonNull
+ public Builder setGenericDocument(@NonNull GenericDocument document) {
+ Preconditions.checkNotNull(document);
+ resetIfBuilt();
+ mGenericDocument = document;
+ return this;
+ }
+
+ /** Adds another match to this SearchResult. */
+ @NonNull
+ public Builder addMatchInfo(@NonNull MatchInfo matchInfo) {
+ Preconditions.checkState(
+ matchInfo.mDocument == null,
+ "This MatchInfo is already associated with a SearchResult and can't be "
+ + "reassigned");
+ resetIfBuilt();
+ mMatchInfoBundles.add(matchInfo.mBundle);
+ return this;
+ }
+
+ /** Sets the ranking signal of the matched document in this SearchResult. */
+ @NonNull
+ public Builder setRankingSignal(double rankingSignal) {
+ resetIfBuilt();
+ mRankingSignal = rankingSignal;
+ return this;
+ }
+
+ /** Constructs a new {@link SearchResult}. */
+ @NonNull
+ public SearchResult build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(PACKAGE_NAME_FIELD, mPackageName);
+ bundle.putString(DATABASE_NAME_FIELD, mDatabaseName);
+ bundle.putBundle(DOCUMENT_FIELD, mGenericDocument.getBundle());
+ bundle.putDouble(RANKING_SIGNAL_FIELD, mRankingSignal);
+ bundle.putParcelableArrayList(MATCH_INFOS_FIELD, mMatchInfoBundles);
+ mBuilt = true;
+ return new SearchResult(bundle);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mMatchInfoBundles = new ArrayList<>(mMatchInfoBundles);
+ mBuilt = false;
+ }
+ }
+ }
+
+ /**
* This class represents a match objects for any Snippets that might be present in
* {@link SearchResults} from query. Using this class
* user can get the full text, exact matches and Snippets of document content for a given match.
@@ -139,9 +279,9 @@
* <p>{@link MatchInfo#getPropertyPath()} returns "subject"
* <p>{@link MatchInfo#getFullText()} returns "A commonly used fake word is foo. Another
* nonsense word that’s used a lot is bar."
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [29, 32]
+ * <p>{@link MatchInfo#getExactMatchRange()} returns [29, 32]
* <p>{@link MatchInfo#getExactMatch()} returns "foo"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [26, 33]
+ * <p>{@link MatchInfo#getSnippetRange()} returns [26, 33]
* <p>{@link MatchInfo#getSnippet()} returns "is foo."
* <p>
* <p>Class Example 2:
@@ -155,70 +295,62 @@
* <p> Match-1
* <p>{@link MatchInfo#getPropertyPath()} returns "sender.name"
* <p>{@link MatchInfo#getFullText()} returns "Test Name Jr."
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 4]
+ * <p>{@link MatchInfo#getExactMatchRange()} returns [0, 4]
* <p>{@link MatchInfo#getExactMatch()} returns "Test"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 9]
+ * <p>{@link MatchInfo#getSnippetRange()} returns [0, 9]
* <p>{@link MatchInfo#getSnippet()} returns "Test Name"
* <p> Match-2
* <p>{@link MatchInfo#getPropertyPath()} returns "sender.email"
* <p>{@link MatchInfo#getFullText()} returns "TestNameJr@gmail.com"
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 20]
+ * <p>{@link MatchInfo#getExactMatchRange()} returns [0, 20]
* <p>{@link MatchInfo#getExactMatch()} returns "TestNameJr@gmail.com"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 20]
+ * <p>{@link MatchInfo#getSnippetRange()} returns [0, 20]
* <p>{@link MatchInfo#getSnippet()} returns "TestNameJr@gmail.com"
*/
public static final class MatchInfo {
- /**
- * The path of the matching snippet property.
- *
- * @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String PROPERTY_PATH_FIELD = "propertyPath";
+ /** The path of the matching snippet property. */
+ private static final String PROPERTY_PATH_FIELD = "propertyPath";
+ private static final String EXACT_MATCH_RANGE_LOWER_FIELD = "exactMatchRangeLower";
+ private static final String EXACT_MATCH_RANGE_UPPER_FIELD = "exactMatchRangeUpper";
+ private static final String SNIPPET_RANGE_LOWER_FIELD = "snippetRangeLower";
+ private static final String SNIPPET_RANGE_UPPER_FIELD = "snippetRangeUpper";
- /**
- * The index of matching value in its property. A property may have multiple values. This
- * index indicates which value is the match.
- *
- * @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String VALUES_INDEX_FIELD = "valuesIndex";
-
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String EXACT_MATCH_POSITION_LOWER_FIELD = "exactMatchPositionLower";
-
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String EXACT_MATCH_POSITION_UPPER_FIELD = "exactMatchPositionUpper";
-
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String WINDOW_POSITION_LOWER_FIELD = "windowPositionLower";
-
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static final String WINDOW_POSITION_UPPER_FIELD = "windowPositionUpper";
-
- private final String mFullText;
private final String mPropertyPath;
- private final Bundle mBundle;
+ final Bundle mBundle;
+
+ /**
+ * Document which the match comes from.
+ *
+ * <p>If this is {@code null}, methods which require access to the document, like
+ * {@link #getExactMatch}, will throw {@link NullPointerException}.
+ */
+ @Nullable
+ final GenericDocument mDocument;
+
+ /** Full text of the matched property. Populated on first use. */
+ @Nullable
+ private String mFullText;
+
+ /** Range of property that exactly matched the query. Populated on first use. */
+ @Nullable
private MatchRange mExactMatchRange;
+
+ /** Range of some reasonable amount of context around the query. Populated on first use. */
+ @Nullable
private MatchRange mWindowRange;
- MatchInfo(@NonNull GenericDocument document, @NonNull Bundle bundle) {
+ MatchInfo(@NonNull Bundle bundle, @Nullable GenericDocument document) {
mBundle = Preconditions.checkNotNull(bundle);
- Preconditions.checkNotNull(document);
+ mDocument = document;
mPropertyPath = Preconditions.checkNotNull(bundle.getString(PROPERTY_PATH_FIELD));
- mFullText = getPropertyValues(
- document, mPropertyPath, mBundle.getInt(VALUES_INDEX_FIELD));
}
/**
* Gets the property path corresponding to the given entry.
- * <p>Property Path: '.' - delimited sequence of property names indicating which property in
- * the Document these snippets correspond to.
+ *
+ * <p>A property path is a '.' - delimited sequence of property names indicating which
+ * property in the document these snippets correspond to.
+ *
* <p>Example properties: 'body', 'sender.name', 'sender.emailaddress', etc.
* For class example 1 this returns "subject"
*/
@@ -234,6 +366,12 @@
*/
@NonNull
public String getFullText() {
+ if (mFullText == null) {
+ Preconditions.checkState(
+ mDocument != null,
+ "Document has not been populated; this MatchInfo cannot be used yet");
+ mFullText = getPropertyValues(mDocument, mPropertyPath);
+ }
return mFullText;
}
@@ -242,11 +380,11 @@
* <p>For class example 1 this returns [29, 32]
*/
@NonNull
- public MatchRange getExactMatchPosition() {
+ public MatchRange getExactMatchRange() {
if (mExactMatchRange == null) {
mExactMatchRange = new MatchRange(
- mBundle.getInt(EXACT_MATCH_POSITION_LOWER_FIELD),
- mBundle.getInt(EXACT_MATCH_POSITION_UPPER_FIELD));
+ mBundle.getInt(EXACT_MATCH_RANGE_LOWER_FIELD),
+ mBundle.getInt(EXACT_MATCH_RANGE_UPPER_FIELD));
}
return mExactMatchRange;
}
@@ -257,7 +395,7 @@
*/
@NonNull
public CharSequence getExactMatch() {
- return getSubstring(getExactMatchPosition());
+ return getSubstring(getExactMatchRange());
}
/**
@@ -267,11 +405,11 @@
* <p>For class example 1 this returns [29, 41].
*/
@NonNull
- public MatchRange getSnippetPosition() {
+ public MatchRange getSnippetRange() {
if (mWindowRange == null) {
mWindowRange = new MatchRange(
- mBundle.getInt(WINDOW_POSITION_LOWER_FIELD),
- mBundle.getInt(WINDOW_POSITION_UPPER_FIELD));
+ mBundle.getInt(SNIPPET_RANGE_LOWER_FIELD),
+ mBundle.getInt(SNIPPET_RANGE_UPPER_FIELD));
}
return mWindowRange;
}
@@ -286,7 +424,7 @@
*/
@NonNull
public CharSequence getSnippet() {
- return getSubstring(getSnippetPosition());
+ return getSubstring(getSnippetRange());
}
private CharSequence getSubstring(MatchRange range) {
@@ -294,18 +432,66 @@
}
/** Extracts the matching string from the document. */
- private static String getPropertyValues(
- GenericDocument document, String propertyName, int valueIndex) {
+ private static String getPropertyValues(GenericDocument document, String propertyName) {
// In IcingLib snippeting is available for only 3 data types i.e String, double and
// long, so we need to check which of these three are requested.
- // TODO (tytytyww): getPropertyStringArray takes property name, handle for property
- // path.
// TODO (tytytyww): support double[] and long[].
- String[] values = document.getPropertyStringArray(propertyName);
- if (values == null) {
- throw new IllegalStateException("No content found for requested property path!");
+ String result = document.getPropertyString(propertyName);
+ if (result == null) {
+ throw new IllegalStateException(
+ "No content found for requested property path: " + propertyName);
}
- return values[valueIndex];
+ return result;
+ }
+
+ /** Builder for {@link MatchInfo} objects. */
+ public static final class Builder {
+ private final String mPropertyPath;
+ private MatchRange mExactMatchRange = new MatchRange(0, 0);
+ private MatchRange mSnippetRange = new MatchRange(0, 0);
+
+ /**
+ * Creates a new {@link MatchInfo.Builder} reporting a match with the given property
+ * path.
+ *
+ * <p>A property path is a dot-delimited sequence of property names indicating which
+ * property in the document these snippets correspond to.
+ *
+ * <p>Example properties: 'body', 'sender.name', 'sender.emailaddress', etc.
+ * For class example 1 this returns "subject".
+ *
+ * @param propertyPath A {@code dot-delimited sequence of property names indicating
+ * which property in the document these snippets correspond to.
+ */
+ public Builder(@NonNull String propertyPath) {
+ mPropertyPath = Preconditions.checkNotNull(propertyPath);
+ }
+
+ /** Sets the exact {@link MatchRange} corresponding to the given entry. */
+ @NonNull
+ public Builder setExactMatchRange(@NonNull MatchRange matchRange) {
+ mExactMatchRange = Preconditions.checkNotNull(matchRange);
+ return this;
+ }
+
+ /** Sets the snippet {@link MatchRange} corresponding to the given entry. */
+ @NonNull
+ public Builder setSnippetRange(@NonNull MatchRange matchRange) {
+ mSnippetRange = Preconditions.checkNotNull(matchRange);
+ return this;
+ }
+
+ /** Constructs a new {@link MatchInfo}. */
+ @NonNull
+ public MatchInfo build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(SearchResult.MatchInfo.PROPERTY_PATH_FIELD, mPropertyPath);
+ bundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, mExactMatchRange.getStart());
+ bundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, mExactMatchRange.getEnd());
+ bundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, mSnippetRange.getStart());
+ bundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, mSnippetRange.getEnd());
+ return new MatchInfo(bundle, /*document=*/ null);
+ }
}
}
@@ -328,9 +514,7 @@
*
* @param start The start point (inclusive)
* @param end The end point (exclusive)
- * @hide
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public MatchRange(int start, int end) {
if (start > end) {
throw new IllegalArgumentException("Start point must be less than or equal to "
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
index cdd3f3e..6bf301f 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
@@ -24,25 +24,30 @@
import java.util.List;
/**
- * SearchResults are a returned object from a query API.
+ * Encapsulates results of a search operation.
*
- * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets
- * based on request.
+ * <p>Each {@link AppSearchSession#search} operation returns a list of {@link SearchResult}
+ * objects, referred to as a "page", limited by the size configured by
+ * {@link SearchSpec.Builder#setResultCountPerPage}.
*
- * <p>Should close this object after finish fetching results.
+ * <p>To fetch a page of results, call {@link #getNextPage()}.
+ *
+ * <p>All instances of {@link SearchResults} must call {@link SearchResults#close()} after the
+ * results are fetched.
*
* <p>This class is not thread safe.
*/
public interface SearchResults extends Closeable {
/**
- * Gets a whole page of {@link SearchResult}s.
+ * Retrieves the next page of {@link SearchResult} objects.
*
- * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an
- * empty list.
+ * <p>The page size is configured by {@link SearchSpec.Builder#setResultCountPerPage}.
*
- * <p>The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}.
+ * <p>Continue calling this method to access results until it returns an empty list,
+ * signifying there are no more results.
*
- * @return The pending result of performing this operation.
+ * @return a {@link ListenableFuture} which resolves to a list of {@link SearchResult}
+ * objects.
*/
@NonNull
ListenableFuture<List<SearchResult>> getNextPage();
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
index 5c939dd..756cddf 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
@@ -23,8 +23,9 @@
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.Document;
import androidx.appsearch.exceptions.AppSearchException;
-import androidx.appsearch.exceptions.IllegalSearchSpecException;
+import androidx.appsearch.util.BundleUtil;
import androidx.collection.ArrayMap;
import androidx.core.util.Preconditions;
@@ -52,8 +53,9 @@
public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
static final String TERM_MATCH_TYPE_FIELD = "termMatchType";
- static final String SCHEMA_TYPE_FIELD = "schemaType";
+ static final String SCHEMA_FIELD = "schema";
static final String NAMESPACE_FIELD = "namespace";
+ static final String PACKAGE_NAME_FIELD = "packageName";
static final String NUM_PER_PAGE_FIELD = "numPerPage";
static final String RANKING_STRATEGY_FIELD = "rankingStrategy";
static final String ORDER_FIELD = "order";
@@ -61,6 +63,8 @@
static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
static final String MAX_SNIPPET_FIELD = "maxSnippet";
static final String PROJECTION_TYPE_PROPERTY_PATHS_FIELD = "projectionTypeFieldMasks";
+ static final String RESULT_GROUPING_TYPE_FLAGS = "resultGroupingTypeFlags";
+ static final String RESULT_GROUPING_LIMIT = "resultGroupingLimit";
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -75,6 +79,7 @@
/**
* Term Match Type for the query.
+ *
* @hide
*/
// NOTE: The integer values of these constants must match the proto enum constants in
@@ -84,7 +89,8 @@
TERM_MATCH_PREFIX
})
@Retention(RetentionPolicy.SOURCE)
- public @interface TermMatch {}
+ public @interface TermMatch {
+ }
/**
* Query terms will only match exact tokens in the index.
@@ -99,6 +105,7 @@
/**
* Ranking Strategy for query result.
+ *
* @hide
*/
// NOTE: The integer values of these constants must match the proto enum constants in
@@ -107,12 +114,17 @@
RANKING_STRATEGY_NONE,
RANKING_STRATEGY_DOCUMENT_SCORE,
RANKING_STRATEGY_CREATION_TIMESTAMP,
- RANKING_STRATEGY_RELEVANCE_SCORE
+ RANKING_STRATEGY_RELEVANCE_SCORE,
+ RANKING_STRATEGY_USAGE_COUNT,
+ RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP,
+ RANKING_STRATEGY_SYSTEM_USAGE_COUNT,
+ RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface RankingStrategy {}
+ public @interface RankingStrategy {
+ }
- /** No Ranking, results are returned in arbitrary order.*/
+ /** No Ranking, results are returned in arbitrary order. */
public static final int RANKING_STRATEGY_NONE = 0;
/** Ranked by app-provided document scores. */
public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1;
@@ -120,9 +132,18 @@
public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
/** Ranked by document relevance score. */
public static final int RANKING_STRATEGY_RELEVANCE_SCORE = 3;
+ /** Ranked by number of usages, as reported by the app. */
+ public static final int RANKING_STRATEGY_USAGE_COUNT = 4;
+ /** Ranked by timestamp of last usage, as reported by the app. */
+ public static final int RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP = 5;
+ /** Ranked by number of usages from a system UI surface. */
+ public static final int RANKING_STRATEGY_SYSTEM_USAGE_COUNT = 6;
+ /** Ranked by timestamp of last usage from a system UI surface. */
+ public static final int RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP = 7;
/**
* Order for query result.
+ *
* @hide
*/
// NOTE: The integer values of these constants must match the proto enum constants in
@@ -132,13 +153,39 @@
ORDER_ASCENDING
})
@Retention(RetentionPolicy.SOURCE)
- public @interface Order {}
+ public @interface Order {
+ }
/** Search results will be returned in a descending order. */
public static final int ORDER_DESCENDING = 0;
/** Search results will be returned in an ascending order. */
public static final int ORDER_ASCENDING = 1;
+ /**
+ * Grouping type for result limits.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, value = {
+ GROUPING_TYPE_PER_PACKAGE,
+ GROUPING_TYPE_PER_NAMESPACE
+ })
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GroupingType {
+ }
+
+ /**
+ * Results should be grouped together by package for the purpose of enforcing a limit on the
+ * number of results returned per package.
+ */
+ public static final int GROUPING_TYPE_PER_PACKAGE = 0b01;
+ /**
+ * Results should be grouped together by namespace for the purpose of enforcing a limit on the
+ * number of results returned per namespace.
+ */
+ public static final int GROUPING_TYPE_PER_NAMESPACE = 0b10;
+
private final Bundle mBundle;
/** @hide */
@@ -150,6 +197,7 @@
/**
* Returns the {@link Bundle} populated by this builder.
+ *
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -169,21 +217,21 @@
* <p>If empty, the query will search over all schema types.
*/
@NonNull
- public List<String> getSchemaTypes() {
- List<String> schemaTypes = mBundle.getStringArrayList(SCHEMA_TYPE_FIELD);
- if (schemaTypes == null) {
+ public List<String> getFilterSchemas() {
+ List<String> schemas = mBundle.getStringArrayList(SCHEMA_FIELD);
+ if (schemas == null) {
return Collections.emptyList();
}
- return Collections.unmodifiableList(schemaTypes);
+ return Collections.unmodifiableList(schemas);
}
/**
- * Returns the list of namespaces to search for.
+ * Returns the list of namespaces to search over.
*
* <p>If empty, the query will search over all namespaces.
*/
@NonNull
- public List<String> getNamespaces() {
+ public List<String> getFilterNamespaces() {
List<String> namespaces = mBundle.getStringArrayList(NAMESPACE_FIELD);
if (namespaces == null) {
return Collections.emptyList();
@@ -191,6 +239,22 @@
return Collections.unmodifiableList(namespaces);
}
+ /**
+ * Returns the list of package name filters to search over.
+ *
+ * <p>If empty, the query will search over all packages that the caller has access to. If
+ * package names are specified which caller doesn't have access to, then those package names
+ * will be ignored.
+ */
+ @NonNull
+ public List<String> getFilterPackageNames() {
+ List<String> packageNames = mBundle.getStringArrayList(PACKAGE_NAME_FIELD);
+ if (packageNames == null) {
+ return Collections.emptyList();
+ }
+ return Collections.unmodifiableList(packageNames);
+ }
+
/** Returns the number of results per page in the result set. */
public int getResultCountPerPage() {
return mBundle.getInt(NUM_PER_PAGE_FIELD, DEFAULT_NUM_PER_PAGE);
@@ -233,41 +297,63 @@
*/
@NonNull
public Map<String, List<String>> getProjections() {
- Bundle typePropertyPathsBundle =
- mBundle.getBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD);
- Set<String> schemaTypes = typePropertyPathsBundle.keySet();
- Map<String, List<String>> typePropertyPathsMap = new ArrayMap<>(schemaTypes.size());
- for (String schemaType : schemaTypes) {
- typePropertyPathsMap.put(schemaType,
- typePropertyPathsBundle.getStringArrayList(schemaType));
+ Bundle typePropertyPathsBundle = mBundle.getBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD);
+ Set<String> schemas = typePropertyPathsBundle.keySet();
+ Map<String, List<String>> typePropertyPathsMap = new ArrayMap<>(schemas.size());
+ for (String schema : schemas) {
+ typePropertyPathsMap.put(schema, typePropertyPathsBundle.getStringArrayList(schema));
}
return typePropertyPathsMap;
}
+ /**
+ * Get the type of grouping limit to apply, or 0 if {@link Builder#setResultGrouping} was not
+ * called.
+ */
+ public @GroupingType int getResultGroupingTypeFlags() {
+ return mBundle.getInt(RESULT_GROUPING_TYPE_FLAGS);
+ }
+
+ /**
+ * Get the maximum number of results to return for each group.
+ *
+ * @return the maximum number of results to return for each group or Integer.MAX_VALUE if
+ * {@link Builder#setResultGrouping(int, int)} was not called.
+ */
+ public int getResultGroupingLimit() {
+ return mBundle.getInt(RESULT_GROUPING_LIMIT, Integer.MAX_VALUE);
+ }
+
/** Builder for {@link SearchSpec objects}. */
public static final class Builder {
+ private ArrayList<String> mSchemas = new ArrayList<>();
+ private ArrayList<String> mNamespaces = new ArrayList<>();
+ private ArrayList<String> mPackageNames = new ArrayList<>();
+ private Bundle mProjectionTypePropertyMasks = new Bundle();
- private final Bundle mBundle;
- private final ArrayList<String> mSchemaTypes = new ArrayList<>();
- private final ArrayList<String> mNamespaces = new ArrayList<>();
- private final Bundle mProjectionTypePropertyMasks = new Bundle();
+ private int mResultCountPerPage = DEFAULT_NUM_PER_PAGE;
+ private @TermMatch int mTermMatchType = TERM_MATCH_PREFIX;
+ private int mSnippetCount = 0;
+ private int mSnippetCountPerProperty = MAX_SNIPPET_PER_PROPERTY_COUNT;
+ private int mMaxSnippetSize = 0;
+ private @RankingStrategy int mRankingStrategy = RANKING_STRATEGY_NONE;
+ private @Order int mOrder = ORDER_DESCENDING;
+ private @GroupingType int mGroupingTypeFlags = 0;
+ private int mGroupingLimit = 0;
private boolean mBuilt = false;
- /** Creates a new {@link SearchSpec.Builder}. */
- public Builder() {
- mBundle = new Bundle();
- mBundle.putInt(NUM_PER_PAGE_FIELD, DEFAULT_NUM_PER_PAGE);
- }
-
/**
* Indicates how the query terms should match {@code TermMatchCode} in the index.
+ *
+ * <p>If this method is not called, the default term match type is
+ * {@link SearchSpec#TERM_MATCH_PREFIX}.
*/
@NonNull
- public Builder setTermMatch(@TermMatch int termMatchTypeCode) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_EXACT_ONLY,
+ public Builder setTermMatch(@TermMatch int termMatchType) {
+ Preconditions.checkArgumentInRange(termMatchType, TERM_MATCH_EXACT_ONLY,
TERM_MATCH_PREFIX, "Term match type");
- mBundle.putInt(TERM_MATCH_TYPE_FIELD, termMatchTypeCode);
+ resetIfBuilt();
+ mTermMatchType = termMatchType;
return this;
}
@@ -278,10 +364,10 @@
* <p>If unset, the query will search over all schema types.
*/
@NonNull
- public Builder addSchemaType(@NonNull String... schemaTypes) {
- Preconditions.checkNotNull(schemaTypes);
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- return addSchemaType(Arrays.asList(schemaTypes));
+ public Builder addFilterSchemas(@NonNull String... schemas) {
+ Preconditions.checkNotNull(schemas);
+ resetIfBuilt();
+ return addFilterSchemas(Arrays.asList(schemas));
}
/**
@@ -291,56 +377,59 @@
* <p>If unset, the query will search over all schema types.
*/
@NonNull
- public Builder addSchemaType(@NonNull Collection<String> schemaTypes) {
- Preconditions.checkNotNull(schemaTypes);
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mSchemaTypes.addAll(schemaTypes);
+ public Builder addFilterSchemas(@NonNull Collection<String> schemas) {
+ Preconditions.checkNotNull(schemas);
+ resetIfBuilt();
+ mSchemas.addAll(schemas);
return this;
}
// @exportToFramework:startStrip()
+
/**
- * Adds the Schema type of given data classes to the Schema type filter of
+ * Adds the Schema names of given document classes to the Schema type filter of
* {@link SearchSpec} Entry. Only search for documents that have the specified schema types.
*
* <p>If unset, the query will search over all schema types.
*
- * @param dataClasses classes annotated with
- * {@link androidx.appsearch.annotation.AppSearchDocument}.
+ * @param documentClasses classes annotated with {@link Document}.
*/
- @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getSchemaTypes
+ // Merged list available from getFilterSchemas
+ @SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder addSchemaByDataClass(@NonNull Collection<? extends Class<?>> dataClasses)
- throws AppSearchException {
- Preconditions.checkNotNull(dataClasses);
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- List<String> schemaTypes = new ArrayList<>(dataClasses.size());
- DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
- for (Class<?> dataClass : dataClasses) {
- DataClassFactory<?> factory = registry.getOrCreateFactory(dataClass);
- schemaTypes.add(factory.getSchemaType());
+ public Builder addFilterDocumentClasses(
+ @NonNull Collection<? extends Class<?>> documentClasses) throws AppSearchException {
+ Preconditions.checkNotNull(documentClasses);
+ resetIfBuilt();
+ List<String> schemas = new ArrayList<>(documentClasses.size());
+ DocumentClassFactoryRegistry registry = DocumentClassFactoryRegistry.getInstance();
+ for (Class<?> documentClass : documentClasses) {
+ DocumentClassFactory<?> factory = registry.getOrCreateFactory(documentClass);
+ schemas.add(factory.getSchemaName());
}
- addSchemaType(schemaTypes);
+ addFilterSchemas(schemas);
return this;
}
// @exportToFramework:endStrip()
// @exportToFramework:startStrip()
+
/**
- * Adds the Schema type of given data classes to the Schema type filter of
+ * Adds the Schema names of given document classes to the Schema type filter of
* {@link SearchSpec} Entry. Only search for documents that have the specified schema types.
*
* <p>If unset, the query will search over all schema types.
*
- * @param dataClasses classes annotated with
- * {@link androidx.appsearch.annotation.AppSearchDocument}.
+ * @param documentClasses classes annotated with {@link Document}.
*/
- @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getSchemas()
+ // Merged list available from getFilterSchemas()
+ @SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder addSchemaByDataClass(@NonNull Class<?>... dataClasses)
+ public Builder addFilterDocumentClasses(@NonNull Class<?>... documentClasses)
throws AppSearchException {
- Preconditions.checkNotNull(dataClasses);
- return addSchemaByDataClass(Arrays.asList(dataClasses));
+ Preconditions.checkNotNull(documentClasses);
+ resetIfBuilt();
+ return addFilterDocumentClasses(Arrays.asList(documentClasses));
}
// @exportToFramework:endStrip()
@@ -350,10 +439,10 @@
* <p>If unset, the query will search over all namespaces.
*/
@NonNull
- public Builder addNamespace(@NonNull String... namespaces) {
+ public Builder addFilterNamespaces(@NonNull String... namespaces) {
Preconditions.checkNotNull(namespaces);
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- return addNamespace(Arrays.asList(namespaces));
+ resetIfBuilt();
+ return addFilterNamespaces(Arrays.asList(namespaces));
}
/**
@@ -362,34 +451,66 @@
* <p>If unset, the query will search over all namespaces.
*/
@NonNull
- public Builder addNamespace(@NonNull Collection<String> namespaces) {
+ public Builder addFilterNamespaces(@NonNull Collection<String> namespaces) {
Preconditions.checkNotNull(namespaces);
- Preconditions.checkState(!mBuilt, "Builder has already been used");
+ resetIfBuilt();
mNamespaces.addAll(namespaces);
return this;
}
/**
+ * Adds a package name filter to {@link SearchSpec} Entry. Only search for documents that
+ * were indexed from the specified packages.
+ *
+ * <p>If unset, the query will search over all packages that the caller has access to.
+ * If package names are specified which caller doesn't have access to, then those package
+ * names will be ignored.
+ */
+ @NonNull
+ public Builder addFilterPackageNames(@NonNull String... packageNames) {
+ Preconditions.checkNotNull(packageNames);
+ resetIfBuilt();
+ return addFilterPackageNames(Arrays.asList(packageNames));
+ }
+
+ /**
+ * Adds a package name filter to {@link SearchSpec} Entry. Only search for documents that
+ * were indexed from the specified packages.
+ *
+ * <p>If unset, the query will search over all packages that the caller has access to.
+ * If package names are specified which caller doesn't have access to, then those package
+ * names will be ignored.
+ */
+ @NonNull
+ public Builder addFilterPackageNames(@NonNull Collection<String> packageNames) {
+ Preconditions.checkNotNull(packageNames);
+ resetIfBuilt();
+ mPackageNames.addAll(packageNames);
+ return this;
+ }
+
+ /**
* Sets the number of results per page in the returned object.
*
* <p>The default number of results per page is 10.
*/
@NonNull
public SearchSpec.Builder setResultCountPerPage(
- @IntRange(from = 0, to = MAX_NUM_PER_PAGE) int numPerPage) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkArgumentInRange(numPerPage, 0, MAX_NUM_PER_PAGE, "NumPerPage");
- mBundle.putInt(NUM_PER_PAGE_FIELD, numPerPage);
+ @IntRange(from = 0, to = MAX_NUM_PER_PAGE) int resultCountPerPage) {
+ Preconditions.checkArgumentInRange(
+ resultCountPerPage, 0, MAX_NUM_PER_PAGE, "resultCountPerPage");
+ resetIfBuilt();
+ mResultCountPerPage = resultCountPerPage;
return this;
}
- /** Sets ranking strategy for AppSearch results.*/
+ /** Sets ranking strategy for AppSearch results. */
@NonNull
public Builder setRankingStrategy(@RankingStrategy int rankingStrategy) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(rankingStrategy, RANKING_STRATEGY_NONE,
- RANKING_STRATEGY_RELEVANCE_SCORE, "Result ranking strategy");
- mBundle.putInt(RANKING_STRATEGY_FIELD, rankingStrategy);
+ RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP, "Result ranking strategy");
+ resetIfBuilt();
+ mRankingStrategy = rankingStrategy;
return this;
}
@@ -401,10 +522,10 @@
*/
@NonNull
public Builder setOrder(@Order int order) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(order, ORDER_DESCENDING, ORDER_ASCENDING,
"Result ranking order");
- mBundle.putInt(ORDER_FIELD, order);
+ resetIfBuilt();
+ mOrder = order;
return this;
}
@@ -412,33 +533,40 @@
* Only the first {@code snippetCount} documents based on the ranking strategy
* will have snippet information provided.
*
- * <p>If set to 0 (default), snippeting is disabled and {@link SearchResult#getMatches} will
- * return {@code null} for that result.
+ * <p>The list returned from {@link SearchResult#getMatchInfos} will contain at most this
+ * many entries.
+ *
+ * <p>If set to 0 (default), snippeting is disabled and the list returned from
+ * {@link SearchResult#getMatchInfos} will be empty.
*/
@NonNull
public SearchSpec.Builder setSnippetCount(
@IntRange(from = 0, to = MAX_SNIPPET_COUNT) int snippetCount) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(snippetCount, 0, MAX_SNIPPET_COUNT, "snippetCount");
- mBundle.putInt(SNIPPET_COUNT_FIELD, snippetCount);
+ resetIfBuilt();
+ mSnippetCount = snippetCount;
return this;
}
/**
* Sets {@code snippetCountPerProperty}. Only the first {@code snippetCountPerProperty}
- * snippets for each property of {@link GenericDocument} will contain snippet information.
+ * snippets for each property of each {@link GenericDocument} will contain snippet
+ * information.
*
- * <p>If set to 0, snippeting is disabled and {@link SearchResult#getMatches}
- * will return {@code null} for that result.
+ * <p>If set to 0, snippeting is disabled and the list
+ * returned from {@link SearchResult#getMatchInfos} will be empty.
+ *
+ * <p>The default behavior is to snippet all matches a property contains, up to the maximum
+ * value of 10,000.
*/
@NonNull
public SearchSpec.Builder setSnippetCountPerProperty(
@IntRange(from = 0, to = MAX_SNIPPET_PER_PROPERTY_COUNT)
int snippetCountPerProperty) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(snippetCountPerProperty,
0, MAX_SNIPPET_PER_PROPERTY_COUNT, "snippetCountPerProperty");
- mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, snippetCountPerProperty);
+ resetIfBuilt();
+ mSnippetCountPerProperty = snippetCountPerProperty;
return this;
}
@@ -457,14 +585,14 @@
@NonNull
public SearchSpec.Builder setMaxSnippetSize(
@IntRange(from = 0, to = MAX_SNIPPET_SIZE_LIMIT) int maxSnippetSize) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(
maxSnippetSize, 0, MAX_SNIPPET_SIZE_LIMIT, "maxSnippetSize");
- mBundle.putInt(MAX_SNIPPET_FIELD, maxSnippetSize);
+ resetIfBuilt();
+ mMaxSnippetSize = maxSnippetSize;
return this;
}
- /**
+ /**
* Adds property paths for the specified type to be used for projection. If property
* paths are added for a type, then only the properties referred to will be retrieved for
* results of that type. If a property path that is specified isn't present in a result,
@@ -503,7 +631,7 @@
* <p>Then, suppose that a query for "important" is issued with the following projection
* type property paths:
* <pre>{@code
- * {schemaType: "Email", ["subject", "sender.name", "recipients.name"]}
+ * {schema: "Email", ["subject", "sender.name", "recipients.name"]}
* }</pre>
*
* <p>The above document will be returned as:
@@ -526,58 +654,77 @@
*/
@NonNull
public SearchSpec.Builder addProjection(
- @NonNull String schemaType, @NonNull String... propertyPaths) {
+ @NonNull String schema, @NonNull Collection<String> propertyPaths) {
+ Preconditions.checkNotNull(schema);
Preconditions.checkNotNull(propertyPaths);
- return addProjection(schemaType, Arrays.asList(propertyPaths));
- }
-
- /**
- * Adds property paths for the specified type to be used for projection. If property
- * paths are added for a type, then only the properties referred to will be retrieved for
- * results of that type. If a property path that is specified isn't present in a result,
- * it will be ignored for that result. Property paths cannot be null.
- *
- * <p>If no property paths are added for a particular type, then all properties of
- * results of that type will be retrieved.
- *
- * <p>If property path is added for the
- * {@link SearchSpec#PROJECTION_SCHEMA_TYPE_WILDCARD}, then those property paths will
- * apply to all results, excepting any types that have their own, specific property paths
- * set.
- *
- * {@see SearchSpec.Builder#addProjection(String, String...)}
- */
- @NonNull
- public SearchSpec.Builder addProjection(
- @NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemaType);
- Preconditions.checkNotNull(propertyPaths);
+ resetIfBuilt();
ArrayList<String> propertyPathsArrayList = new ArrayList<>(propertyPaths.size());
for (String propertyPath : propertyPaths) {
Preconditions.checkNotNull(propertyPath);
propertyPathsArrayList.add(propertyPath);
}
- mProjectionTypePropertyMasks.putStringArrayList(schemaType, propertyPathsArrayList);
+ mProjectionTypePropertyMasks.putStringArrayList(schema, propertyPathsArrayList);
return this;
}
/**
- * Constructs a new {@link SearchSpec} from the contents of this builder.
+ * Set the maximum number of results to return for each group, where groups are defined
+ * by grouping type.
*
- * <p>After calling this method, the builder must no longer be used.
+ * <p>Calling this method will override any previous calls. So calling
+ * setResultGrouping(GROUPING_TYPE_PER_PACKAGE, 7) and then calling
+ * setResultGrouping(GROUPING_TYPE_PER_PACKAGE, 2) will result in only the latter, a
+ * limit of two results per package, being applied. Or calling setResultGrouping
+ * (GROUPING_TYPE_PER_PACKAGE, 1) and then calling setResultGrouping
+ * (GROUPING_TYPE_PER_PACKAGE | GROUPING_PER_NAMESPACE, 5) will result in five results
+ * per package per namespace.
+ *
+ * @param groupingTypeFlags One or more combination of grouping types.
+ * @param limit Number of results to return per {@code groupingTypeFlags}.
+ * @throws IllegalArgumentException if groupingTypeFlags is zero.
*/
+ // Individual parameters available from getResultGroupingTypeFlags and
+ // getResultGroupingLimit
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setResultGrouping(@GroupingType int groupingTypeFlags, int limit) {
+ Preconditions.checkState(
+ groupingTypeFlags != 0, "Result grouping type cannot be zero.");
+ resetIfBuilt();
+ mGroupingTypeFlags = groupingTypeFlags;
+ mGroupingLimit = limit;
+ return this;
+ }
+
+ /** Constructs a new {@link SearchSpec} from the contents of this builder. */
@NonNull
public SearchSpec build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- if (!mBundle.containsKey(TERM_MATCH_TYPE_FIELD)) {
- throw new IllegalSearchSpecException("Missing termMatchType field.");
- }
- mBundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces);
- mBundle.putStringArrayList(SCHEMA_TYPE_FIELD, mSchemaTypes);
- mBundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks);
+ Bundle bundle = new Bundle();
+ bundle.putStringArrayList(SCHEMA_FIELD, mSchemas);
+ bundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces);
+ bundle.putStringArrayList(PACKAGE_NAME_FIELD, mPackageNames);
+ bundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks);
+ bundle.putInt(NUM_PER_PAGE_FIELD, mResultCountPerPage);
+ bundle.putInt(TERM_MATCH_TYPE_FIELD, mTermMatchType);
+ bundle.putInt(SNIPPET_COUNT_FIELD, mSnippetCount);
+ bundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, mSnippetCountPerProperty);
+ bundle.putInt(MAX_SNIPPET_FIELD, mMaxSnippetSize);
+ bundle.putInt(RANKING_STRATEGY_FIELD, mRankingStrategy);
+ bundle.putInt(ORDER_FIELD, mOrder);
+ bundle.putInt(RESULT_GROUPING_TYPE_FLAGS, mGroupingTypeFlags);
+ bundle.putInt(RESULT_GROUPING_LIMIT, mGroupingLimit);
mBuilt = true;
- return new SearchSpec(mBundle);
+ return new SearchSpec(bundle);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mSchemas = new ArrayList<>(mSchemas);
+ mNamespaces = new ArrayList<>(mNamespaces);
+ mPackageNames = new ArrayList<>(mPackageNames);
+ mProjectionTypePropertyMasks = BundleUtil.deepCopy(mProjectionTypePropertyMasks);
+ mBuilt = false;
+ }
}
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaRequest.java
index 07df364..e09eec9 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaRequest.java
@@ -18,6 +18,7 @@
import android.annotation.SuppressLint;
+import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.appsearch.exceptions.AppSearchException;
@@ -36,44 +37,90 @@
/**
* Encapsulates a request to update the schema of an {@link AppSearchSession} database.
*
+ * <p>The schema is composed of a collection of {@link AppSearchSchema} objects, each of which
+ * defines a unique type of data.
+ *
+ * <p>The first call to SetSchemaRequest will set the provided schema and store it within the
+ * {@link AppSearchSession} database.
+ *
+ * <p>Subsequent calls will compare the provided schema to the previously saved schema, to
+ * determine how to treat existing documents.
+ *
+ * <p>The following types of schema modifications are always safe and are made without deleting any
+ * existing documents:
+ * <ul>
+ * <li>Addition of new {@link AppSearchSchema} types
+ * <li>Addition of new properties to an existing {@link AppSearchSchema} type
+ * <li>Changing the cardinality of a property to be less restrictive
+ * </ul>
+ *
+ * <p>The following types of schema changes are not backwards compatible:
+ * <ul>
+ * <li>Removal of an existing {@link AppSearchSchema} type
+ * <li>Removal of a property from an existing {@link AppSearchSchema} type
+ * <li>Changing the data type of an existing property
+ * <li>Changing the cardinality of a property to be more restrictive
+ * </ul>
+ *
+ * <p>Providing a schema with incompatible changes, will throw an
+ * {@link androidx.appsearch.exceptions.AppSearchException}, with a message describing the
+ * incompatibility. As a result, the previously set schema will remain unchanged.
+ *
+ * <p>Backward incompatible changes can be made by :
+ * <ul>
+ * <li>setting {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}.
+ * This deletes all documents that are incompatible with the new schema. The new schema is
+ * then saved and persisted to disk.
+ * <li>Add a {@link Migrator} for each incompatible type and make no deletion. The migrator
+ * will migrate documents from it's old schema version to the new version. Migrated types
+ * will be set into both {@link SetSchemaResponse#getIncompatibleTypes()} and
+ * {@link SetSchemaResponse#getMigratedTypes()}. See the migration section below.
+ * </ul>
* @see AppSearchSession#setSchema
+ * @see Migrator
*/
public final class SetSchemaRequest {
private final Set<AppSearchSchema> mSchemas;
- private final Set<String> mSchemasNotVisibleToSystemUi;
+ private final Set<String> mSchemasNotDisplayedBySystem;
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages;
+ private final Map<String, Migrator> mMigrators;
private final boolean mForceOverride;
+ private final int mVersion;
SetSchemaRequest(@NonNull Set<AppSearchSchema> schemas,
- @NonNull Set<String> schemasNotVisibleToSystemUi,
+ @NonNull Set<String> schemasNotDisplayedBySystem,
@NonNull Map<String, Set<PackageIdentifier>> schemasVisibleToPackages,
- boolean forceOverride) {
+ @NonNull Map<String, Migrator> migrators,
+ boolean forceOverride,
+ int version) {
mSchemas = Preconditions.checkNotNull(schemas);
- mSchemasNotVisibleToSystemUi = Preconditions.checkNotNull(schemasNotVisibleToSystemUi);
+ mSchemasNotDisplayedBySystem = Preconditions.checkNotNull(schemasNotDisplayedBySystem);
mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages);
+ mMigrators = Preconditions.checkNotNull(migrators);
mForceOverride = forceOverride;
+ mVersion = version;
}
- /** Returns the schemas that are part of this request. */
+ /** Returns the {@link AppSearchSchema} types that are part of this request. */
@NonNull
public Set<AppSearchSchema> getSchemas() {
return Collections.unmodifiableSet(mSchemas);
}
/**
- * Returns the set of schema types that have opted out of being visible on system UI surfaces.
+ * Returns all the schema types that are opted out of being displayed and visible on any
+ * system UI surface.
*/
@NonNull
- public Set<String> getSchemasNotVisibleToSystemUi() {
- return Collections.unmodifiableSet(mSchemasNotVisibleToSystemUi);
+ public Set<String> getSchemasNotDisplayedBySystem() {
+ return Collections.unmodifiableSet(mSchemasNotDisplayedBySystem);
}
/**
* Returns a mapping of schema types to the set of packages that have access
- * to that schema type. Each package is represented by a {@link PackageIdentifier}.
- * name and byte[] certificate.
+ * to that schema type.
*
- * This method is inefficient to call repeatedly.
+ * <p>It’s inefficient to call this method repeatedly.
*/
@NonNull
public Map<String, Set<PackageIdentifier>> getSchemasVisibleToPackages() {
@@ -85,11 +132,19 @@
}
/**
- * Returns a mapping of schema types to the set of packages that have access
- * to that schema type. Each package is represented by a {@link PackageIdentifier}.
- * name and byte[] certificate.
+ * Returns the map of {@link Migrator}, the key will be the schema type of the
+ * {@link Migrator} associated with.
+ */
+ @NonNull
+ public Map<String, Migrator> getMigrators() {
+ return Collections.unmodifiableMap(mMigrators);
+ }
+
+ /**
+ * Returns a mapping of {@link AppSearchSchema} types to the set of packages that have access
+ * to that schema type.
*
- * A more efficient version of {@link #getSchemasVisibleToPackages}, but it returns a
+ * <p>A more efficient version of {@link #getSchemasVisibleToPackages}, but it returns a
* modifiable map. This is not meant to be unhidden and should only be used by internal
* classes.
*
@@ -106,108 +161,139 @@
return mForceOverride;
}
+ /** Returns the database overall schema version. */
+ @IntRange(from = 1)
+ public int getVersion() {
+ return mVersion;
+ }
+
/** Builder for {@link SetSchemaRequest} objects. */
public static final class Builder {
- private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
- private final Set<String> mSchemasNotVisibleToSystemUi = new ArraySet<>();
- private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
+ private static final int DEFAULT_VERSION = 1;
+ private ArraySet<AppSearchSchema> mSchemas = new ArraySet<>();
+ private ArraySet<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
+ private ArrayMap<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
new ArrayMap<>();
+ private ArrayMap<String, Migrator> mMigrators = new ArrayMap<>();
private boolean mForceOverride = false;
+ private int mVersion = DEFAULT_VERSION;
private boolean mBuilt = false;
/**
- * Adds one or more types to the schema.
+ * Adds one or more {@link AppSearchSchema} types to the schema.
*
- * <p>Any documents of these types will be visible on system UI surfaces by default.
+ * <p>An {@link AppSearchSchema} object represents one type of structured data.
+ *
+ * <p>Any documents of these types will be displayed on system UI surfaces by default.
*/
@NonNull
- public Builder addSchema(@NonNull AppSearchSchema... schemas) {
+ public Builder addSchemas(@NonNull AppSearchSchema... schemas) {
Preconditions.checkNotNull(schemas);
- return addSchema(Arrays.asList(schemas));
+ resetIfBuilt();
+ return addSchemas(Arrays.asList(schemas));
}
/**
- * Adds one or more types to the schema.
+ * Adds a collection of {@link AppSearchSchema} objects to the schema.
*
- * <p>Any documents of these types will be visible on system UI surfaces by default.
+ * <p>An {@link AppSearchSchema} object represents one type of structured data.
*/
@NonNull
- public Builder addSchema(@NonNull Collection<AppSearchSchema> schemas) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
+ public Builder addSchemas(@NonNull Collection<AppSearchSchema> schemas) {
Preconditions.checkNotNull(schemas);
+ resetIfBuilt();
mSchemas.addAll(schemas);
return this;
}
// @exportToFramework:startStrip()
/**
- * Adds one or more types to the schema.
+ * Adds one or more {@link androidx.appsearch.annotation.Document} annotated classes to the
+ * schema.
*
- * <p>Any documents of these types will be visible on system UI surfaces by default.
- *
- * @param dataClasses classes annotated with
- * {@link androidx.appsearch.annotation.AppSearchDocument}.
+ * @param documentClasses classes annotated with
+ * {@link androidx.appsearch.annotation.Document}.
* @throws AppSearchException if {@code androidx.appsearch.compiler.AppSearchCompiler}
- * has not generated a schema for the given data classes.
+ * has not generated a schema for the given document classes.
*/
@SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getSchemas()
@NonNull
- public Builder addDataClass(@NonNull Class<?>... dataClasses)
+ public Builder addDocumentClasses(@NonNull Class<?>... documentClasses)
throws AppSearchException {
- Preconditions.checkNotNull(dataClasses);
- return addDataClass(Arrays.asList(dataClasses));
+ Preconditions.checkNotNull(documentClasses);
+ resetIfBuilt();
+ return addDocumentClasses(Arrays.asList(documentClasses));
}
/**
- * Adds one or more types to the schema.
+ * Adds a collection of {@link androidx.appsearch.annotation.Document} annotated classes to
+ * the schema.
*
- * <p>Any documents of these types will be visible on system UI surfaces by default.
- *
- * @param dataClasses classes annotated with
- * {@link androidx.appsearch.annotation.AppSearchDocument}.
+ * @param documentClasses classes annotated with
+ * {@link androidx.appsearch.annotation.Document}.
* @throws AppSearchException if {@code androidx.appsearch.compiler.AppSearchCompiler}
- * has not generated a schema for the given data classes.
+ * has not generated a schema for the given document classes.
*/
@SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getSchemas()
@NonNull
- public Builder addDataClass(@NonNull Collection<? extends Class<?>> dataClasses)
+ public Builder addDocumentClasses(@NonNull Collection<? extends Class<?>> documentClasses)
throws AppSearchException {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(dataClasses);
- List<AppSearchSchema> schemas = new ArrayList<>(dataClasses.size());
- DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
- for (Class<?> dataClass : dataClasses) {
- DataClassFactory<?> factory = registry.getOrCreateFactory(dataClass);
+ Preconditions.checkNotNull(documentClasses);
+ resetIfBuilt();
+ List<AppSearchSchema> schemas = new ArrayList<>(documentClasses.size());
+ DocumentClassFactoryRegistry registry = DocumentClassFactoryRegistry.getInstance();
+ for (Class<?> documentClass : documentClasses) {
+ DocumentClassFactory<?> factory = registry.getOrCreateFactory(documentClass);
schemas.add(factory.getSchema());
}
- return addSchema(schemas);
+ return addSchemas(schemas);
}
// @exportToFramework:endStrip()
/**
- * Sets visibility on system UI surfaces for the given {@code schemaType}.
+ * Sets whether or not documents from the provided {@code schemaType} will be displayed
+ * and visible on any system UI surface.
*
- * @param schemaType The schema type to set visibility on.
- * @param visible Whether the {@code schemaType} will be visible or not.
+ * <p>This setting applies to the provided {@code schemaType} only, and does not persist
+ * across {@link AppSearchSession#setSchema} calls.
+ *
+ * <p>The default behavior, if this method is not called, is to allow types to be
+ * displayed on system UI surfaces.
+ *
+ * @param schemaType The name of an {@link AppSearchSchema} within the same
+ * {@link SetSchemaRequest}, which will be configured.
+ * @param displayed Whether documents of this type will be displayed on system UI surfaces.
*/
- // Merged list available from getSchemasNotVisibleToSystemUi
+ // Merged list available from getSchemasNotDisplayedBySystem
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder setSchemaTypeVisibilityForSystemUi(@NonNull String schemaType,
- boolean visible) {
+ public Builder setSchemaTypeDisplayedBySystem(
+ @NonNull String schemaType, boolean displayed) {
Preconditions.checkNotNull(schemaType);
- Preconditions.checkState(!mBuilt, "Builder has already been used");
-
- if (visible) {
- mSchemasNotVisibleToSystemUi.remove(schemaType);
+ resetIfBuilt();
+ if (displayed) {
+ mSchemasNotDisplayedBySystem.remove(schemaType);
} else {
- mSchemasNotVisibleToSystemUi.add(schemaType);
+ mSchemasNotDisplayedBySystem.add(schemaType);
}
return this;
}
/**
- * Sets visibility for a package for the given {@code schemaType}.
+ * Sets whether or not documents from the provided {@code schemaType} can be read by the
+ * specified package.
+ *
+ * <p>Each package is represented by a {@link PackageIdentifier}, containing a package name
+ * and a byte array of type {@link android.content.pm.PackageManager#CERT_INPUT_SHA256}.
+ *
+ * <p>To opt into one-way data sharing with another application, the developer will need to
+ * explicitly grant the other application’s package name and certificate Read access to its
+ * data.
+ *
+ * <p>For two-way data sharing, both applications need to explicitly grant Read access to
+ * one another.
+ *
+ * <p>By default, data sharing between applications is disabled.
*
* @param schemaType The schema type to set visibility on.
* @param visible Whether the {@code schemaType} will be visible or not.
@@ -216,14 +302,15 @@
// Merged list available from getSchemasVisibleToPackages
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder setSchemaTypeVisibilityForPackage(@NonNull String schemaType,
- boolean visible, @NonNull PackageIdentifier packageIdentifier) {
+ public Builder setSchemaTypeVisibilityForPackage(
+ @NonNull String schemaType,
+ boolean visible,
+ @NonNull PackageIdentifier packageIdentifier) {
Preconditions.checkNotNull(schemaType);
Preconditions.checkNotNull(packageIdentifier);
- Preconditions.checkState(!mBuilt, "Builder has already been used");
+ resetIfBuilt();
- Set<PackageIdentifier> packageIdentifiers =
- mSchemasVisibleToPackages.get(schemaType);
+ Set<PackageIdentifier> packageIdentifiers = mSchemasVisibleToPackages.get(schemaType);
if (visible) {
if (packageIdentifiers == null) {
packageIdentifiers = new ArraySet<>();
@@ -245,83 +332,212 @@
return this;
}
-// @exportToFramework:startStrip()
/**
- * Sets visibility on system UI surfaces for the given {@code dataClass}.
+ * Sets the {@link Migrator} associated with the given SchemaType.
*
- * @param dataClass The schema to set visibility on.
- * @param visible Whether the {@code schemaType} will be visible or not.
- * @return {@link SetSchemaRequest.Builder}
- * @throws AppSearchException if {@code androidx.appsearch.compiler.AppSearchCompiler}
- * has not generated a schema for the given data classes.
+ * <p>The {@link Migrator} migrates all {@link GenericDocument}s under given schema type
+ * from the current version number stored in AppSearch to the final version set via
+ * {@link #setVersion}.
+ *
+ * <p>A {@link Migrator} will be invoked if the current version number stored in
+ * AppSearch is different from the final version set via {@link #setVersion} and
+ * {@link Migrator#shouldMigrate} returns {@code true}.
+ *
+ * <p>The target schema type of the output {@link GenericDocument} of
+ * {@link Migrator#onUpgrade} or {@link Migrator#onDowngrade} must exist in this
+ * {@link SetSchemaRequest}.
+ *
+ * @param schemaType The schema type to set migrator on.
+ * @param migrator The migrator translates a document from its current version to the
+ * final version set via {@link #setVersion}.
+ *
+ * @see SetSchemaRequest.Builder#setVersion
+ * @see SetSchemaRequest.Builder#addSchemas
+ * @see AppSearchSession#setSchema
*/
- // Merged list available from getSchemasNotVisibleToSystemUi
- @SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder setDataClassVisibilityForSystemUi(@NonNull Class<?> dataClass,
- boolean visible) throws AppSearchException {
- Preconditions.checkNotNull(dataClass);
-
- DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
- DataClassFactory<?> factory = registry.getOrCreateFactory(dataClass);
- return setSchemaTypeVisibilityForSystemUi(factory.getSchemaType(), visible);
+ @SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
+ public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) {
+ Preconditions.checkNotNull(schemaType);
+ Preconditions.checkNotNull(migrator);
+ resetIfBuilt();
+ mMigrators.put(schemaType, migrator);
+ return this;
}
/**
- * Sets visibility for a package for the given {@code dataClass}.
+ * Sets a Map of {@link Migrator}s.
*
- * @param dataClass The schema to set visibility on.
- * @param visible Whether the {@code schemaType} will be visible or not.
- * @param packageIdentifier Represents the package that will be granted visibility
- * @return {@link SetSchemaRequest.Builder}
+ * <p>The key of the map is the schema type that the {@link Migrator} value applies to.
+ *
+ * <p>The {@link Migrator} migrates all {@link GenericDocument}s under given schema type
+ * from the current version number stored in AppSearch to the final version set via
+ * {@link #setVersion}.
+ *
+ * <p>A {@link Migrator} will be invoked if the current version number stored in
+ * AppSearch is different from the final version set via {@link #setVersion} and
+ * {@link Migrator#shouldMigrate} returns {@code true}.
+ *
+ * <p>The target schema type of the output {@link GenericDocument} of
+ * {@link Migrator#onUpgrade} or {@link Migrator#onDowngrade} must exist in this
+ * {@link SetSchemaRequest}.
+ *
+ * @param migrators A {@link Map} of migrators that translate a document from it's current
+ * version to the final version set via {@link #setVersion}. The key of
+ * the map is the schema type that the {@link Migrator} value applies to.
+ *
+ * @see SetSchemaRequest.Builder#setVersion
+ * @see SetSchemaRequest.Builder#addSchemas
+ * @see AppSearchSession#setSchema
+ */
+ @NonNull
+ public Builder setMigrators(@NonNull Map<String, Migrator> migrators) {
+ Preconditions.checkNotNull(migrators);
+ resetIfBuilt();
+ mMigrators.putAll(migrators);
+ return this;
+ }
+
+// @exportToFramework:startStrip()
+
+ /**
+ * Sets whether or not documents from the provided
+ * {@link androidx.appsearch.annotation.Document} annotated class will be displayed and
+ * visible on any system UI surface.
+ *
+ * <p>This setting applies to the provided {@link androidx.appsearch.annotation.Document}
+ * annotated class only, and does not persist across {@link AppSearchSession#setSchema}
+ * calls.
+ *
+ * <p>The default behavior, if this method is not called, is to allow types to be
+ * displayed on system UI surfaces.
+ *
+ * @param documentClass A class annotated with
+ * {@link androidx.appsearch.annotation.Document}, the visibility of
+ * which will be configured
+ * @param displayed Whether documents of this type will be displayed on system UI
+ * surfaces.
* @throws AppSearchException if {@code androidx.appsearch.compiler.AppSearchCompiler}
- * has not generated a schema for the given data classes.
+ * has not generated a schema for the given document class.
+ */
+ // Merged list available from getSchemasNotDisplayedBySystem
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setDocumentClassDisplayedBySystem(@NonNull Class<?> documentClass,
+ boolean displayed) throws AppSearchException {
+ Preconditions.checkNotNull(documentClass);
+ resetIfBuilt();
+ DocumentClassFactoryRegistry registry = DocumentClassFactoryRegistry.getInstance();
+ DocumentClassFactory<?> factory = registry.getOrCreateFactory(documentClass);
+ return setSchemaTypeDisplayedBySystem(factory.getSchemaName(), displayed);
+ }
+
+ /**
+ * Sets whether or not documents from the provided
+ * {@link androidx.appsearch.annotation.Document} annotated class can be read by the
+ * specified package.
+ *
+ * <p>Each package is represented by a {@link PackageIdentifier}, containing a package name
+ * and a byte array of type {@link android.content.pm.PackageManager#CERT_INPUT_SHA256}.
+ *
+ * <p>To opt into one-way data sharing with another application, the developer will need to
+ * explicitly grant the other application’s package name and certificate Read access to its
+ * data.
+ *
+ * <p>For two-way data sharing, both applications need to explicitly grant Read access to
+ * one another.
+ *
+ * <p>By default, app data sharing between applications is disabled.
+ *
+ * @param documentClass The {@link androidx.appsearch.annotation.Document} class to set
+ * visibility on.
+ * @param visible Whether the {@code documentClass} will be visible or not.
+ * @param packageIdentifier Represents the package that will be granted visibility.
+ * @throws AppSearchException if {@code androidx.appsearch.compiler.AppSearchCompiler}
+ * has not generated a schema for the given document class.
*/
// Merged list available from getSchemasVisibleToPackages
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder setDataClassVisibilityForPackage(@NonNull Class<?> dataClass,
+ public Builder setDocumentClassVisibilityForPackage(@NonNull Class<?> documentClass,
boolean visible, @NonNull PackageIdentifier packageIdentifier)
throws AppSearchException {
- Preconditions.checkNotNull(dataClass);
-
- DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
- DataClassFactory<?> factory = registry.getOrCreateFactory(dataClass);
- return setSchemaTypeVisibilityForPackage(factory.getSchemaType(), visible,
+ Preconditions.checkNotNull(documentClass);
+ resetIfBuilt();
+ DocumentClassFactoryRegistry registry = DocumentClassFactoryRegistry.getInstance();
+ DocumentClassFactory<?> factory = registry.getOrCreateFactory(documentClass);
+ return setSchemaTypeVisibilityForPackage(factory.getSchemaName(), visible,
packageIdentifier);
}
// @exportToFramework:endStrip()
/**
- * Configures the {@link SetSchemaRequest} to delete any existing documents that don't
- * follow the new schema.
+ * Sets whether or not to override the current schema in the {@link AppSearchSession}
+ * database.
*
- * <p>By default, this is {@code false} and schema incompatibility causes the
- * {@link AppSearchSession#setSchema} call to fail.
+ * <p>Call this method whenever backward incompatible changes need to be made by setting
+ * {@code forceOverride} to {@code true}. As a result, during execution of the setSchema
+ * operation, all documents that are incompatible with the new schema will be deleted and
+ * the new schema will be saved and persisted.
*
- * @see AppSearchSession#setSchema
+ * <p>By default, this is {@code false}.
*/
@NonNull
public Builder setForceOverride(boolean forceOverride) {
+ resetIfBuilt();
mForceOverride = forceOverride;
return this;
}
/**
- * Builds a new {@link SetSchemaRequest}.
+ * Sets the version number of the overall {@link AppSearchSchema} in the database.
*
- * @throws IllegalArgumentException If schema types were referenced, but the
- * corresponding {@link AppSearchSchema} was never added.
+ * <p>The {@link AppSearchSession} database can only ever hold documents for one version
+ * at a time.
+ *
+ * <p>Setting a version number that is different from the version number currently stored
+ * in AppSearch will result in AppSearch calling the {@link Migrator}s provided to
+ * {@link AppSearchSession#setSchema} to migrate the documents already in AppSearch from
+ * the previous version to the one set in this request. The version number can be
+ * updated without any other changes to the set of schemas.
+ *
+ * <p>The version number can stay the same, increase, or decrease relative to the current
+ * version number that is already stored in the {@link AppSearchSession} database.
+ *
+ * <p>The version of an empty database will always be 0. You cannot set version to the
+ * {@link SetSchemaRequest}, if it doesn't contains any {@link AppSearchSchema}.
+ *
+ * @param version A positive integer representing the version of the entire set of
+ * schemas represents the version of the whole schema in the
+ * {@link AppSearchSession} database, default version is 1.
+ *
+ * @throws IllegalArgumentException if the version is negative.
+ *
+ * @see AppSearchSession#setSchema
+ * @see Migrator
+ * @see SetSchemaRequest.Builder#setMigrator
+ */
+ @NonNull
+ public Builder setVersion(@IntRange(from = 1) int version) {
+ Preconditions.checkArgument(version >= 1, "Version must be a positive number.");
+ resetIfBuilt();
+ mVersion = version;
+ return this;
+ }
+
+ /**
+ * Builds a new {@link SetSchemaRequest} object.
+ *
+ * @throws IllegalArgumentException if schema types were referenced, but the
+ * corresponding {@link AppSearchSchema} type was never
+ * added.
*/
@NonNull
public SetSchemaRequest build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBuilt = true;
-
- // Verify that any schema types with visibility settings refer to a real schema.
+ // Verify that any schema types with display or visibility settings refer to a real
+ // schema.
// Create a copy because we're going to remove from the set for verification purposes.
- Set<String> referencedSchemas = new ArraySet<>(
- mSchemasNotVisibleToSystemUi);
+ Set<String> referencedSchemas = new ArraySet<>(mSchemasNotDisplayedBySystem);
referencedSchemas.addAll(mSchemasVisibleToPackages.keySet());
for (AppSearchSchema schema : mSchemas) {
@@ -331,13 +547,37 @@
// We still have schema types that weren't seen in our mSchemas set. This means
// there wasn't a corresponding AppSearchSchema.
throw new IllegalArgumentException(
- "Schema types " + referencedSchemas
- + " referenced, but were not added.");
+ "Schema types " + referencedSchemas + " referenced, but were not added.");
}
-
- return new SetSchemaRequest(mSchemas, mSchemasNotVisibleToSystemUi,
+ if (mSchemas.isEmpty() && mVersion != DEFAULT_VERSION) {
+ throw new IllegalArgumentException(
+ "Cannot set version to the request if schema is empty.");
+ }
+ mBuilt = true;
+ return new SetSchemaRequest(
+ mSchemas,
+ mSchemasNotDisplayedBySystem,
mSchemasVisibleToPackages,
- mForceOverride);
+ mMigrators,
+ mForceOverride,
+ mVersion);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ ArrayMap<String, Set<PackageIdentifier>> schemasVisibleToPackages =
+ new ArrayMap<>(mSchemasVisibleToPackages.size());
+ for (Map.Entry<String, Set<PackageIdentifier>> entry
+ : mSchemasVisibleToPackages.entrySet()) {
+ schemasVisibleToPackages.put(entry.getKey(), new ArraySet<>(entry.getValue()));
+ }
+ mSchemasVisibleToPackages = schemasVisibleToPackages;
+
+ mSchemas = new ArraySet<>(mSchemas);
+ mSchemasNotDisplayedBySystem = new ArraySet<>(mSchemasNotDisplayedBySystem);
+ mMigrators = new ArrayMap<>(mMigrators);
+ mBuilt = false;
+ }
}
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaResponse.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaResponse.java
new file mode 100644
index 0000000..88e6645
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaResponse.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.collection.ArraySet;
+import androidx.core.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/** The response class of {@link AppSearchSession#setSchema} */
+public class SetSchemaResponse {
+
+ private static final String DELETED_TYPES_FIELD = "deletedTypes";
+ private static final String INCOMPATIBLE_TYPES_FIELD = "incompatibleTypes";
+ private static final String MIGRATED_TYPES_FIELD = "migratedTypes";
+
+ private final Bundle mBundle;
+ /**
+ * The migrationFailures won't be saved in the bundle. Since:
+ * <ul>
+ * <li>{@link MigrationFailure} is generated in {@link AppSearchSession} which will be
+ * the SDK side in platform. We don't need to pass it from service side via binder.
+ * <li>Translate multiple {@link MigrationFailure}s to bundles in {@link Builder} and then
+ * back in constructor will be a huge waste.
+ * </ul>
+ */
+ private final List<MigrationFailure> mMigrationFailures;
+
+ /** Cache of the inflated deleted schema types. Comes from inflating mBundles at first use. */
+ @Nullable
+ private Set<String> mDeletedTypes;
+
+ /** Cache of the inflated migrated schema types. Comes from inflating mBundles at first use. */
+ @Nullable
+ private Set<String> mMigratedTypes;
+
+ /**
+ * Cache of the inflated incompatible schema types. Comes from inflating mBundles at first use.
+ */
+ @Nullable
+ private Set<String> mIncompatibleTypes;
+
+ SetSchemaResponse(@NonNull Bundle bundle, @NonNull List<MigrationFailure> migrationFailures) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ mMigrationFailures = Preconditions.checkNotNull(migrationFailures);
+ }
+
+ SetSchemaResponse(@NonNull Bundle bundle) {
+ this(bundle, /*migrationFailures=*/ Collections.emptyList());
+ }
+
+ /**
+ * Returns the {@link Bundle} populated by this builder.
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public Bundle getBundle() {
+ return mBundle;
+ }
+
+ /**
+ * Returns a {@link List} of all failed {@link MigrationFailure}.
+ *
+ * <p>A {@link MigrationFailure} will be generated if the system trying to save a post-migrated
+ * {@link GenericDocument} but fail.
+ *
+ * <p>{@link MigrationFailure} contains the namespace, id and schemaType of the post-migrated
+ * {@link GenericDocument} and the error reason. Mostly it will be mismatch the schema it
+ * migrated to.
+ */
+ @NonNull
+ public List<MigrationFailure> getMigrationFailures() {
+ return Collections.unmodifiableList(mMigrationFailures);
+ }
+
+ /**
+ * Returns a {@link Set} of deleted schema types.
+ *
+ * <p>A "deleted" type is a schema type that was previously a part of the database schema but
+ * was not present in the {@link SetSchemaRequest} object provided in the
+ * {@link AppSearchSession#setSchema) call.
+ *
+ * <p>Documents for a deleted type are removed from the database.
+ */
+ @NonNull
+ public Set<String> getDeletedTypes() {
+ if (mDeletedTypes == null) {
+ mDeletedTypes = new ArraySet<>(
+ Preconditions.checkNotNull(mBundle.getStringArrayList(DELETED_TYPES_FIELD)));
+ }
+ return Collections.unmodifiableSet(mDeletedTypes);
+ }
+
+ /**
+ * Returns a {@link Set} of schema type that were migrated by the
+ * {@link AppSearchSession#setSchema} call.
+ *
+ * <p> A "migrated" type is a schema type that has triggered a {@link Migrator} instance to
+ * migrate documents of the schema type to another schema type, or to another version of the
+ * schema type.
+ *
+ * <p>If a document fails to be migrated, a {@link MigrationFailure} will be generated
+ * for that document.
+ *
+ * @see Migrator
+ */
+ @NonNull
+ public Set<String> getMigratedTypes() {
+ if (mMigratedTypes == null) {
+ mMigratedTypes = new ArraySet<>(
+ Preconditions.checkNotNull(mBundle.getStringArrayList(MIGRATED_TYPES_FIELD)));
+ }
+ return Collections.unmodifiableSet(mMigratedTypes);
+ }
+
+ /**
+ * Returns a {@link Set} of schema type whose new definitions set in the
+ * {@link AppSearchSession#setSchema} call were incompatible with the pre-existing schema.
+ *
+ * <p>If a {@link Migrator} is provided for this type and the migration is success triggered.
+ * The type will also appear in {@link #getMigratedTypes()}.
+ *
+ * @see SetSchemaRequest
+ * @see AppSearchSession#setSchema
+ * @see SetSchemaRequest.Builder#setForceOverride
+ */
+ @NonNull
+ public Set<String> getIncompatibleTypes() {
+ if (mIncompatibleTypes == null) {
+ mIncompatibleTypes = new ArraySet<>(
+ Preconditions.checkNotNull(
+ mBundle.getStringArrayList(INCOMPATIBLE_TYPES_FIELD)));
+ }
+ return Collections.unmodifiableSet(mIncompatibleTypes);
+ }
+
+ /**
+ * Translates the {@link SetSchemaResponse}'s bundle to {@link Builder}.
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ // TODO(b/179302942) change to Builder(mBundle) powered by mBundle.deepCopy
+ public Builder toBuilder() {
+ return new Builder()
+ .addDeletedTypes(getDeletedTypes())
+ .addIncompatibleTypes(getIncompatibleTypes())
+ .addMigratedTypes(getMigratedTypes())
+ .addMigrationFailures(mMigrationFailures);
+ }
+
+ /** Builder for {@link SetSchemaResponse} objects. */
+ public static final class Builder {
+ private List<MigrationFailure> mMigrationFailures = new ArrayList<>();
+ private ArrayList<String> mDeletedTypes = new ArrayList<>();
+ private ArrayList<String> mMigratedTypes = new ArrayList<>();
+ private ArrayList<String> mIncompatibleTypes = new ArrayList<>();
+ private boolean mBuilt = false;
+
+ /** Adds {@link MigrationFailure}s to the list of migration failures. */
+ @NonNull
+ public Builder addMigrationFailures(
+ @NonNull Collection<MigrationFailure> migrationFailures) {
+ Preconditions.checkNotNull(migrationFailures);
+ resetIfBuilt();
+ mMigrationFailures.addAll(migrationFailures);
+ return this;
+ }
+
+ /** Adds a {@link MigrationFailure} to the list of migration failures. */
+ @NonNull
+ public Builder addMigrationFailure(@NonNull MigrationFailure migrationFailure) {
+ Preconditions.checkNotNull(migrationFailure);
+ resetIfBuilt();
+ mMigrationFailures.add(migrationFailure);
+ return this;
+ }
+
+ /** Adds deletedTypes to the list of deleted schema types. */
+ @NonNull
+ public Builder addDeletedTypes(@NonNull Collection<String> deletedTypes) {
+ Preconditions.checkNotNull(deletedTypes);
+ resetIfBuilt();
+ mDeletedTypes.addAll(deletedTypes);
+ return this;
+ }
+
+ /** Adds one deletedType to the list of deleted schema types. */
+ @NonNull
+ public Builder addDeletedType(@NonNull String deletedType) {
+ Preconditions.checkNotNull(deletedType);
+ resetIfBuilt();
+ mDeletedTypes.add(deletedType);
+ return this;
+ }
+
+ /** Adds incompatibleTypes to the list of incompatible schema types. */
+ @NonNull
+ public Builder addIncompatibleTypes(@NonNull Collection<String> incompatibleTypes) {
+ Preconditions.checkNotNull(incompatibleTypes);
+ resetIfBuilt();
+ mIncompatibleTypes.addAll(incompatibleTypes);
+ return this;
+ }
+
+ /** Adds one incompatibleType to the list of incompatible schema types. */
+ @NonNull
+ public Builder addIncompatibleType(@NonNull String incompatibleType) {
+ Preconditions.checkNotNull(incompatibleType);
+ resetIfBuilt();
+ mIncompatibleTypes.add(incompatibleType);
+ return this;
+ }
+
+ /** Adds migratedTypes to the list of migrated schema types. */
+ @NonNull
+ public Builder addMigratedTypes(@NonNull Collection<String> migratedTypes) {
+ Preconditions.checkNotNull(migratedTypes);
+ resetIfBuilt();
+ mMigratedTypes.addAll(migratedTypes);
+ return this;
+ }
+
+ /** Adds one migratedType to the list of migrated schema types. */
+ @NonNull
+ public Builder addMigratedType(@NonNull String migratedType) {
+ Preconditions.checkNotNull(migratedType);
+ resetIfBuilt();
+ mMigratedTypes.add(migratedType);
+ return this;
+ }
+
+ /** Builds a {@link SetSchemaResponse} object. */
+ @NonNull
+ public SetSchemaResponse build() {
+ Bundle bundle = new Bundle();
+ bundle.putStringArrayList(INCOMPATIBLE_TYPES_FIELD, mIncompatibleTypes);
+ bundle.putStringArrayList(DELETED_TYPES_FIELD, mDeletedTypes);
+ bundle.putStringArrayList(MIGRATED_TYPES_FIELD, mMigratedTypes);
+ mBuilt = true;
+ // Avoid converting the potential thousands of MigrationFailures to Pracelable and
+ // back just for put in bundle. In platform, we should set MigrationFailures in
+ // AppSearchSession after we pass SetSchemaResponse via binder.
+ return new SetSchemaResponse(bundle, mMigrationFailures);
+ }
+
+ private void resetIfBuilt() {
+ if (mBuilt) {
+ mMigrationFailures = new ArrayList<>(mMigrationFailures);
+ mDeletedTypes = new ArrayList<>(mDeletedTypes);
+ mMigratedTypes = new ArrayList<>(mMigratedTypes);
+ mIncompatibleTypes = new ArrayList<>(mIncompatibleTypes);
+ mBuilt = false;
+ }
+ }
+ }
+
+ /**
+ * The class represents a post-migrated {@link GenericDocument} that failed to be saved by
+ * {@link AppSearchSession#setSchema}.
+ */
+ public static class MigrationFailure {
+ private static final String SCHEMA_TYPE_FIELD = "schemaType";
+ private static final String NAMESPACE_FIELD = "namespace";
+ private static final String DOCUMENT_ID_FIELD = "id";
+ private static final String ERROR_MESSAGE_FIELD = "errorMessage";
+ private static final String RESULT_CODE_FIELD = "resultCode";
+
+ private final Bundle mBundle;
+
+ /**
+ * Constructs a new {@link MigrationFailure}.
+ *
+ * @param namespace The namespace of the document which failed to be migrated.
+ * @param documentId The id of the document which failed to be migrated.
+ * @param schemaType The type of the document which failed to be migrated.
+ * @param failedResult The reason why the document failed to be indexed.
+ * @throws IllegalArgumentException if the provided {@code failedResult} was not a failure.
+ */
+ public MigrationFailure(
+ @NonNull String namespace,
+ @NonNull String documentId,
+ @NonNull String schemaType,
+ @NonNull AppSearchResult<?> failedResult) {
+ mBundle = new Bundle();
+ mBundle.putString(NAMESPACE_FIELD, Preconditions.checkNotNull(namespace));
+ mBundle.putString(DOCUMENT_ID_FIELD, Preconditions.checkNotNull(documentId));
+ mBundle.putString(SCHEMA_TYPE_FIELD, Preconditions.checkNotNull(schemaType));
+
+ Preconditions.checkNotNull(failedResult);
+ Preconditions.checkArgument(
+ !failedResult.isSuccess(), "failedResult was actually successful");
+ mBundle.putString(ERROR_MESSAGE_FIELD, failedResult.getErrorMessage());
+ mBundle.putInt(RESULT_CODE_FIELD, failedResult.getResultCode());
+ }
+
+ MigrationFailure(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ }
+
+ /**
+ * Returns the Bundle of the {@link MigrationFailure}.
+ *
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public Bundle getBundle() {
+ return mBundle;
+ }
+
+ /** Returns the namespace of the {@link GenericDocument} that failed to be migrated. */
+ @NonNull
+ public String getNamespace() {
+ return mBundle.getString(NAMESPACE_FIELD, /*defaultValue=*/"");
+ }
+
+ /** Returns the id of the {@link GenericDocument} that failed to be migrated. */
+ @NonNull
+ public String getDocumentId() {
+ return mBundle.getString(DOCUMENT_ID_FIELD, /*defaultValue=*/"");
+ }
+
+ /** Returns the schema type of the {@link GenericDocument} that failed to be migrated. */
+ @NonNull
+ public String getSchemaType() {
+ return mBundle.getString(SCHEMA_TYPE_FIELD, /*defaultValue=*/"");
+ }
+
+ /**
+ * Returns the {@link AppSearchResult} that indicates why the
+ * post-migration {@link GenericDocument} failed to be indexed.
+ */
+ @NonNull
+ public AppSearchResult<Void> getAppSearchResult() {
+ return AppSearchResult.newFailedResult(mBundle.getInt(RESULT_CODE_FIELD),
+ mBundle.getString(ERROR_MESSAGE_FIELD, /*defaultValue=*/""));
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "MigrationFailure { schemaType: " + getSchemaType() + ", namespace: "
+ + getNamespace() + ", documentId: " + getDocumentId() + ", appSearchResult: "
+ + getAppSearchResult().toString() + "}";
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/StorageInfo.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StorageInfo.java
new file mode 100644
index 0000000..0d7901d
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StorageInfo.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.util.Preconditions;
+
+/** The response class of {@code AppSearchSession#getStorageInfo}. */
+public class StorageInfo {
+
+ private static final String SIZE_BYTES_FIELD = "sizeBytes";
+ private static final String ALIVE_DOCUMENTS_COUNT = "aliveDocumentsCount";
+ private static final String ALIVE_NAMESPACES_COUNT = "aliveNamespacesCount";
+
+ private final Bundle mBundle;
+
+ StorageInfo(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ }
+
+ /**
+ * Returns the {@link Bundle} populated by this builder.
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public Bundle getBundle() {
+ return mBundle;
+ }
+
+ /** Returns the estimated size of the session's database in bytes. */
+ public long getSizeBytes() {
+ return mBundle.getLong(SIZE_BYTES_FIELD);
+ }
+
+ /**
+ * Returns the number of alive documents in the current session.
+ *
+ * <p>Alive documents are documents that haven't been deleted and haven't exceeded the ttl as
+ * set in {@link GenericDocument.Builder#setTtlMillis}.
+ */
+ public int getAliveDocumentsCount() {
+ return mBundle.getInt(ALIVE_DOCUMENTS_COUNT);
+ }
+
+ /**
+ * Returns the number of namespaces that have at least one alive document in the current
+ * session's database.
+ *
+ * <p>Alive documents are documents that haven't been deleted and haven't exceeded the ttl as
+ * set in {@link GenericDocument.Builder#setTtlMillis}.
+ */
+ public int getAliveNamespacesCount() {
+ return mBundle.getInt(ALIVE_NAMESPACES_COUNT);
+ }
+
+ /** Builder for {@link StorageInfo} objects. */
+ public static final class Builder {
+ private long mSizeBytes;
+ private int mAliveDocumentsCount;
+ private int mAliveNamespacesCount;
+
+ /** Sets the size in bytes. */
+ @NonNull
+ public StorageInfo.Builder setSizeBytes(long sizeBytes) {
+ mSizeBytes = sizeBytes;
+ return this;
+ }
+
+ /** Sets the number of alive documents. */
+ @NonNull
+ public StorageInfo.Builder setAliveDocumentsCount(int aliveDocumentsCount) {
+ mAliveDocumentsCount = aliveDocumentsCount;
+ return this;
+ }
+
+ /** Sets the number of alive namespaces. */
+ @NonNull
+ public StorageInfo.Builder setAliveNamespacesCount(int aliveNamespacesCount) {
+ mAliveNamespacesCount = aliveNamespacesCount;
+ return this;
+ }
+
+ /** Builds a {@link StorageInfo} object. */
+ @NonNull
+ public StorageInfo build() {
+ Bundle bundle = new Bundle();
+ bundle.putLong(SIZE_BYTES_FIELD, mSizeBytes);
+ bundle.putInt(ALIVE_DOCUMENTS_COUNT, mAliveDocumentsCount);
+ bundle.putInt(ALIVE_NAMESPACES_COUNT, mAliveNamespacesCount);
+ return new StorageInfo(bundle);
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/AppSearchException.java b/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/AppSearchException.java
index 262c97e..98689f5 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/AppSearchException.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/AppSearchException.java
@@ -31,19 +31,35 @@
/**
* Initializes an {@link AppSearchException} with no message.
- * @hide
+ *
+ * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}.
*/
public AppSearchException(@AppSearchResult.ResultCode int resultCode) {
this(resultCode, /*message=*/ null);
}
- /** @hide */
+ /**
+ * Initializes an {@link AppSearchException} with a result code and message.
+ *
+ * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}.
+ * @param message The detail message (which is saved for later retrieval by the
+ * {@link #getMessage()} method).
+ */
public AppSearchException(
@AppSearchResult.ResultCode int resultCode, @Nullable String message) {
this(resultCode, message, /*cause=*/ null);
}
- /** @hide */
+ /**
+ * Initializes an {@link AppSearchException} with a result code, message and cause.
+ *
+ * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}.
+ * @param message The detail message (which is saved for later retrieval by the
+ * {@link #getMessage()} method).
+ * @param cause The cause (which is saved for later retrieval by the {@link #getCause()}
+ * method). (A null value is permitted, and indicates that the cause is
+ * nonexistent or unknown.)
+ */
public AppSearchException(
@AppSearchResult.ResultCode int resultCode,
@Nullable String message,
@@ -52,14 +68,16 @@
mResultCode = resultCode;
}
- /** Returns the result code this exception was constructed with. */
+ /**
+ * Returns the result code this exception was constructed with.
+ *
+ * @return One of the constants documented in {@link AppSearchResult#getResultCode}.
+ */
public @AppSearchResult.ResultCode int getResultCode() {
return mResultCode;
}
- /**
- * Converts this {@link java.lang.Exception} into a failed {@link AppSearchResult}
- */
+ /** Converts this {@link java.lang.Exception} into a failed {@link AppSearchResult}. */
@NonNull
public <T> AppSearchResult<T> toAppSearchResult() {
return AppSearchResult.newFailedResult(mResultCode, getMessage());
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/IllegalSearchSpecException.java b/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/IllegalSearchSpecException.java
deleted file mode 100644
index 3e06f81..0000000
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/IllegalSearchSpecException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.exceptions;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * Indicates that a {@link androidx.appsearch.app.SearchResult} has logical inconsistencies such
- * as unpopulated mandatory fields or illegal combinations of parameters.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class IllegalSearchSpecException extends IllegalArgumentException {
- /**
- * Constructs a new {@link IllegalSearchSpecException}.
- *
- * @param message A developer-readable description of the issue with the bundle.
- */
- public IllegalSearchSpecException(@NonNull String message) {
- super(message);
- }
-}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/util/BundleUtil.java b/appsearch/appsearch/src/main/java/androidx/appsearch/util/BundleUtil.java
index 86de233..bf22395 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/util/BundleUtil.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/util/BundleUtil.java
@@ -17,8 +17,10 @@
package androidx.appsearch.util;
import android.os.Bundle;
+import android.os.Parcel;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
@@ -148,35 +150,41 @@
if (bundle == null) {
return 0;
}
- int[] hashCodes = new int[bundle.size()];
- int i = 0;
+ int[] hashCodes = new int[bundle.size() + 1];
+ int hashCodeIdx = 0;
// Bundle inherit its hashCode() from Object.java, which only relative to their memory
// address. Bundle doesn't have an order, so we should iterate all keys and combine
// their value's hashcode into an array. And use the hashcode of the array to be
// the hashcode of the bundle.
- for (String key : bundle.keySet()) {
- Object value = bundle.get(key);
+ // Because bundle.keySet() doesn't guarantee any particular order, we need to sort the keys
+ // in case the iteration order varies from run to run.
+ String[] keys = bundle.keySet().toArray(new String[0]);
+ Arrays.sort(keys);
+ // Hash the keys so we can detect key-only differences
+ hashCodes[hashCodeIdx++] = Arrays.hashCode(keys);
+ for (int keyIdx = 0; keyIdx < keys.length; keyIdx++) {
+ Object value = bundle.get(keys[keyIdx]);
if (value instanceof Bundle) {
- hashCodes[i++] = deepHashCode((Bundle) value);
+ hashCodes[hashCodeIdx++] = deepHashCode((Bundle) value);
} else if (value instanceof int[]) {
- hashCodes[i++] = Arrays.hashCode((int[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((int[]) value);
} else if (value instanceof byte[]) {
- hashCodes[i++] = Arrays.hashCode((byte[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((byte[]) value);
} else if (value instanceof char[]) {
- hashCodes[i++] = Arrays.hashCode((char[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((char[]) value);
} else if (value instanceof long[]) {
- hashCodes[i++] = Arrays.hashCode((long[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((long[]) value);
} else if (value instanceof float[]) {
- hashCodes[i++] = Arrays.hashCode((float[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((float[]) value);
} else if (value instanceof short[]) {
- hashCodes[i++] = Arrays.hashCode((short[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((short[]) value);
} else if (value instanceof double[]) {
- hashCodes[i++] = Arrays.hashCode((double[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((double[]) value);
} else if (value instanceof boolean[]) {
- hashCodes[i++] = Arrays.hashCode((boolean[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((boolean[]) value);
} else if (value instanceof String[]) {
// Optimization to avoid Object[] handler creating an inner array for common cases
- hashCodes[i++] = Arrays.hashCode((String[]) value);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode((String[]) value);
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
int[] innerHashCodes = new int[array.length];
@@ -187,7 +195,7 @@
innerHashCodes[j] = array[j].hashCode();
}
}
- hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode(innerHashCodes);
} else if (value instanceof ArrayList) {
ArrayList<?> list = (ArrayList<?>) value;
int[] innerHashCodes = new int[list.size()];
@@ -199,7 +207,7 @@
innerHashCodes[j] = item.hashCode();
}
}
- hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode(innerHashCodes);
} else if (value instanceof SparseArray) {
SparseArray<?> array = (SparseArray<?>) value;
int[] innerHashCodes = new int[array.size() * 2];
@@ -212,11 +220,33 @@
innerHashCodes[j * 2 + 1] = item.hashCode();
}
}
- hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+ hashCodes[hashCodeIdx++] = Arrays.hashCode(innerHashCodes);
} else {
- hashCodes[i++] = value.hashCode();
+ hashCodes[hashCodeIdx++] = value.hashCode();
}
}
return Arrays.hashCode(hashCodes);
}
+
+ /**
+ * Deeply clones a Bundle.
+ *
+ * <p>Values which are Bundles, Lists or Arrays are deeply copied themselves.
+ */
+ @NonNull
+ public static Bundle deepCopy(@NonNull Bundle bundle) {
+ // Write bundle to bytes
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeBundle(bundle);
+ byte[] serializedMessage = parcel.marshall();
+
+ // Read bundle from bytes
+ parcel.unmarshall(serializedMessage, 0, serializedMessage.length);
+ parcel.setDataPosition(0);
+ return parcel.readBundle();
+ } finally {
+ parcel.recycle();
+ }
+ }
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/util/IndentingStringBuilder.java b/appsearch/appsearch/src/main/java/androidx/appsearch/util/IndentingStringBuilder.java
new file mode 100644
index 0000000..ea5717e
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/util/IndentingStringBuilder.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.util;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+/**
+ * Utility for building indented strings.
+ *
+ * <p>This is a wrapper for {@link StringBuilder} for appending strings with indentation.
+ * The indentation level can be increased by calling {@link #increaseIndentLevel()} and decreased
+ * by calling {@link #decreaseIndentLevel()}.
+ *
+ * <p>Indentation is applied after each newline character for the given indent level.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class IndentingStringBuilder {
+ private final StringBuilder mStringBuilder = new StringBuilder();
+
+ // Indicates whether next non-newline character should have an indent applied before it.
+ private boolean mIndentNext = false;
+ private int mIndentLevel = 0;
+
+ /**
+ * Increases the indent level by one for appended strings.
+ */
+ @NonNull
+ public IndentingStringBuilder increaseIndentLevel() {
+ mIndentLevel++;
+ return this;
+ }
+
+ /**
+ * Decreases the indent level by one for appended strings.
+ */
+ @NonNull
+ public IndentingStringBuilder decreaseIndentLevel() throws IllegalStateException {
+ if (mIndentLevel == 0) {
+ throw new IllegalStateException("Cannot set indent level below 0.");
+ }
+ mIndentLevel--;
+ return this;
+ }
+
+ /**
+ * Appends provided {@code String} at the current indentation level.
+ *
+ * <p>Indentation is applied after each newline character.
+ */
+ @NonNull
+ public IndentingStringBuilder append(@NonNull String str) {
+ applyIndentToString(str);
+ return this;
+ }
+
+ /**
+ * Appends provided {@code Object}, represented as a {@code String}, at the current indentation
+ * level.
+ *
+ * <p>Indentation is applied after each newline character.
+ */
+ @NonNull
+ public IndentingStringBuilder append(@NonNull Object obj) {
+ applyIndentToString(obj.toString());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return mStringBuilder.toString();
+ }
+
+ /**
+ * Adds indent string to the {@link StringBuilder} instance for current indent level.
+ */
+ private void applyIndent() {
+ for (int i = 0; i < mIndentLevel; i++) {
+ mStringBuilder.append(" ");
+ }
+ }
+
+ /**
+ * Applies indent, for current indent level, after each newline character.
+ *
+ * <p>Consecutive newline characters are not indented.
+ */
+ private void applyIndentToString(@NonNull String str) {
+ int index = str.indexOf("\n");
+ if (index == 0) {
+ // String begins with new line character: append newline and slide past newline.
+ mStringBuilder.append("\n");
+ mIndentNext = true;
+ if (str.length() > 1) {
+ applyIndentToString(str.substring(index + 1));
+ }
+ } else if (index >= 1) {
+ // String contains new line character: divide string between newline, append new line,
+ // and recurse on each string.
+ String beforeIndentString = str.substring(0, index);
+ applyIndentToString(beforeIndentString);
+ mStringBuilder.append("\n");
+ mIndentNext = true;
+ if (str.length() > index + 1) {
+ String afterIndentString = str.substring(index + 1);
+ applyIndentToString(afterIndentString);
+ }
+ } else {
+ // String does not contain newline character: append string.
+ if (mIndentNext) {
+ applyIndent();
+ mIndentNext = false;
+ }
+ mStringBuilder.append(str);
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/util/LogUtil.java b/appsearch/appsearch/src/main/java/androidx/appsearch/util/LogUtil.java
new file mode 100644
index 0000000..b360ea0
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/util/LogUtil.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.util;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.core.util.Preconditions;
+
+/**
+ * Utilities for logging to logcat.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class LogUtil {
+ /**
+ * The {@link #piiTrace} logs are intended for sensitive data that can't be enabled in
+ * production, so they are build-gated by this constant.
+ *
+ * <p><ul>
+ * <li>0: no tracing.
+ * <li>1: fast tracing (statuses/counts only)
+ * <li>2: full tracing (complete messages)
+ * </ul>
+ */
+ private static final int PII_TRACE_LEVEL = 0;
+
+ private final String mTag;
+
+ public LogUtil(@NonNull String tag) {
+ mTag = Preconditions.checkNotNull(tag);
+ }
+
+ /** Returns whether piiTrace() is enabled (PII_TRACE_LEVEL > 0). */
+ public boolean isPiiTraceEnabled() {
+ return PII_TRACE_LEVEL > 0;
+ }
+
+ /**
+ * If icing lib interaction tracing is enabled via {@link #PII_TRACE_LEVEL}, logs the provided
+ * message to logcat.
+ *
+ * <p>If {@link #PII_TRACE_LEVEL} is 0, nothing is logged and this method returns immediately.
+ */
+ public void piiTrace(@NonNull String message) {
+ piiTrace(message, /*fastTraceObj=*/null, /*fullTraceObj=*/null);
+ }
+
+ /**
+ * If icing lib interaction tracing is enabled via {@link #PII_TRACE_LEVEL}, logs the provided
+ * message and object to logcat.
+ *
+ * <p>If {@link #PII_TRACE_LEVEL} is 0, nothing is logged and this method returns immediately.
+ * <p>Otherwise, {@code traceObj} is logged if it is non-null.
+ */
+ public void piiTrace(@NonNull String message, @Nullable Object traceObj) {
+ piiTrace(message, /*fastTraceObj=*/traceObj, /*fullTraceObj=*/null);
+ }
+
+ /**
+ * If icing lib interaction tracing is enabled via {@link #PII_TRACE_LEVEL}, logs the provided
+ * message and objects to logcat.
+ *
+ * <p>If {@link #PII_TRACE_LEVEL} is 0, nothing is logged and this method returns immediately.
+ * <p>If {@link #PII_TRACE_LEVEL} is 1, {@code fastTraceObj} is logged if it is non-null.
+ * <p>If {@link #PII_TRACE_LEVEL} is 2, {@code fullTraceObj} is logged if it is non-null, else
+ * {@code fastTraceObj} is logged if it is non-null..
+ */
+ public void piiTrace(
+ @NonNull String message, @Nullable Object fastTraceObj, @Nullable Object fullTraceObj) {
+ if (PII_TRACE_LEVEL == 0) {
+ return;
+ }
+ StringBuilder builder = new StringBuilder("(trace) ").append(message);
+ if (PII_TRACE_LEVEL == 1 && fastTraceObj != null) {
+ builder.append(": ").append(fastTraceObj);
+ } else if (PII_TRACE_LEVEL == 2 && fullTraceObj != null) {
+ builder.append(": ").append(fullTraceObj);
+ } else if (PII_TRACE_LEVEL == 2 && fastTraceObj != null) {
+ builder.append(": ").append(fastTraceObj);
+ }
+ Log.i(mTag, builder.toString());
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/util/SchemaMigrationUtil.java b/appsearch/appsearch/src/main/java/androidx/appsearch/util/SchemaMigrationUtil.java
new file mode 100644
index 0000000..1408fb8
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/util/SchemaMigrationUtil.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.util;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.Migrator;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.collection.ArrayMap;
+import androidx.collection.ArraySet;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utilities for schema migration.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class SchemaMigrationUtil {
+ private SchemaMigrationUtil() {}
+
+ /**
+ * Returns all active {@link Migrator}s that need to be triggered in this migration.
+ *
+ * <p>{@link Migrator#shouldMigrate} returns {@code true} will make the {@link Migrator} active.
+ */
+ @NonNull
+ public static Map<String, Migrator> getActiveMigrators(
+ @NonNull Set<AppSearchSchema> existingSchemas,
+ @NonNull Map<String, Migrator> migrators,
+ int currentVersion,
+ int finalVersion) {
+ if (currentVersion == finalVersion) {
+ return Collections.emptyMap();
+ }
+ Set<String> existingTypes = new ArraySet<>(existingSchemas.size());
+ for (AppSearchSchema schema : existingSchemas) {
+ existingTypes.add(schema.getSchemaType());
+ }
+
+ Map<String, Migrator> activeMigrators = new ArrayMap<>();
+ for (Map.Entry<String, Migrator> entry : migrators.entrySet()) {
+ // The device contains the source type, and we should trigger migration for the type.
+ String schemaType = entry.getKey();
+ Migrator migrator = entry.getValue();
+ if (existingTypes.contains(schemaType)
+ && migrator.shouldMigrate(currentVersion, finalVersion)) {
+ activeMigrators.put(schemaType, migrator);
+ }
+ }
+ return activeMigrators;
+ }
+
+ /**
+ * Checks the setSchema() call won't delete any types or has incompatible types after
+ * all {@link Migrator} has been triggered.
+ */
+ public static void checkDeletedAndIncompatibleAfterMigration(
+ @NonNull SetSchemaResponse setSchemaResponse,
+ @NonNull Set<String> activeMigrators) throws AppSearchException {
+ Set<String> unmigratedIncompatibleTypes =
+ new ArraySet<>(setSchemaResponse.getIncompatibleTypes());
+ unmigratedIncompatibleTypes.removeAll(activeMigrators);
+
+ Set<String> unmigratedDeletedTypes =
+ new ArraySet<>(setSchemaResponse.getDeletedTypes());
+ unmigratedDeletedTypes.removeAll(activeMigrators);
+
+ // check if there are any unmigrated incompatible types or deleted types. If there
+ // are, we will getActiveMigratorsthrow an exception. That's the only case we
+ // swallowed in the AppSearchImpl#setSchema().
+ // Since the force override is false, the schema will not have been set if there are
+ // any incompatible or deleted types.
+ checkDeletedAndIncompatible(unmigratedDeletedTypes,
+ unmigratedIncompatibleTypes);
+ }
+
+ /** Checks the setSchema() call won't delete any types or has incompatible types. */
+ public static void checkDeletedAndIncompatible(@NonNull Set<String> deletedTypes,
+ @NonNull Set<String> incompatibleTypes) throws AppSearchException {
+ if (deletedTypes.size() > 0
+ || incompatibleTypes.size() > 0) {
+ String newMessage = "Schema is incompatible."
+ + "\n Deleted types: " + deletedTypes
+ + "\n Incompatible types: " + incompatibleTypes;
+ throw new AppSearchException(AppSearchResult.RESULT_INVALID_SCHEMA, newMessage);
+ }
+ }
+}
diff --git a/appsearch/compiler/build.gradle b/appsearch/compiler/build.gradle
index 3ce8ab9..93c22c6 100644
--- a/appsearch/compiler/build.gradle
+++ b/appsearch/compiler/build.gradle
@@ -24,6 +24,10 @@
dependencies {
api('androidx.annotation:annotation:1.1.0')
+ api(libs.jsr250)
+ implementation(libs.autoCommon)
+ implementation(libs.autoValue)
+ implementation(libs.autoValueAnnotations)
implementation(libs.javapoet)
// For testing, add in the compiled classes from appsearch to get access to annotations.
@@ -41,6 +45,6 @@
type = LibraryType.COMPILER_PLUGIN
mavenGroup = LibraryGroups.APPSEARCH
inceptionYear = '2019'
- description = 'Compiler for AndroidX AppSearch data classes'
+ description = 'Compiler for classes annotated with @androidx.appsearch.annotation.Document'
failOnDeprecationWarnings = false
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/AppSearchCompiler.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/AppSearchCompiler.java
index 63f6e379..90f31aa 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/AppSearchCompiler.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/AppSearchCompiler.java
@@ -15,17 +15,24 @@
*/
package androidx.appsearch.compiler;
+import static javax.lang.model.util.ElementFilter.typesIn;
+
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.google.auto.common.BasicAnnotationProcessor;
+import com.google.auto.common.MoreElements;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+
import java.io.File;
import java.io.IOException;
import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
@@ -33,13 +40,17 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
-/** Processes AppSearchDocument annotations. */
-@SupportedAnnotationTypes({IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS})
+/**
+ * Processes {@code androidx.appsearch.annotation.Document} annotations.
+ *
+ * <p>Only plain Java objects and AutoValue Document classes without builders are supported.
+ */
+@SupportedAnnotationTypes({IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedOptions({AppSearchCompiler.OUTPUT_DIR_OPTION})
-public class AppSearchCompiler extends AbstractProcessor {
+public class AppSearchCompiler extends BasicAnnotationProcessor {
/**
* This property causes us to write output to a different folder instead of the usual filer
* location. It should only be used for testing.
@@ -47,8 +58,6 @@
@VisibleForTesting
static final String OUTPUT_DIR_OPTION = "AppSearchCompiler.OutputDir";
- private Messager mMessager;
-
@Override
@NonNull
public SourceVersion getSupportedSourceVersion() {
@@ -56,73 +65,106 @@
}
@Override
- public synchronized void init(@NonNull ProcessingEnvironment processingEnvironment) {
- super.init(processingEnvironment);
- mMessager = processingEnvironment.getMessager();
+ protected Iterable<? extends Step> steps() {
+ return ImmutableList.of(new AppSearchCompileStep(processingEnv));
}
- @Override
- public boolean process(
- @NonNull Set<? extends TypeElement> set,
- @NonNull RoundEnvironment roundEnvironment) {
- try {
- tryProcess(set, roundEnvironment);
- } catch (ProcessingException e) {
- e.printDiagnostic(mMessager);
+ private static final class AppSearchCompileStep implements Step {
+ private final ProcessingEnvironment mProcessingEnv;
+ private final Messager mMessager;
+
+ AppSearchCompileStep(ProcessingEnvironment processingEnv) {
+ mProcessingEnv = processingEnv;
+ mMessager = processingEnv.getMessager();
}
- // True means we claimed the annotations. This is true regardless of whether they were
- // used correctly.
- return true;
- }
- private void tryProcess(
- @NonNull Set<? extends TypeElement> set,
- @NonNull RoundEnvironment roundEnvironment) throws ProcessingException {
- if (set.isEmpty()) return;
+ @Override
+ public ImmutableSet<String> annotations() {
+ return ImmutableSet.of(IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS);
+ }
- // Find the TypeElement corresponding to the @AppSearchDocument annotation. We can't use the
- // annotation class directly because the appsearch project compiles only on Android, but
- // this annotation processor runs on the host.
- TypeElement appSearchDocument =
- findAnnotation(set, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ @Override
+ public ImmutableSet<Element> process(
+ ImmutableSetMultimap<String, Element> elementsByAnnotation) {
+ Set<TypeElement> documentElements =
+ typesIn(elementsByAnnotation.get(
+ IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS));
+ for (TypeElement document : documentElements) {
+ try {
+ processDocument(document);
+ } catch (MissingTypeException e) {
+ // Save it for next round to wait for the AutoValue annotation processor to
+ // be run first.
+ return ImmutableSet.of(e.getTypeName());
+ } catch (ProcessingException e) {
+ // Prints error message.
+ e.printDiagnostic(mMessager);
+ }
+ }
+ // No elements will be passed to next round of processing.
+ return ImmutableSet.of();
+ }
- for (Element element : roundEnvironment.getElementsAnnotatedWith(appSearchDocument)) {
+ private void processDocument(@NonNull TypeElement element)
+ throws ProcessingException, MissingTypeException {
if (element.getKind() != ElementKind.CLASS) {
throw new ProcessingException(
- "@AppSearchDocument annotation on something other than a class", element);
+ "@Document annotation on something other than a class", element);
}
- processAppSearchDocument((TypeElement) element);
- }
- }
- private void processAppSearchDocument(@NonNull TypeElement element) throws ProcessingException {
- AppSearchDocumentModel model = AppSearchDocumentModel.create(processingEnv, element);
- CodeGenerator generator = CodeGenerator.generate(processingEnv, model);
- String outputDir = processingEnv.getOptions().get(OUTPUT_DIR_OPTION);
- try {
- if (outputDir == null || outputDir.isEmpty()) {
- generator.writeToFiler();
+ DocumentModel model;
+ if (element.getAnnotation(AutoValue.class) != null) {
+ // Document class is annotated as AutoValue class. For processing the AutoValue
+ // class, we also need the generated class from AutoValue annotation processor.
+ TypeElement generatedElement =
+ mProcessingEnv.getElementUtils().getTypeElement(
+ getAutoValueGeneratedClassName(element));
+ if (generatedElement == null) {
+ // Generated class is not found.
+ throw new MissingTypeException(element);
+ } else {
+ model = DocumentModel.createAutoValueModel(mProcessingEnv, element,
+ generatedElement);
+ }
} else {
- mMessager.printMessage(
- Diagnostic.Kind.NOTE,
- "Writing output to \"" + outputDir
- + "\" due to the presence of -A" + OUTPUT_DIR_OPTION);
- generator.writeToFolder(new File(outputDir));
+ // Non-AutoValue AppSearch Document class.
+ model = DocumentModel.createPojoModel(mProcessingEnv, element);
}
- } catch (IOException e) {
- ProcessingException pe =
- new ProcessingException("Failed to write output", model.getClassElement());
- pe.initCause(e);
- throw pe;
+ CodeGenerator generator = CodeGenerator.generate(mProcessingEnv, model);
+ String outputDir = mProcessingEnv.getOptions().get(OUTPUT_DIR_OPTION);
+ try {
+ if (outputDir == null || outputDir.isEmpty()) {
+ generator.writeToFiler();
+ } else {
+ mMessager.printMessage(
+ Kind.NOTE,
+ "Writing output to \"" + outputDir
+ + "\" due to the presence of -A" + OUTPUT_DIR_OPTION);
+ generator.writeToFolder(new File(outputDir));
+ }
+ } catch (IOException e) {
+ ProcessingException pe =
+ new ProcessingException("Failed to write output", model.getClassElement());
+ pe.initCause(e);
+ throw pe;
+ }
}
- }
- private TypeElement findAnnotation(Set<? extends TypeElement> set, String name) {
- for (TypeElement typeElement : set) {
- if (typeElement.getQualifiedName().contentEquals(name)) {
- return typeElement;
+ /**
+ * Gets the generated class name of an AutoValue annotated class.
+ *
+ * <p>This is the same naming strategy used by AutoValue's processor.
+ */
+ private String getAutoValueGeneratedClassName(TypeElement element) {
+ TypeElement type = element;
+ String name = type.getSimpleName().toString();
+ while (type.getEnclosingElement() instanceof TypeElement) {
+ type = (TypeElement) type.getEnclosingElement();
+ name = type.getSimpleName().toString() + "_" + name;
}
+ String pkg = MoreElements.getPackage(type).getQualifiedName().toString();
+ String dot = pkg.isEmpty() ? "" : ".";
+ return pkg + dot + "AutoValue_" + name;
}
- return null;
}
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/AppSearchDocumentModel.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/AppSearchDocumentModel.java
deleted file mode 100644
index 76578db..0000000
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/AppSearchDocumentModel.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.appsearch.compiler;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-
-/**
- * Processes AppSearchDocument annotations.
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class AppSearchDocumentModel {
-
- /** Enumeration of fields that must be handled specially (i.e. are not properties) */
- enum SpecialField { URI, NAMESPACE, CREATION_TIMESTAMP_MILLIS, TTL_MILLIS, SCORE }
- /** Determines how the annotation processor has decided to read the value of a field. */
- enum ReadKind { FIELD, GETTER }
- /** Determines how the annotation processor has decided to write the value of a field. */
- enum WriteKind { FIELD, SETTER, CONSTRUCTOR }
-
- private final IntrospectionHelper mIntrospectionHelper;
- private final TypeElement mClass;
- private final AnnotationMirror mAppSearchDocumentAnnotation;
- private final Set<ExecutableElement> mConstructors = new LinkedHashSet<>();
- private final Set<ExecutableElement> mMethods = new LinkedHashSet<>();
- private final Map<String, VariableElement> mAllAppSearchFields = new LinkedHashMap<>();
- private final Map<String, VariableElement> mPropertyFields = new LinkedHashMap<>();
- private final Map<SpecialField, String> mSpecialFieldNames = new EnumMap<>(SpecialField.class);
- private final Map<VariableElement, ReadKind> mReadKinds = new HashMap<>();
- private final Map<VariableElement, WriteKind> mWriteKinds = new HashMap<>();
- private final Map<VariableElement, ProcessingException> mWriteWhyConstructor = new HashMap<>();
- private List<String> mChosenConstructorParams = null;
-
- private AppSearchDocumentModel(
- @NonNull ProcessingEnvironment env,
- @NonNull TypeElement clazz)
- throws ProcessingException {
- mIntrospectionHelper = new IntrospectionHelper(env);
- mClass = clazz;
- if (mClass.getModifiers().contains(Modifier.PRIVATE)) {
- throw new ProcessingException("@AppSearchDocument annotated class is private", mClass);
- }
-
- mAppSearchDocumentAnnotation = mIntrospectionHelper.getAnnotation(
- mClass, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
-
- // Scan methods and constructors. AppSearch doesn't define any annotations that apply to
- // these, but we will need this info when processing fields to make sure the fields can
- // be get and set.
- for (Element child : mClass.getEnclosedElements()) {
- if (child.getKind() == ElementKind.CONSTRUCTOR) {
- mConstructors.add((ExecutableElement) child);
- } else if (child.getKind() == ElementKind.METHOD) {
- mMethods.add((ExecutableElement) child);
- }
- }
-
- scanFields();
- scanConstructors();
- }
-
- @NonNull
- public TypeElement getClassElement() {
- return mClass;
- }
-
- @NonNull
- public String getSchemaName() {
- Map<String, Object> params =
- mIntrospectionHelper.getAnnotationParams(mAppSearchDocumentAnnotation);
- String name = params.get("name").toString();
- if (name.isEmpty()) {
- return mClass.getSimpleName().toString();
- }
- return name;
- }
-
- @NonNull
- public Map<String, VariableElement> getAllFields() {
- return Collections.unmodifiableMap(mAllAppSearchFields);
- }
-
- @NonNull
- public Map<String, VariableElement> getPropertyFields() {
- return Collections.unmodifiableMap(mPropertyFields);
- }
-
- @Nullable
- public String getSpecialFieldName(SpecialField field) {
- return mSpecialFieldNames.get(field);
- }
-
- @Nullable
- public ReadKind getFieldReadKind(String fieldName) {
- VariableElement element = mAllAppSearchFields.get(fieldName);
- return mReadKinds.get(element);
- }
-
- @Nullable
- public WriteKind getFieldWriteKind(String fieldName) {
- VariableElement element = mAllAppSearchFields.get(fieldName);
- return mWriteKinds.get(element);
- }
-
- /**
- * Finds the AppSearch name for the given property.
- *
- * <p>This is usually the name of the field in Java, but may be changed if the developer
- * specifies a different 'name' parameter in the annotation.
- */
- @NonNull
- public String getPropertyName(@NonNull VariableElement property) throws ProcessingException {
- AnnotationMirror annotation =
- mIntrospectionHelper.getAnnotation(property, IntrospectionHelper.PROPERTY_CLASS);
- Map<String, Object> params = mIntrospectionHelper.getAnnotationParams(annotation);
- String propertyName = params.get("name").toString();
- if (propertyName.isEmpty()) {
- propertyName = property.getSimpleName().toString();
- }
- return propertyName;
- }
-
- @NonNull
- public List<String> getChosenConstructorParams() {
- return Collections.unmodifiableList(mChosenConstructorParams);
- }
-
- private void scanFields() throws ProcessingException {
- Element uriField = null;
- Element namespaceField = null;
- Element creationTimestampField = null;
- Element ttlField = null;
- Element scoreField = null;
- for (Element childElement : mClass.getEnclosedElements()) {
- if (!childElement.getKind().isField()) continue;
- VariableElement child = (VariableElement) childElement;
- String fieldName = child.getSimpleName().toString();
- for (AnnotationMirror annotation : child.getAnnotationMirrors()) {
- String annotationFq = annotation.getAnnotationType().toString();
- boolean isAppSearchField = true;
- if (IntrospectionHelper.URI_CLASS.equals(annotationFq)) {
- if (uriField != null) {
- throw new ProcessingException(
- "Class contains multiple fields annotated @Uri", child);
- }
- uriField = child;
- mSpecialFieldNames.put(SpecialField.URI, fieldName);
-
- } else if (IntrospectionHelper.NAMESPACE_CLASS.equals(annotationFq)) {
- if (namespaceField != null) {
- throw new ProcessingException(
- "Class contains multiple fields annotated @Namespace", child);
- }
- namespaceField = child;
- mSpecialFieldNames.put(SpecialField.NAMESPACE, fieldName);
-
- } else if (
- IntrospectionHelper.CREATION_TIMESTAMP_MILLIS_CLASS.equals(annotationFq)) {
- if (creationTimestampField != null) {
- throw new ProcessingException(
- "Class contains multiple fields annotated @CreationTimestampMillis",
- child);
- }
- creationTimestampField = child;
- mSpecialFieldNames.put(SpecialField.CREATION_TIMESTAMP_MILLIS, fieldName);
-
- } else if (IntrospectionHelper.TTL_MILLIS_CLASS.equals(annotationFq)) {
- if (ttlField != null) {
- throw new ProcessingException(
- "Class contains multiple fields annotated @TtlMillis", child);
- }
- ttlField = child;
- mSpecialFieldNames.put(SpecialField.TTL_MILLIS, fieldName);
-
- } else if (IntrospectionHelper.SCORE_CLASS.equals(annotationFq)) {
- if (scoreField != null) {
- throw new ProcessingException(
- "Class contains multiple fields annotated @Score", child);
- }
- scoreField = child;
- mSpecialFieldNames.put(SpecialField.SCORE, fieldName);
-
- } else if (IntrospectionHelper.PROPERTY_CLASS.equals(annotationFq)) {
- mPropertyFields.put(fieldName, child);
-
- } else {
- isAppSearchField = false;
- }
-
- if (isAppSearchField) {
- mAllAppSearchFields.put(fieldName, child);
- }
- }
- }
-
- // Every document must always have a URI
- if (uriField == null) {
- throw new ProcessingException(
- "All @AppSearchDocument classes must have exactly one field annotated with "
- + "@Uri", mClass);
- }
-
- for (VariableElement appSearchField : mAllAppSearchFields.values()) {
- chooseAccessKinds(appSearchField);
- }
- }
-
- /**
- * Chooses how to access the given field for read and write, subject to our requirements for all
- * AppSearch-managed class fields:
- *
- * <p>For read: visible field, or visible getter
- * <p>For write: visible mutable field, or visible setter, or visible constructor accepting at
- * minimum all fields that aren't mutable and have no visible setter.
- *
- * @throws ProcessingException if no access type is possible for the given field
- */
- private void chooseAccessKinds(@NonNull VariableElement field)
- throws ProcessingException {
- // Choose get access
- String fieldName = field.getSimpleName().toString();
- Set<Modifier> modifiers = field.getModifiers();
- if (modifiers.contains(Modifier.PRIVATE)) {
- String getterName = getAccessorName(fieldName, /*get=*/ true);
- findGetter(field, getterName);
- mReadKinds.put(field, ReadKind.GETTER);
- } else {
- mReadKinds.put(field, ReadKind.FIELD);
- }
-
- // Choose set access
- if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.FINAL)
- || modifiers.contains(Modifier.STATIC)) {
- // Try to find a setter. If we can't find one, mark the WriteKind as CONSTRUCTOR. We
- // don't know if this is true yet, the constructors will be inspected in a subsequent
- // pass.
- String setterName = getAccessorName(fieldName, /*get=*/ false);
- try {
- findSetter(field, setterName);
- mWriteKinds.put(field, WriteKind.SETTER);
- } catch (ProcessingException e) {
- // We'll look for a constructor, so we may still be able to set this field,
- // but it's more likely the developer configured the setter incorrectly. Keep
- // the exception around to include it in the report if no constructor is found.
- mWriteWhyConstructor.put(field, e);
- mWriteKinds.put(field, WriteKind.CONSTRUCTOR);
- }
- } else {
- mWriteKinds.put(field, WriteKind.FIELD);
- }
- }
-
- private void findGetter(@NonNull VariableElement field, @NonNull String getterName)
- throws ProcessingException {
- ProcessingException e = new ProcessingException(
- "Field cannot be read: it is private and we failed to find a suitable getter named "
- + "\"" + getterName + "\"",
- field);
-
- for (ExecutableElement method : mMethods) {
- if (!method.getSimpleName().toString().equals(getterName)) {
- continue;
- }
- if (method.getModifiers().contains(Modifier.PRIVATE)) {
- e.addWarning(new ProcessingException(
- "Getter cannot be used: private visibility", method));
- continue;
- }
- if (!method.getParameters().isEmpty()) {
- e.addWarning(new ProcessingException(
- "Getter cannot be used: should take no parameters", method));
- continue;
- }
- // Found one!
- return;
- }
-
- // Broke out of the loop without finding anything.
- throw e;
- }
-
- private void findSetter(@NonNull VariableElement field, @NonNull String setterName)
- throws ProcessingException {
- // We can't report setter failure until we've searched the constructors, so this message is
- // anticipatory and should be buffered by the caller.
- ProcessingException e = new ProcessingException(
- "Field cannot be written directly or via setter because it is private, final, or "
- + "static, and we failed to find a suitable setter named \""
- + setterName + "\". Trying to find a suitable constructor.",
- field);
-
- for (ExecutableElement method : mMethods) {
- if (!method.getSimpleName().toString().equals(setterName)) {
- continue;
- }
- if (method.getModifiers().contains(Modifier.PRIVATE)) {
- e.addWarning(new ProcessingException(
- "Setter cannot be used: private visibility", method));
- continue;
- }
- if (method.getParameters().size() != 1) {
- e.addWarning(new ProcessingException(
- "Setter cannot be used: takes " + method.getParameters().size()
- + " parameters instead of 1",
- method));
- continue;
- }
- // Found one!
- return;
- }
-
- // Broke out of the loop without finding anything.
- throw e;
- }
-
- private void scanConstructors() throws ProcessingException {
- // Maps name to Element
- Map<String, VariableElement> constructorWrittenFields = new LinkedHashMap<>();
- for (Map.Entry<VariableElement, WriteKind> it : mWriteKinds.entrySet()) {
- if (it.getValue() == WriteKind.CONSTRUCTOR) {
- String name = it.getKey().getSimpleName().toString();
- constructorWrittenFields.put(name, it.getKey());
- }
- }
-
- Map<ExecutableElement, String> whyNotConstructor = new HashMap<>();
- constructorSearch: for (ExecutableElement constructor : mConstructors) {
- if (constructor.getModifiers().contains(Modifier.PRIVATE)) {
- whyNotConstructor.put(constructor, "Constructor is private");
- continue constructorSearch;
- }
- List<String> constructorParamFields = new ArrayList<>();
- Set<String> remainingFields = new HashSet<>(constructorWrittenFields.keySet());
- for (VariableElement parameter : constructor.getParameters()) {
- String name = parameter.getSimpleName().toString();
- if (!mAllAppSearchFields.containsKey(name)) {
- whyNotConstructor.put(
- constructor,
- "Parameter \"" + name + "\" is not an AppSearch parameter; don't know "
- + "how to supply it.");
- continue constructorSearch;
- }
- remainingFields.remove(name);
- constructorParamFields.add(name);
- }
- if (!remainingFields.isEmpty()) {
- whyNotConstructor.put(
- constructor,
- "This constructor doesn't have parameters for the following fields: "
- + remainingFields);
- continue constructorSearch;
- }
- // Found one!
- mChosenConstructorParams = constructorParamFields;
- return;
- }
-
- // If we got here, we couldn't find any constructors.
- ProcessingException e =
- new ProcessingException(
- "Failed to find any suitable constructors to build this class. See "
- + "warnings for details.", mClass);
-
- // Inform the developer why we started looking for constructors in the first place
- for (VariableElement field : constructorWrittenFields.values()) {
- ProcessingException warning = mWriteWhyConstructor.get(field);
- if (warning != null) {
- e.addWarning(warning);
- }
- }
-
- // Inform the developer about why each constructor we considered was rejected
- for (Map.Entry<ExecutableElement, String> it : whyNotConstructor.entrySet()) {
- ProcessingException warning = new ProcessingException(
- "Cannot use this constructor to construct the class: " + it.getValue(),
- it.getKey());
- e.addWarning(warning);
- }
-
- throw e;
- }
-
- public String getAccessorName(String fieldName, boolean get) {
- char fieldNameFirst = fieldName.charAt(0);
- StringBuilder methodNameBuilder = new StringBuilder();
- methodNameBuilder.append(Character.toUpperCase(fieldNameFirst));
- if (fieldName.length() > 1) {
- methodNameBuilder.append(fieldName.subSequence(1, fieldName.length()));
- }
- if (get) {
- return "get" + methodNameBuilder;
- } else {
- return "set" + methodNameBuilder;
- }
- }
-
- /**
- * Tries to create an {@link AppSearchDocumentModel} from the given {@link Element}.
- *
- * @throws ProcessingException if the @{@code AppSearchDocument}-annotated class is invalid.
- */
- public static AppSearchDocumentModel create(
- @NonNull ProcessingEnvironment env, @NonNull TypeElement clazz)
- throws ProcessingException {
- return new AppSearchDocumentModel(env, clazz);
- }
-}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
index 9ee924a..f74e2bb 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
@@ -17,8 +17,9 @@
package androidx.appsearch.compiler;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
+import com.google.auto.common.GeneratedAnnotationSpecs;
+import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
@@ -32,27 +33,24 @@
/**
* Generates java code for an {@link androidx.appsearch.app.AppSearchSchema} and a translator
- * between the data class and a {@link androidx.appsearch.app.GenericDocument}.
+ * between the document class and a {@link androidx.appsearch.app.GenericDocument}.
*/
class CodeGenerator {
- @VisibleForTesting
- static final String GEN_CLASS_PREFIX = "$$__AppSearch__";
-
private final ProcessingEnvironment mEnv;
private final IntrospectionHelper mHelper;
- private final AppSearchDocumentModel mModel;
+ private final DocumentModel mModel;
private final String mOutputPackage;
private final TypeSpec mOutputClass;
public static CodeGenerator generate(
- @NonNull ProcessingEnvironment env, @NonNull AppSearchDocumentModel model)
+ @NonNull ProcessingEnvironment env, @NonNull DocumentModel model)
throws ProcessingException {
return new CodeGenerator(env, model);
}
private CodeGenerator(
- @NonNull ProcessingEnvironment env, @NonNull AppSearchDocumentModel model)
+ @NonNull ProcessingEnvironment env, @NonNull DocumentModel model)
throws ProcessingException {
// Prepare constants needed for processing
mEnv = env;
@@ -74,27 +72,23 @@
/**
* Creates factory class for any class annotated with
- * {@link androidx.appsearch.annotation.AppSearchDocument}
+ * {@link androidx.appsearch.annotation.Document}
* <p>Class Example 1:
- * For a class Foo annotated with @AppSearchDocument, we will generated a
+ * For a class Foo annotated with @Document, we will generated a
* $$__AppSearch__Foo.class under the output package.
* <p>Class Example 2:
- * For an inner class Foo.Bar annotated with @AppSearchDocument, we will generated a
+ * For an inner class Foo.Bar annotated with @Document, we will generated a
* $$__AppSearch__Foo$$__Bar.class under the output package.
*/
private TypeSpec createClass() throws ProcessingException {
// Gets the full name of target class.
String qualifiedName = mModel.getClassElement().getQualifiedName().toString();
- String packageName = mOutputPackage + ".";
-
- // Creates the name of output class. $$__AppSearch__Foo for Foo, $$__AppSearch__Foo$$__Bar
- // for inner class Foo.Bar.
- String genClassName = GEN_CLASS_PREFIX
- + qualifiedName.substring(packageName.length()).replace(".", "$$__");
+ String className = qualifiedName.substring(mOutputPackage.length() + 1);
+ ClassName genClassName = mHelper.getDocumentClassFactoryForClass(mOutputPackage, className);
TypeName genClassType = TypeName.get(mModel.getClassElement().asType());
TypeName factoryType = ParameterizedTypeName.get(
- mHelper.getAppSearchClass("DataClassFactory"),
+ mHelper.getAppSearchClass("DocumentClassFactory"),
genClassType);
TypeSpec.Builder genClass = TypeSpec
@@ -103,6 +97,13 @@
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(factoryType);
+ // Add the @Generated annotation to avoid static analysis running on these files
+ GeneratedAnnotationSpecs.generatedAnnotationSpec(
+ mEnv.getElementUtils(),
+ mEnv.getSourceVersion(),
+ AppSearchCompiler.class
+ ).ifPresent(genClass::addAnnotation);
+
SchemaCodeGenerator.generate(mEnv, mModel, genClass);
ToGenericDocumentCodeGenerator.generate(mEnv, mModel, genClass);
FromGenericDocumentCodeGenerator.generate(mEnv, mModel, genClass);
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
new file mode 100644
index 0000000..a93a6f1
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
@@ -0,0 +1,700 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.compiler;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+import static androidx.appsearch.compiler.IntrospectionHelper.getDocumentAnnotation;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.compiler.IntrospectionHelper.PropertyClass;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.ElementFilter;
+
+/**
+ * Processes @Document annotations.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class DocumentModel {
+
+ /** Enumeration of fields that must be handled specially (i.e. are not properties) */
+ enum SpecialField {ID, NAMESPACE, CREATION_TIMESTAMP_MILLIS, TTL_MILLIS, SCORE}
+
+ /** Determines how the annotation processor has decided to read the value of a field. */
+ enum ReadKind {FIELD, GETTER}
+
+ /** Determines how the annotation processor has decided to write the value of a field. */
+ enum WriteKind {FIELD, SETTER, CREATION_METHOD}
+
+ private final IntrospectionHelper mHelper;
+ private final TypeElement mClass;
+ private final AnnotationMirror mDocumentAnnotation;
+ // Warning: if you change this to a HashSet, we may choose different getters or setters from
+ // run to run, causing the generated code to bounce.
+ private final Set<ExecutableElement> mAllMethods = new LinkedHashSet<>();
+ private final boolean mIsAutoValueDocument;
+ // Key: Name of the field which is accessed through the getter method.
+ // Value: ExecutableElement of the getter method.
+ private final Map<String, ExecutableElement> mGetterMethods = new HashMap<>();
+ // Key: Name of the field whose value is set through the setter method.
+ // Value: ExecutableElement of the setter method.
+ private final Map<String, ExecutableElement> mSetterMethods = new HashMap<>();
+ // Warning: if you change this to a HashMap, we may assign fields in a different order from run
+ // to run, causing the generated code to bounce.
+ private final Map<String, VariableElement> mAllAppSearchFields = new LinkedHashMap<>();
+ // Warning: if you change this to a HashMap, we may assign fields in a different order from run
+ // to run, causing the generated code to bounce.
+ private final Map<String, VariableElement> mPropertyFields = new LinkedHashMap<>();
+ private final Map<SpecialField, String> mSpecialFieldNames = new EnumMap<>(SpecialField.class);
+ private final Map<VariableElement, ReadKind> mReadKinds = new HashMap<>();
+ private final Map<VariableElement, WriteKind> mWriteKinds = new HashMap<>();
+ // Contains the reason why that field couldn't be written either by field or by setter.
+ private final Map<VariableElement, ProcessingException> mWriteWhyCreationMethod =
+ new HashMap<>();
+ private ExecutableElement mChosenCreationMethod = null;
+ private List<String> mChosenCreationMethodParams = null;
+
+ private DocumentModel(
+ @NonNull ProcessingEnvironment env,
+ @NonNull TypeElement clazz,
+ @Nullable TypeElement generatedAutoValueElement)
+ throws ProcessingException {
+ if (clazz.getModifiers().contains(Modifier.PRIVATE)) {
+ throw new ProcessingException("@Document annotated class is private", clazz);
+ }
+
+ mHelper = new IntrospectionHelper(env);
+ mClass = clazz;
+ mDocumentAnnotation = getDocumentAnnotation(mClass);
+
+ if (generatedAutoValueElement != null) {
+ mIsAutoValueDocument = true;
+ // Scan factory methods from AutoValue class.
+ Set<ExecutableElement> creationMethods = new LinkedHashSet<>();
+ for (Element child : ElementFilter.methodsIn(mClass.getEnclosedElements())) {
+ ExecutableElement method = (ExecutableElement) child;
+ if (isFactoryMethod(method)) {
+ creationMethods.add(method);
+ }
+ }
+ mAllMethods.addAll(
+ ElementFilter.methodsIn(generatedAutoValueElement.getEnclosedElements()));
+
+ scanFields(generatedAutoValueElement);
+ scanCreationMethods(creationMethods);
+ } else {
+ mIsAutoValueDocument = false;
+ // Scan methods and constructors. We will need this info when processing fields to
+ // make sure the fields can be get and set.
+ Set<ExecutableElement> creationMethods = new LinkedHashSet<>();
+ for (Element child : mClass.getEnclosedElements()) {
+ if (child.getKind() == ElementKind.CONSTRUCTOR) {
+ creationMethods.add((ExecutableElement) child);
+ } else if (child.getKind() == ElementKind.METHOD) {
+ ExecutableElement method = (ExecutableElement) child;
+ mAllMethods.add(method);
+ if (isFactoryMethod(method)) {
+ creationMethods.add(method);
+ }
+ }
+ }
+
+ scanFields(mClass);
+ scanCreationMethods(creationMethods);
+ }
+ }
+
+ /**
+ * Tries to create an {@link DocumentModel} from the given {@link Element}.
+ *
+ * @throws ProcessingException if the @{@code Document}-annotated class is invalid.
+ */
+ public static DocumentModel createPojoModel(
+ @NonNull ProcessingEnvironment env, @NonNull TypeElement clazz)
+ throws ProcessingException {
+ return new DocumentModel(env, clazz, null);
+ }
+
+ /**
+ * Tries to create an {@link DocumentModel} from the given AutoValue {@link Element} and
+ * corresponding generated class.
+ *
+ * @throws ProcessingException if the @{@code Document}-annotated class is invalid.
+ */
+ public static DocumentModel createAutoValueModel(
+ @NonNull ProcessingEnvironment env, @NonNull TypeElement clazz,
+ @NonNull TypeElement generatedAutoValueElement)
+ throws ProcessingException {
+ return new DocumentModel(env, clazz, generatedAutoValueElement);
+ }
+
+ @NonNull
+ public TypeElement getClassElement() {
+ return mClass;
+ }
+
+ @NonNull
+ public String getSchemaName() {
+ Map<String, Object> params =
+ mHelper.getAnnotationParams(mDocumentAnnotation);
+ String name = params.get("name").toString();
+ if (name.isEmpty()) {
+ return mClass.getSimpleName().toString();
+ }
+ return name;
+ }
+
+ @NonNull
+ public Map<String, VariableElement> getAllFields() {
+ return Collections.unmodifiableMap(mAllAppSearchFields);
+ }
+
+ @NonNull
+ public Map<String, VariableElement> getPropertyFields() {
+ return Collections.unmodifiableMap(mPropertyFields);
+ }
+
+ @Nullable
+ public String getSpecialFieldName(SpecialField field) {
+ return mSpecialFieldNames.get(field);
+ }
+
+ @Nullable
+ public ReadKind getFieldReadKind(String fieldName) {
+ VariableElement element = mAllAppSearchFields.get(fieldName);
+ return mReadKinds.get(element);
+ }
+
+ @Nullable
+ public WriteKind getFieldWriteKind(String fieldName) {
+ VariableElement element = mAllAppSearchFields.get(fieldName);
+ return mWriteKinds.get(element);
+ }
+
+ @Nullable
+ public ExecutableElement getGetterForField(String fieldName) {
+ return mGetterMethods.get(fieldName);
+ }
+
+ @Nullable
+ public ExecutableElement getSetterForField(String fieldName) {
+ return mSetterMethods.get(fieldName);
+ }
+
+ /**
+ * Finds the AppSearch name for the given property.
+ *
+ * <p>This is usually the name of the field in Java, but may be changed if the developer
+ * specifies a different 'name' parameter in the annotation.
+ */
+ @NonNull
+ public String getPropertyName(@NonNull VariableElement property) throws ProcessingException {
+ AnnotationMirror annotation = getPropertyAnnotation(property);
+ Map<String, Object> params = mHelper.getAnnotationParams(annotation);
+ String propertyName = params.get("name").toString();
+ if (propertyName.isEmpty()) {
+ propertyName = getNormalizedFieldName(property.getSimpleName().toString());
+ }
+ return propertyName;
+ }
+
+ /**
+ * Returns the first found AppSearch property annotation element from the input element's
+ * annotations.
+ *
+ * @throws ProcessingException if no AppSearch property annotation is found.
+ */
+ @NonNull
+ public AnnotationMirror getPropertyAnnotation(@NonNull Element element)
+ throws ProcessingException {
+ Objects.requireNonNull(element);
+ if (mIsAutoValueDocument) {
+ element = getGetterForField(element.getSimpleName().toString());
+ }
+ Set<String> propertyClassPaths = new HashSet<>();
+ for (PropertyClass propertyClass : PropertyClass.values()) {
+ propertyClassPaths.add(propertyClass.getClassFullPath());
+ }
+ for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
+ String annotationFq = annotation.getAnnotationType().toString();
+ if (propertyClassPaths.contains(annotationFq)) {
+ return annotation;
+ }
+ }
+ throw new ProcessingException("Missing AppSearch property annotation.", element);
+ }
+
+ @NonNull
+ public ExecutableElement getChosenCreationMethod() {
+ return mChosenCreationMethod;
+ }
+
+ @NonNull
+ public List<String> getChosenCreationMethodParams() {
+ return Collections.unmodifiableList(mChosenCreationMethodParams);
+ }
+
+ private boolean isFactoryMethod(ExecutableElement method) {
+ Set<Modifier> methodModifiers = method.getModifiers();
+ return methodModifiers.contains(Modifier.STATIC)
+ && !methodModifiers.contains(Modifier.PRIVATE)
+ && method.getReturnType() == mClass.asType();
+ }
+
+ private void scanFields(TypeElement element) throws ProcessingException {
+ Element namespaceField = null;
+ Element idField = null;
+ Element creationTimestampField = null;
+ Element ttlField = null;
+ Element scoreField = null;
+ List<? extends Element> enclosedElements = element.getEnclosedElements();
+ for (int i = 0; i < enclosedElements.size(); i++) {
+ Element childElement = enclosedElements.get(i);
+ if (mIsAutoValueDocument && childElement.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ String fieldName = childElement.getSimpleName().toString();
+ for (AnnotationMirror annotation : childElement.getAnnotationMirrors()) {
+ String annotationFq = annotation.getAnnotationType().toString();
+ if (!annotationFq.startsWith(DOCUMENT_ANNOTATION_CLASS)) {
+ continue;
+ }
+ VariableElement child;
+ if (mIsAutoValueDocument) {
+ child = findFieldForFunctionWithSameName(enclosedElements, childElement);
+ } else {
+ if (childElement.getKind() == ElementKind.METHOD) {
+ throw new ProcessingException(
+ "AppSearch annotation is not applicable to methods for "
+ + "Non-AutoValue class",
+ childElement);
+ } else {
+ child = (VariableElement) childElement;
+ }
+ }
+ switch (annotationFq) {
+ case IntrospectionHelper.ID_CLASS:
+ if (idField != null) {
+ throw new ProcessingException(
+ "Class contains multiple fields annotated @Id", child);
+ }
+ idField = child;
+ mSpecialFieldNames.put(SpecialField.ID, fieldName);
+ break;
+ case IntrospectionHelper.NAMESPACE_CLASS:
+ if (namespaceField != null) {
+ throw new ProcessingException(
+ "Class contains multiple fields annotated @Namespace",
+ child);
+ }
+ namespaceField = child;
+ mSpecialFieldNames.put(SpecialField.NAMESPACE, fieldName);
+ break;
+ case IntrospectionHelper.CREATION_TIMESTAMP_MILLIS_CLASS:
+ if (creationTimestampField != null) {
+ throw new ProcessingException(
+ "Class contains multiple fields annotated "
+ + "@CreationTimestampMillis",
+ child);
+ }
+ creationTimestampField = child;
+ mSpecialFieldNames.put(SpecialField.CREATION_TIMESTAMP_MILLIS, fieldName);
+ break;
+ case IntrospectionHelper.TTL_MILLIS_CLASS:
+ if (ttlField != null) {
+ throw new ProcessingException(
+ "Class contains multiple fields annotated @TtlMillis",
+ child);
+ }
+ ttlField = child;
+ mSpecialFieldNames.put(SpecialField.TTL_MILLIS, fieldName);
+ break;
+ case IntrospectionHelper.SCORE_CLASS:
+ if (scoreField != null) {
+ throw new ProcessingException(
+ "Class contains multiple fields annotated @Score", child);
+ }
+ scoreField = child;
+ mSpecialFieldNames.put(SpecialField.SCORE, fieldName);
+ break;
+ default:
+ PropertyClass propertyClass = getPropertyClass(annotationFq);
+ if (propertyClass != null) {
+ checkFieldTypeForPropertyAnnotation(child, propertyClass);
+ mPropertyFields.put(fieldName, child);
+ }
+ }
+ mAllAppSearchFields.put(fieldName, child);
+ }
+ }
+
+ // Every document must always have a namespace
+ if (namespaceField == null) {
+ throw new ProcessingException(
+ "All @Document classes must have exactly one field annotated with @Namespace",
+ mClass);
+ }
+
+ // Every document must always have an ID
+ if (idField == null) {
+ throw new ProcessingException(
+ "All @Document classes must have exactly one field annotated with @Id",
+ mClass);
+ }
+
+ for (VariableElement appSearchField : mAllAppSearchFields.values()) {
+ chooseAccessKinds(appSearchField);
+ }
+ }
+
+ @NonNull
+ private VariableElement findFieldForFunctionWithSameName(
+ @NonNull List<? extends Element> elements,
+ @NonNull Element functionElement) throws ProcessingException {
+ String fieldName = functionElement.getSimpleName().toString();
+ for (VariableElement field : ElementFilter.fieldsIn(elements)) {
+ if (fieldName.equals(field.getSimpleName().toString())) {
+ return field;
+ }
+ }
+ throw new ProcessingException(
+ "Cannot find the corresponding field for the annotated function",
+ functionElement);
+ }
+
+ /**
+ * Checks whether property's data type matches the {@code androidx.appsearch.annotation
+ * .Document} property annotation's requirement.
+ *
+ * @throws ProcessingException if data type doesn't match property annotation's requirement.
+ */
+ void checkFieldTypeForPropertyAnnotation(@NonNull VariableElement property,
+ PropertyClass propertyClass) throws ProcessingException {
+ switch (propertyClass) {
+ case BOOLEAN_PROPERTY_CLASS:
+ if (mHelper.isFieldOfExactType(property, mHelper.mBooleanBoxType,
+ mHelper.mBooleanPrimitiveType)) {
+ return;
+ }
+ break;
+ case BYTES_PROPERTY_CLASS:
+ if (mHelper.isFieldOfExactType(property, mHelper.mByteBoxType,
+ mHelper.mBytePrimitiveType, mHelper.mByteBoxArrayType,
+ mHelper.mBytePrimitiveArrayType)) {
+ return;
+ }
+ break;
+ case DOCUMENT_PROPERTY_CLASS:
+ if (mHelper.isFieldOfDocumentType(property)) {
+ return;
+ }
+ break;
+ case DOUBLE_PROPERTY_CLASS:
+ if (mHelper.isFieldOfExactType(property, mHelper.mDoubleBoxType,
+ mHelper.mDoublePrimitiveType, mHelper.mFloatBoxType,
+ mHelper.mFloatPrimitiveType)) {
+ return;
+ }
+ break;
+ case LONG_PROPERTY_CLASS:
+ if (mHelper.isFieldOfExactType(property, mHelper.mIntegerBoxType,
+ mHelper.mIntPrimitiveType, mHelper.mLongBoxType,
+ mHelper.mLongPrimitiveType)) {
+ return;
+ }
+ break;
+ case STRING_PROPERTY_CLASS:
+ if (mHelper.isFieldOfExactType(property, mHelper.mStringType)) {
+ return;
+ }
+ break;
+ default:
+ // do nothing
+ }
+ throw new ProcessingException(
+ "Property Annotation " + propertyClass.getClassFullPath() + " doesn't accept the "
+ + "data type of property field " + property.getSimpleName(), property);
+ }
+
+ /**
+ * Returns the {@link PropertyClass} with {@code annotationFq} as full class path, and {@code
+ * null} if failed to find such a {@link PropertyClass}.
+ */
+ @Nullable
+ private PropertyClass getPropertyClass(@Nullable String annotationFq) {
+ for (PropertyClass propertyClass : PropertyClass.values()) {
+ if (propertyClass.isPropertyClass(annotationFq)) {
+ return propertyClass;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Chooses how to access the given field for read and write, subject to our requirements for all
+ * AppSearch-managed class fields:
+ *
+ * <p>For read: visible field, or visible getter
+ *
+ * <p>For write: visible mutable field, or visible setter, or visible creation method
+ * accepting at minimum all fields that aren't mutable and have no visible setter.
+ *
+ * @throws ProcessingException if no access type is possible for the given field
+ */
+ private void chooseAccessKinds(@NonNull VariableElement field)
+ throws ProcessingException {
+ // Choose get access
+ String fieldName = field.getSimpleName().toString();
+ Set<Modifier> modifiers = field.getModifiers();
+ if (modifiers.contains(Modifier.PRIVATE)) {
+ findGetter(fieldName);
+ mReadKinds.put(field, ReadKind.GETTER);
+ } else {
+ mReadKinds.put(field, ReadKind.FIELD);
+ }
+
+ // Choose set access
+ if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.FINAL)
+ || modifiers.contains(Modifier.STATIC)) {
+ // Try to find a setter. If we can't find one, mark the WriteKind as {@code
+ // CREATION_METHOD}. We don't know if this is true yet, the creation methods will be
+ // inspected in a subsequent pass.
+ try {
+ findSetter(fieldName);
+ mWriteKinds.put(field, WriteKind.SETTER);
+ } catch (ProcessingException e) {
+ // We'll look for a creation method, so we may still be able to set this field,
+ // but it's more likely the developer configured the setter incorrectly. Keep
+ // the exception around to include it in the report if no creation method is found.
+ mWriteWhyCreationMethod.put(field, e);
+ mWriteKinds.put(field, WriteKind.CREATION_METHOD);
+ }
+ } else {
+ mWriteKinds.put(field, WriteKind.FIELD);
+ }
+ }
+
+ private void scanCreationMethods(Set<ExecutableElement> creationMethods)
+ throws ProcessingException {
+ // Maps field name to Element.
+ // If this is changed to a HashSet, we might report errors to the developer in a different
+ // order about why a field was written via creation method.
+ Map<String, VariableElement> creationMethodWrittenFields = new LinkedHashMap<>();
+ for (Map.Entry<VariableElement, WriteKind> it : mWriteKinds.entrySet()) {
+ if (it.getValue() == WriteKind.CREATION_METHOD) {
+ String name = it.getKey().getSimpleName().toString();
+ creationMethodWrittenFields.put(name, it.getKey());
+ }
+ }
+
+ // Maps normalized field name to real field name.
+ Map<String, String> normalizedToRawFieldName = new HashMap<>();
+ for (String fieldName : mAllAppSearchFields.keySet()) {
+ normalizedToRawFieldName.put(getNormalizedFieldName(fieldName), fieldName);
+ }
+
+ Map<ExecutableElement, String> whyNotCreationMethod = new HashMap<>();
+ creationMethodSearch:
+ for (ExecutableElement method : creationMethods) {
+ if (method.getModifiers().contains(Modifier.PRIVATE)) {
+ whyNotCreationMethod.put(method, "Creation method is private");
+ continue creationMethodSearch;
+ }
+ // The field name of each field that goes into the creation method, in the order they
+ // are declared in the creation method signature.
+ List<String> creationMethodParamFields = new ArrayList<>();
+ Set<String> remainingFields = new HashSet<>(creationMethodWrittenFields.keySet());
+ for (VariableElement parameter : method.getParameters()) {
+ String paramName = parameter.getSimpleName().toString();
+ String fieldName = normalizedToRawFieldName.get(paramName);
+ if (fieldName == null) {
+ whyNotCreationMethod.put(
+ method,
+ "Parameter \"" + paramName + "\" is not an AppSearch parameter; don't "
+ + "know how to supply it.");
+ continue creationMethodSearch;
+ }
+ remainingFields.remove(fieldName);
+ creationMethodParamFields.add(fieldName);
+ }
+ if (!remainingFields.isEmpty()) {
+ whyNotCreationMethod.put(
+ method,
+ "This method doesn't have parameters for the following fields: "
+ + remainingFields);
+ continue creationMethodSearch;
+ }
+ // Found one!
+ mChosenCreationMethod = method;
+ mChosenCreationMethodParams = creationMethodParamFields;
+ return;
+ }
+
+ // If we got here, we couldn't find any creation methods.
+ ProcessingException e =
+ new ProcessingException(
+ "Failed to find any suitable creation methods to build this class. See "
+ + "warnings for details.", mClass);
+
+ // Inform the developer why we started looking for creation methods in the first place.
+ for (VariableElement field : creationMethodWrittenFields.values()) {
+ ProcessingException warning = mWriteWhyCreationMethod.get(field);
+ if (warning != null) {
+ e.addWarning(warning);
+ }
+ }
+
+ // Inform the developer about why each creation method we considered was rejected.
+ for (Map.Entry<ExecutableElement, String> it : whyNotCreationMethod.entrySet()) {
+ ProcessingException warning = new ProcessingException(
+ "Cannot use this creation method to construct the class: " + it.getValue(),
+ it.getKey());
+ e.addWarning(warning);
+ }
+
+ throw e;
+ }
+
+ /** Finds getter function for a private field. */
+ private void findGetter(@NonNull String fieldName) throws ProcessingException {
+ ProcessingException e = new ProcessingException(
+ "Field cannot be read: it is private and we failed to find a suitable getter "
+ + "for field \"" + fieldName + "\"",
+ mAllAppSearchFields.get(fieldName));
+
+ for (ExecutableElement method : mAllMethods) {
+ String methodName = method.getSimpleName().toString();
+ String normalizedFieldName = getNormalizedFieldName(fieldName);
+ if (methodName.equals(normalizedFieldName)
+ || methodName.equals("get"
+ + normalizedFieldName.substring(0, 1).toUpperCase()
+ + normalizedFieldName.substring(1))) {
+ if (method.getModifiers().contains(Modifier.PRIVATE)) {
+ e.addWarning(new ProcessingException(
+ "Getter cannot be used: private visibility", method));
+ continue;
+ }
+ if (!method.getParameters().isEmpty()) {
+ e.addWarning(new ProcessingException(
+ "Getter cannot be used: should take no parameters", method));
+ continue;
+ }
+ // Found one!
+ mGetterMethods.put(fieldName, method);
+ return;
+ }
+ }
+
+ // Broke out of the loop without finding anything.
+ throw e;
+ }
+
+ /** Finds setter function for a private field. */
+ private void findSetter(@NonNull String fieldName) throws ProcessingException {
+ // We can't report setter failure until we've searched the creation methods, so this
+ // message is anticipatory and should be buffered by the caller.
+ ProcessingException e = new ProcessingException(
+ "Field cannot be written directly or via setter because it is private, final, or "
+ + "static, and we failed to find a suitable setter for field \""
+ + fieldName
+ + "\". Trying to find a suitable creation method.",
+ mAllAppSearchFields.get(fieldName));
+
+ for (ExecutableElement method : mAllMethods) {
+ String methodName = method.getSimpleName().toString();
+ String normalizedFieldName = getNormalizedFieldName(fieldName);
+ if (methodName.equals(normalizedFieldName)
+ || methodName.equals("set"
+ + normalizedFieldName.substring(0, 1).toUpperCase()
+ + normalizedFieldName.substring(1))) {
+ if (method.getModifiers().contains(Modifier.PRIVATE)) {
+ e.addWarning(new ProcessingException(
+ "Setter cannot be used: private visibility", method));
+ continue;
+ }
+ if (method.getParameters().size() != 1) {
+ e.addWarning(new ProcessingException(
+ "Setter cannot be used: takes " + method.getParameters().size()
+ + " parameters instead of 1",
+ method));
+ continue;
+ }
+ // Found one!
+ mSetterMethods.put(fieldName, method);
+ return;
+ }
+ }
+
+ // Broke out of the loop without finding anything.
+ throw e;
+ }
+
+ /**
+ * Produces the canonical name of a field (which is used as the default property name as well as
+ * to find accessors) by removing prefixes and suffixes of common conventions.
+ */
+ private String getNormalizedFieldName(String fieldName) {
+ if (fieldName.length() < 2) {
+ return fieldName;
+ }
+
+ // Handle convention of having field names start with m
+ // (e.g. String mName; public String getName())
+ if (fieldName.charAt(0) == 'm' && Character.isUpperCase(fieldName.charAt(1))) {
+ return fieldName.substring(1, 2).toLowerCase() + fieldName.substring(2);
+ }
+
+ // Handle convention of having field names start with _
+ // (e.g. String _name; public String getName())
+ if (fieldName.charAt(0) == '_'
+ && fieldName.charAt(1) != '_'
+ && Character.isLowerCase(fieldName.charAt(1))) {
+ return fieldName.substring(1);
+ }
+
+ // Handle convention of having field names end with _
+ // (e.g. String name_; public String getName())
+ if (fieldName.charAt(fieldName.length() - 1) == '_'
+ && fieldName.charAt(fieldName.length() - 2) != '_') {
+ return fieldName.substring(0, fieldName.length() - 1);
+ }
+
+ return fieldName;
+ }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
index 7ccdc53..05b9752 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
@@ -16,6 +16,8 @@
package androidx.appsearch.compiler;
+import static androidx.appsearch.compiler.IntrospectionHelper.getDocumentAnnotation;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -30,9 +32,11 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
@@ -42,28 +46,28 @@
import javax.lang.model.util.Types;
/**
- * Generates java code for a translator from a {@link androidx.appsearch.app.GenericDocument} to
- * a data class.
+ * Generates java code for a translator from a {@code androidx.appsearch.app.GenericDocument} to
+ * an instance of a class annotated with {@code androidx.appsearch.annotation.Document}.
*/
class FromGenericDocumentCodeGenerator {
private final ProcessingEnvironment mEnv;
private final IntrospectionHelper mHelper;
- private final AppSearchDocumentModel mModel;
-
- public static void generate(
- @NonNull ProcessingEnvironment env,
- @NonNull AppSearchDocumentModel model,
- @NonNull TypeSpec.Builder classBuilder) throws ProcessingException {
- new FromGenericDocumentCodeGenerator(env, model).generate(classBuilder);
- }
+ private final DocumentModel mModel;
private FromGenericDocumentCodeGenerator(
- @NonNull ProcessingEnvironment env, @NonNull AppSearchDocumentModel model) {
+ @NonNull ProcessingEnvironment env, @NonNull DocumentModel model) {
mEnv = env;
mHelper = new IntrospectionHelper(env);
mModel = model;
}
+ public static void generate(
+ @NonNull ProcessingEnvironment env,
+ @NonNull DocumentModel model,
+ @NonNull TypeSpec.Builder classBuilder) throws ProcessingException {
+ new FromGenericDocumentCodeGenerator(env, model).generate(classBuilder);
+ }
+
private void generate(TypeSpec.Builder classBuilder) throws ProcessingException {
classBuilder.addMethod(createFromGenericDocumentMethod());
}
@@ -80,14 +84,21 @@
unpackSpecialFields(methodBuilder);
- // Unpack properties from the GenericDocument into the format desired by the data class
+ // Unpack properties from the GenericDocument into the format desired by the document class
for (Map.Entry<String, VariableElement> entry : mModel.getPropertyFields().entrySet()) {
fieldFromGenericDoc(methodBuilder, entry.getKey(), entry.getValue());
}
- // Create an instance of the data class via the chosen constructor
- methodBuilder.addStatement(
- "$T dataClass = new $T($L)", classType, classType, getConstructorParams());
+ // Create an instance of the document class via the chosen create method.
+ if (mModel.getChosenCreationMethod().getKind() == ElementKind.CONSTRUCTOR) {
+ methodBuilder.addStatement(
+ "$T document = new $T($L)", classType, classType, getCreationMethodParams());
+ } else {
+ methodBuilder.addStatement(
+ "$T document = $T.$L($L)", classType, classType,
+ mModel.getChosenCreationMethod().getSimpleName().toString(),
+ getCreationMethodParams());
+ }
// Assign all fields which weren't set in the constructor
for (String field : mModel.getAllFields().keySet()) {
@@ -97,13 +108,13 @@
}
}
- methodBuilder.addStatement("return dataClass");
+ methodBuilder.addStatement("return document");
return methodBuilder.build();
}
/**
- * Converts a field from a {@link androidx.appsearch.app.GenericDocument} into a format suitable
- * for the data class.
+ * Converts a field from a {@code androidx.appsearch.app.GenericDocument} into a format suitable
+ * for the document class.
*/
private void fieldFromGenericDoc(
@NonNull MethodSpec.Builder builder,
@@ -121,7 +132,7 @@
// conversion of the collection elements is needed. We can use Arrays#asList for this.
//
// 1c: ListForLoopCallFromGenericDocument
- // List contains a class which is annotated with @AppSearchDocument.
+ // List contains a class which is annotated with @Document.
// We have to convert this from an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
//
@@ -143,7 +154,7 @@
// We can directly use this field with no conversion.
//
// 2c: ArrayForLoopCallFromGenericDocument
- // Array is of a class which is annotated with @AppSearchDocument.
+ // Array is of a class which is annotated with @Document.
// We have to convert this from an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
//
@@ -167,11 +178,9 @@
// needed
//
// 3c: FieldCallFromGenericDocument
- // Field is of a class which is annotated with @AppSearchDocument.
+ // Field is of a class which is annotated with @Document.
// We have to convert this from a GenericDocument through the standard conversion
// machinery.
- //
- // 3x: Field is of any other kind of class. This is unsupported and compilation fails.
String propertyName = mModel.getPropertyName(property);
if (tryConvertToList(builder, fieldName, propertyName, property)) {
@@ -206,9 +215,9 @@
CodeBlock.Builder builder = CodeBlock.builder();
if (!tryListForLoopAssign(builder, fieldName, propertyName, propertyType, listTypeName)// 1a
&& !tryListCallArraysAsList(
- builder, fieldName, propertyName, propertyType, listTypeName) // 1b
+ builder, fieldName, propertyName, propertyType, listTypeName) // 1b
&& !tryListForLoopCallFromGenericDocument(
- builder, fieldName, propertyName, propertyType, listTypeName)) { // 1c
+ builder, fieldName, propertyName, propertyType, listTypeName)) { // 1c
// Scenario 1x
throw new ProcessingException(
"Unhandled in property type (1x): " + property.asType().toString(), property);
@@ -322,7 +331,7 @@
}
// 1c: ListForLoopCallFromGenericDocument
- // List contains a class which is annotated with @AppSearchDocument.
+ // List contains a class which is annotated with @Document.
// We have to convert this from an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
private boolean tryListForLoopCallFromGenericDocument(
@@ -330,7 +339,7 @@
@NonNull String fieldName,
@NonNull String propertyName,
@NonNull TypeMirror propertyType,
- @NonNull ParameterizedTypeName listTypeName) {
+ @NonNull ParameterizedTypeName listTypeName) {
Types typeUtil = mEnv.getTypeUtils();
CodeBlock.Builder body = CodeBlock.builder();
@@ -340,9 +349,9 @@
return false;
}
try {
- mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ getDocumentAnnotation(element);
} catch (ProcessingException e) {
- // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 1c
+ // The propertyType doesn't have @Document annotation, this is not a type 1c
// list.
return false;
}
@@ -356,17 +365,15 @@
// If not null, iterate and assign
body.add("if ($NCopy != null) {\n", fieldName).indent();
- body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
- ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
- TypeName.get(propertyType)),
- mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
- body.addStatement("$NConv = new $T<>($NCopy.length)", fieldName, ArrayList.class,
- fieldName);
+ body.addStatement(
+ "$NConv = new $T<>($NCopy.length)", fieldName, ArrayList.class, fieldName);
- body.add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent();
- body.addStatement("$NConv.add(factory.fromGenericDocument($NCopy[i]))", fieldName,
- fieldName);
- body.unindent().add("}\n");
+ body
+ .add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent()
+ .addStatement(
+ "$NConv.add($NCopy[i].toDocumentClass($T.class))",
+ fieldName, fieldName, propertyType)
+ .unindent().add("}\n");
body.unindent().add("}\n"); // if ($NCopy != null) {
method.add(body.build());
@@ -397,7 +404,7 @@
if (!tryArrayForLoopAssign(builder, fieldName, propertyName, propertyType) // 2a
&& !tryArrayUseDirectly(builder, fieldName, propertyName, propertyType) // 2b
&& !tryArrayForLoopCallFromGenericDocument(
- builder, fieldName, propertyName, propertyType)) { // 2c
+ builder, fieldName, propertyName, propertyType)) { // 2c
// Scenario 2x
throw new ProcessingException(
"Unhandled in property type (2x): " + property.asType().toString(), property);
@@ -525,7 +532,7 @@
}
// 2c: ArrayForLoopCallFromGenericDocument
- // Array is of a class which is annotated with @AppSearchDocument.
+ // Array is of a class which is annotated with @Document.
// We have to convert this from an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
private boolean tryArrayForLoopCallFromGenericDocument(
@@ -542,9 +549,9 @@
return false;
}
try {
- mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ getDocumentAnnotation(element);
} catch (ProcessingException e) {
- // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 2c
+ // The propertyType doesn't have @Document annotation, this is not a type 2c
// array.
return false;
}
@@ -562,15 +569,13 @@
// If not null, iterate and assign
body.add("if ($NCopy != null) {\n", fieldName).indent();
body.addStatement("$NConv = new $T[$NCopy.length]", fieldName, propertyType, fieldName);
- body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
- ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
- TypeName.get(propertyType)),
- mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
- body.add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent();
- body.addStatement("$NConv[i] = factory.fromGenericDocument($NCopy[i])", fieldName,
- fieldName);
- body.unindent().add("}\n");
+ body
+ .add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent()
+ .addStatement(
+ "$NConv[i] = $NCopy[i].toDocumentClass($T.class)",
+ fieldName, fieldName, propertyType)
+ .unindent().add("}\n");
body.unindent().add("}\n"); // if ($NCopy != null) {
method.add(body.build());
@@ -592,12 +597,10 @@
if (!tryFieldUseDirectlyWithNullCheck(
builder, fieldName, propertyName, property.asType()) // 3a
&& !tryFieldUseDirectlyWithoutNullCheck(
- builder, fieldName, propertyName, property.asType()) // 3b
+ builder, fieldName, propertyName, property.asType()) // 3b
&& !tryFieldCallFromGenericDocument(
- builder, fieldName, propertyName, property.asType())) { // 3c
- // Scenario 3x
- throw new ProcessingException(
- "Unhandled in property type (3x): " + property.asType().toString(), property);
+ builder, fieldName, propertyName, property.asType())) { // 3c
+ throw new ProcessingException("Unhandled property type.", property);
}
method.addCode(builder.build());
}
@@ -716,7 +719,7 @@
}
// 3c: FieldCallFromGenericDocument
- // Field is of a class which is annotated with @AppSearchDocument.
+ // Field is of a class which is annotated with @Document.
// We have to convert this from a GenericDocument through the standard conversion
// machinery.
private boolean tryFieldCallFromGenericDocument(
@@ -733,9 +736,9 @@
return false;
}
try {
- mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ getDocumentAnnotation(element);
} catch (ProcessingException e) {
- // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 3c
+ // The propertyType doesn't have @Document annotation, this is not a type 3c
// field.
return false;
}
@@ -745,23 +748,21 @@
body.addStatement("$T $NConv = null", propertyType, fieldName);
// If not null, assign
- body.add("if ($NCopy != null) {\n", fieldName).indent();
-
- body.addStatement("$NConv = $T.getInstance().getOrCreateFactory($T.class)"
- + ".fromGenericDocument($NCopy)", fieldName,
- mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType,
- fieldName);
-
- body.unindent().add("}\n");
+ body
+ .add("if ($NCopy != null) {\n", fieldName).indent()
+ .addStatement(
+ "$NConv = $NCopy.toDocumentClass($T.class)",
+ fieldName, fieldName, propertyType)
+ .unindent().add("}\n");
method.add(body.build());
return true;
}
- private CodeBlock getConstructorParams() {
+ private CodeBlock getCreationMethodParams() {
CodeBlock.Builder builder = CodeBlock.builder();
- List<String> params = mModel.getChosenConstructorParams();
+ List<String> params = mModel.getChosenCreationMethodParams();
if (params.size() > 0) {
builder.add("$NConv", params.get(0));
}
@@ -772,15 +773,15 @@
}
private void unpackSpecialFields(@NonNull MethodSpec.Builder method) {
- for (AppSearchDocumentModel.SpecialField specialField :
- AppSearchDocumentModel.SpecialField.values()) {
+ for (DocumentModel.SpecialField specialField :
+ DocumentModel.SpecialField.values()) {
String fieldName = mModel.getSpecialFieldName(specialField);
if (fieldName == null) {
- continue; // The data class doesn't have this field, so no need to unpack it.
+ continue; // The document class doesn't have this field, so no need to unpack it.
}
switch (specialField) {
- case URI:
- method.addStatement("String $NConv = genericDoc.getUri()", fieldName);
+ case ID:
+ method.addStatement("String $NConv = genericDoc.getId()", fieldName);
break;
case NAMESPACE:
method.addStatement("String $NConv = genericDoc.getNamespace()", fieldName);
@@ -801,12 +802,12 @@
@Nullable
private CodeBlock createAppSearchFieldWrite(@NonNull String fieldName) {
- switch (mModel.getFieldWriteKind(fieldName)) {
+ switch (Objects.requireNonNull(mModel.getFieldWriteKind(fieldName))) {
case FIELD:
- return CodeBlock.of("dataClass.$N = $NConv", fieldName, fieldName);
+ return CodeBlock.of("document.$N = $NConv", fieldName, fieldName);
case SETTER:
- String setter = mModel.getAccessorName(fieldName, /*get=*/ false);
- return CodeBlock.of("dataClass.$N($NConv)", setter, fieldName);
+ String setter = mModel.getSetterForField(fieldName).getSimpleName().toString();
+ return CodeBlock.of("document.$N($NConv)", setter, fieldName);
default:
return null; // Constructor params should already have been set
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
index 0488796..dd9b510 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
@@ -17,6 +17,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
import com.squareup.javapoet.ClassName;
@@ -24,12 +25,16 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
@@ -37,28 +42,23 @@
/**
* Utilities for working with data structures representing parsed Java code.
+ *
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class IntrospectionHelper {
+ @VisibleForTesting
+ static final String GEN_CLASS_PREFIX = "$$__AppSearch__";
static final String APPSEARCH_PKG = "androidx.appsearch.app";
static final String APPSEARCH_EXCEPTION_PKG = "androidx.appsearch.exceptions";
static final String APPSEARCH_EXCEPTION_SIMPLE_NAME = "AppSearchException";
- static final String APP_SEARCH_DOCUMENT_CLASS =
- "androidx.appsearch.annotation.AppSearchDocument";
- static final String URI_CLASS =
- "androidx.appsearch.annotation.AppSearchDocument.Uri";
- static final String NAMESPACE_CLASS =
- "androidx.appsearch.annotation.AppSearchDocument.Namespace";
+ static final String DOCUMENT_ANNOTATION_CLASS = "androidx.appsearch.annotation.Document";
+ static final String ID_CLASS = "androidx.appsearch.annotation.Document.Id";
+ static final String NAMESPACE_CLASS = "androidx.appsearch.annotation.Document.Namespace";
static final String CREATION_TIMESTAMP_MILLIS_CLASS =
- "androidx.appsearch.annotation.AppSearchDocument.CreationTimestampMillis";
- static final String TTL_MILLIS_CLASS =
- "androidx.appsearch.annotation.AppSearchDocument.TtlMillis";
- static final String SCORE_CLASS =
- "androidx.appsearch.annotation.AppSearchDocument.Score";
- static final String PROPERTY_CLASS =
- "androidx.appsearch.annotation.AppSearchDocument.Property";
-
+ "androidx.appsearch.annotation.Document.CreationTimestampMillis";
+ static final String TTL_MILLIS_CLASS = "androidx.appsearch.annotation.Document.TtlMillis";
+ static final String SCORE_CLASS = "androidx.appsearch.annotation.Document.Score";
final TypeMirror mCollectionType;
final TypeMirror mListType;
final TypeMirror mStringType;
@@ -74,42 +74,96 @@
final TypeMirror mBooleanPrimitiveType;
final TypeMirror mByteBoxType;
final TypeMirror mByteBoxArrayType;
+ final TypeMirror mBytePrimitiveType;
final TypeMirror mBytePrimitiveArrayType;
-
private final ProcessingEnvironment mEnv;
+ private final Types mTypeUtils;
IntrospectionHelper(ProcessingEnvironment env) {
mEnv = env;
Elements elementUtil = env.getElementUtils();
- Types typeUtil = env.getTypeUtils();
+ mTypeUtils = env.getTypeUtils();
mCollectionType = elementUtil.getTypeElement(Collection.class.getName()).asType();
mListType = elementUtil.getTypeElement(List.class.getName()).asType();
mStringType = elementUtil.getTypeElement(String.class.getName()).asType();
mIntegerBoxType = elementUtil.getTypeElement(Integer.class.getName()).asType();
- mIntPrimitiveType = typeUtil.unboxedType(mIntegerBoxType);
+ mIntPrimitiveType = mTypeUtils.unboxedType(mIntegerBoxType);
mLongBoxType = elementUtil.getTypeElement(Long.class.getName()).asType();
- mLongPrimitiveType = typeUtil.unboxedType(mLongBoxType);
+ mLongPrimitiveType = mTypeUtils.unboxedType(mLongBoxType);
mFloatBoxType = elementUtil.getTypeElement(Float.class.getName()).asType();
- mFloatPrimitiveType = typeUtil.unboxedType(mFloatBoxType);
+ mFloatPrimitiveType = mTypeUtils.unboxedType(mFloatBoxType);
mDoubleBoxType = elementUtil.getTypeElement(Double.class.getName()).asType();
- mDoublePrimitiveType = typeUtil.unboxedType(mDoubleBoxType);
+ mDoublePrimitiveType = mTypeUtils.unboxedType(mDoubleBoxType);
mBooleanBoxType = elementUtil.getTypeElement(Boolean.class.getName()).asType();
- mBooleanPrimitiveType = typeUtil.unboxedType(mBooleanBoxType);
+ mBooleanPrimitiveType = mTypeUtils.unboxedType(mBooleanBoxType);
mByteBoxType = elementUtil.getTypeElement(Byte.class.getName()).asType();
- mBytePrimitiveArrayType = typeUtil.getArrayType(typeUtil.getPrimitiveType(TypeKind.BYTE));
- mByteBoxArrayType = typeUtil.getArrayType(mByteBoxType);
+ mByteBoxArrayType = mTypeUtils.getArrayType(mByteBoxType);
+ mBytePrimitiveType = mTypeUtils.unboxedType(mByteBoxType);
+ mBytePrimitiveArrayType = mTypeUtils.getArrayType(mBytePrimitiveType);
}
- public AnnotationMirror getAnnotation(@NonNull Element element, @NonNull String fqClass)
+ /**
+ * Returns {@code androidx.appsearch.annotation.Document} annotation element from the input
+ * element's annotations.
+ *
+ * @throws ProcessingException if no such annotation is found.
+ */
+ @NonNull
+ public static AnnotationMirror getDocumentAnnotation(@NonNull Element element)
throws ProcessingException {
+ Objects.requireNonNull(element);
for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
String annotationFq = annotation.getAnnotationType().toString();
- if (fqClass.equals(annotationFq)) {
+ if (IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS.equals(annotationFq)) {
return annotation;
}
}
- throw new ProcessingException("Missing annotation " + fqClass, element);
+ throw new ProcessingException(
+ "Missing annotation " + IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS, element);
+ }
+
+ /** Checks whether the property data type is one of the valid types. */
+ public boolean isFieldOfExactType(VariableElement property, TypeMirror... validTypes) {
+ TypeMirror propertyType = property.asType();
+ for (TypeMirror validType : validTypes) {
+ if (propertyType.getKind() == TypeKind.ARRAY) {
+ if (mTypeUtils.isSameType(
+ ((ArrayType) propertyType).getComponentType(), validType)) {
+ return true;
+ }
+ } else if (mTypeUtils.isAssignable(mTypeUtils.erasure(propertyType), mCollectionType)) {
+ if (mTypeUtils.isSameType(
+ ((DeclaredType) propertyType).getTypeArguments().get(0), validType)) {
+ return true;
+ }
+ } else if (mTypeUtils.isSameType(property.asType(), validType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether the property data class has {@code androidx.appsearch.annotation.Document
+ * .DocumentProperty} annotation.
+ */
+ public boolean isFieldOfDocumentType(VariableElement property) {
+ TypeMirror propertyType = property.asType();
+ try {
+ if (propertyType.getKind() == TypeKind.ARRAY) {
+ getDocumentAnnotation(
+ mTypeUtils.asElement(((ArrayType) property.asType()).getComponentType()));
+ } else if (mTypeUtils.isAssignable(mTypeUtils.erasure(propertyType), mCollectionType)) {
+ getDocumentAnnotation(mTypeUtils.asElement(
+ ((DeclaredType) propertyType).getTypeArguments().get(0)));
+ } else {
+ getDocumentAnnotation(mTypeUtils.asElement(propertyType));
+ }
+ } catch (ProcessingException e) {
+ return false;
+ }
+ return true;
}
public Map<String, Object> getAnnotationParams(@NonNull AnnotationMirror annotation) {
@@ -124,6 +178,24 @@
return ret;
}
+ /**
+ * Creates the name of output class. $$__AppSearch__Foo for Foo, $$__AppSearch__Foo$$__Bar
+ * for inner class Foo.Bar.
+ */
+ public ClassName getDocumentClassFactoryForClass(String pkg, String className) {
+ String genClassName = GEN_CLASS_PREFIX + className.replace(".", "$$__");
+ return ClassName.get(pkg, genClassName);
+ }
+
+ /**
+ * Creates the name of output class. $$__AppSearch__Foo for Foo, $$__AppSearch__Foo$$__Bar
+ * for inner class Foo.Bar.
+ */
+ public ClassName getDocumentClassFactoryForClass(ClassName clazz) {
+ String className = clazz.canonicalName().substring(clazz.packageName().length() + 1);
+ return getDocumentClassFactoryForClass(clazz.packageName(), className);
+ }
+
public ClassName getAppSearchClass(String clazz, String... nested) {
return ClassName.get(APPSEARCH_PKG, clazz, nested);
}
@@ -131,4 +203,27 @@
public ClassName getAppSearchExceptionClass() {
return ClassName.get(APPSEARCH_EXCEPTION_PKG, APPSEARCH_EXCEPTION_SIMPLE_NAME);
}
+
+ enum PropertyClass {
+ BOOLEAN_PROPERTY_CLASS("androidx.appsearch.annotation.Document.BooleanProperty"),
+ BYTES_PROPERTY_CLASS("androidx.appsearch.annotation.Document.BytesProperty"),
+ DOCUMENT_PROPERTY_CLASS("androidx.appsearch.annotation.Document.DocumentProperty"),
+ DOUBLE_PROPERTY_CLASS("androidx.appsearch.annotation.Document.DoubleProperty"),
+ LONG_PROPERTY_CLASS("androidx.appsearch.annotation.Document.LongProperty"),
+ STRING_PROPERTY_CLASS("androidx.appsearch.annotation.Document.StringProperty");
+
+ private final String mClassFullPath;
+
+ PropertyClass(String classFullPath) {
+ mClassFullPath = classFullPath;
+ }
+
+ String getClassFullPath() {
+ return mClassFullPath;
+ }
+
+ boolean isPropertyClass(String annotationFq) {
+ return mClassFullPath.equals(annotationFq);
+ }
+ }
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/MissingTypeException.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/MissingTypeException.java
new file mode 100644
index 0000000..918038f
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/MissingTypeException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+import javax.lang.model.element.Element;
+
+/**
+ * An exception thrown from the appsearch annotation processor to indicate a type element is not
+ * found due to it being possibly generated at a later annotation processing round.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+final class MissingTypeException extends Exception {
+ @NonNull
+ private final Element mTypeElement;
+
+ MissingTypeException(@NonNull Element typeElement) {
+ super("Type " + typeElement.getSimpleName() + " is not present");
+ mTypeElement = typeElement;
+ }
+
+ @NonNull
+ Element getTypeName() {
+ return mTypeElement;
+ }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
index eca9c5a..3693646 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
@@ -42,17 +42,17 @@
class SchemaCodeGenerator {
private final ProcessingEnvironment mEnv;
private final IntrospectionHelper mHelper;
- private final AppSearchDocumentModel mModel;
+ private final DocumentModel mModel;
public static void generate(
@NonNull ProcessingEnvironment env,
- @NonNull AppSearchDocumentModel model,
+ @NonNull DocumentModel model,
@NonNull TypeSpec.Builder classBuilder) throws ProcessingException {
new SchemaCodeGenerator(env, model).generate(classBuilder);
}
private SchemaCodeGenerator(
- @NonNull ProcessingEnvironment env, @NonNull AppSearchDocumentModel model) {
+ @NonNull ProcessingEnvironment env, @NonNull DocumentModel model) {
mEnv = env;
mHelper = new IntrospectionHelper(env);
mModel = model;
@@ -60,17 +60,17 @@
private void generate(@NonNull TypeSpec.Builder classBuilder) throws ProcessingException {
classBuilder.addField(
- FieldSpec.builder(String.class, "SCHEMA_TYPE")
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
+ FieldSpec.builder(String.class, "SCHEMA_NAME")
+ .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$S", mModel.getSchemaName())
.build());
classBuilder.addMethod(
- MethodSpec.methodBuilder("getSchemaType")
+ MethodSpec.methodBuilder("getSchemaName")
.addModifiers(Modifier.PUBLIC)
.returns(TypeName.get(mHelper.mStringType))
.addAnnotation(Override.class)
- .addStatement("return SCHEMA_TYPE")
+ .addStatement("return SCHEMA_NAME")
.build());
classBuilder.addMethod(
@@ -85,7 +85,7 @@
private CodeBlock createSchemaInitializer() throws ProcessingException {
CodeBlock.Builder codeBlock = CodeBlock.builder()
- .add("new $T(SCHEMA_TYPE)", mHelper.getAppSearchClass("AppSearchSchema", "Builder"))
+ .add("new $T(SCHEMA_NAME)", mHelper.getAppSearchClass("AppSearchSchema", "Builder"))
.indent();
for (VariableElement property : mModel.getPropertyFields().values()) {
codeBlock.add("\n.addProperty($L)", createPropertySchema(property));
@@ -96,22 +96,14 @@
private CodeBlock createPropertySchema(@NonNull VariableElement property)
throws ProcessingException {
- AnnotationMirror annotation =
- mHelper.getAnnotation(property, IntrospectionHelper.PROPERTY_CLASS);
+ AnnotationMirror annotation = mModel.getPropertyAnnotation(property);
Map<String, Object> params = mHelper.getAnnotationParams(annotation);
- // Start the builder for that property
- String propertyName = mModel.getPropertyName(property);
- CodeBlock.Builder codeBlock = CodeBlock.builder()
- .add("new $T($S)",
- mHelper.getAppSearchClass("AppSearchSchema", "PropertyConfig", "Builder"),
- propertyName)
- .indent();
-
// Find the property type
Types typeUtil = mEnv.getTypeUtils();
TypeMirror propertyType;
boolean repeated = false;
+ boolean isPropertyString = false;
boolean isPropertyDocument = false;
if (property.asType().getKind() == TypeKind.ERROR) {
throw new ProcessingException("Property type unknown to java compiler", property);
@@ -136,42 +128,47 @@
} else {
propertyType = property.asType();
}
- ClassName propertyTypeEnum;
+ ClassName propertyClass;
if (typeUtil.isSameType(propertyType, mHelper.mStringType)) {
- propertyTypeEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "DATA_TYPE_STRING");
+ propertyClass = mHelper.getAppSearchClass("AppSearchSchema", "StringPropertyConfig");
+ isPropertyString = true;
} else if (typeUtil.isSameType(propertyType, mHelper.mIntegerBoxType)
|| typeUtil.isSameType(propertyType, mHelper.mIntPrimitiveType)
|| typeUtil.isSameType(propertyType, mHelper.mLongBoxType)
|| typeUtil.isSameType(propertyType, mHelper.mLongPrimitiveType)) {
- propertyTypeEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "DATA_TYPE_INT64");
+ propertyClass = mHelper.getAppSearchClass("AppSearchSchema", "LongPropertyConfig");
} else if (typeUtil.isSameType(propertyType, mHelper.mFloatBoxType)
|| typeUtil.isSameType(propertyType, mHelper.mFloatPrimitiveType)
|| typeUtil.isSameType(propertyType, mHelper.mDoubleBoxType)
|| typeUtil.isSameType(propertyType, mHelper.mDoublePrimitiveType)) {
- propertyTypeEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "DATA_TYPE_DOUBLE");
+ propertyClass = mHelper.getAppSearchClass("AppSearchSchema", "DoublePropertyConfig");
} else if (typeUtil.isSameType(propertyType, mHelper.mBooleanBoxType)
|| typeUtil.isSameType(propertyType, mHelper.mBooleanPrimitiveType)) {
- propertyTypeEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "DATA_TYPE_BOOLEAN");
+ propertyClass = mHelper.getAppSearchClass("AppSearchSchema", "BooleanPropertyConfig");
} else if (typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)
|| typeUtil.isSameType(propertyType, mHelper.mByteBoxArrayType)) {
- propertyTypeEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "DATA_TYPE_BYTES");
+ propertyClass = mHelper.getAppSearchClass("AppSearchSchema", "BytesPropertyConfig");
} else {
- propertyTypeEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "DATA_TYPE_DOCUMENT");
+ propertyClass = mHelper.getAppSearchClass("AppSearchSchema", "DocumentPropertyConfig");
isPropertyDocument = true;
}
- codeBlock.add("\n.setDataType($T)", propertyTypeEnum);
+ // Start the builder for the property
+ String propertyName = mModel.getPropertyName(property);
+ CodeBlock.Builder codeBlock = CodeBlock.builder();
if (isPropertyDocument) {
- codeBlock.add("\n.setSchemaType($T.getInstance()"
- + ".getOrCreateFactory($T.class).getSchemaType())",
- mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
+ ClassName documentClass = (ClassName) ClassName.get(propertyType);
+ ClassName documentFactoryClass = mHelper.getDocumentClassFactoryForClass(documentClass);
+ codeBlock.add(
+ "new $T($S, $T.SCHEMA_NAME)",
+ propertyClass.nestedClass("Builder"),
+ propertyName,
+ documentFactoryClass);
+ } else {
+ codeBlock.add("new $T($S)", propertyClass.nestedClass("Builder"), propertyName);
}
+ codeBlock.indent();
+
// Find property cardinality
ClassName cardinalityEnum;
if (repeated) {
@@ -186,42 +183,45 @@
}
codeBlock.add("\n.setCardinality($T)", cardinalityEnum);
- // Find tokenizer type
- int tokenizerType = Integer.parseInt(params.get("tokenizerType").toString());
- if (Integer.parseInt(params.get("indexingType").toString()) == 0) {
- //TODO(b/171857731) remove this hack after apply to Icing lib's change.
- tokenizerType = 0;
- }
- ClassName tokenizerEnum;
- if (tokenizerType == 0 || isPropertyDocument) { // TOKENIZER_TYPE_NONE
- //It is only valid for tokenizer_type to be 'NONE' if the data type is
- // {@link PropertyConfig#DATA_TYPE_DOCUMENT}.
- tokenizerEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "TOKENIZER_TYPE_NONE");
- } else if (tokenizerType == 1) { // TOKENIZER_TYPE_PLAIN
- tokenizerEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "TOKENIZER_TYPE_PLAIN");
- } else {
- throw new ProcessingException("Unknown tokenizer type " + tokenizerType, property);
- }
- codeBlock.add("\n.setTokenizerType($T)", tokenizerEnum);
+ if (isPropertyString) {
+ // Find tokenizer type
+ int tokenizerType = Integer.parseInt(params.get("tokenizerType").toString());
+ if (Integer.parseInt(params.get("indexingType").toString()) == 0) {
+ //TODO(b/171857731) remove this hack after apply to Icing lib's change.
+ tokenizerType = 0;
+ }
+ ClassName tokenizerEnum;
+ if (tokenizerType == 0) { // TOKENIZER_TYPE_NONE
+ tokenizerEnum = mHelper.getAppSearchClass(
+ "AppSearchSchema", "StringPropertyConfig", "TOKENIZER_TYPE_NONE");
+ } else if (tokenizerType == 1) { // TOKENIZER_TYPE_PLAIN
+ tokenizerEnum = mHelper.getAppSearchClass(
+ "AppSearchSchema", "StringPropertyConfig", "TOKENIZER_TYPE_PLAIN");
+ } else {
+ throw new ProcessingException("Unknown tokenizer type " + tokenizerType, property);
+ }
+ codeBlock.add("\n.setTokenizerType($T)", tokenizerEnum);
- // Find indexing type
- int indexingType = Integer.parseInt(params.get("indexingType").toString());
- ClassName indexingEnum;
- if (indexingType == 0) { // INDEXING_TYPE_NONE
- indexingEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "INDEXING_TYPE_NONE");
- } else if (indexingType == 1) { // INDEXING_TYPE_EXACT_TERMS
- indexingEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "INDEXING_TYPE_EXACT_TERMS");
- } else if (indexingType == 2) { // INDEXING_TYPE_PREFIXES
- indexingEnum = mHelper.getAppSearchClass(
- "AppSearchSchema", "PropertyConfig", "INDEXING_TYPE_PREFIXES");
- } else {
- throw new ProcessingException("Unknown indexing type " + indexingType, property);
+ // Find indexing type
+ int indexingType = Integer.parseInt(params.get("indexingType").toString());
+ ClassName indexingEnum;
+ if (indexingType == 0) { // INDEXING_TYPE_NONE
+ indexingEnum = mHelper.getAppSearchClass(
+ "AppSearchSchema", "StringPropertyConfig", "INDEXING_TYPE_NONE");
+ } else if (indexingType == 1) { // INDEXING_TYPE_EXACT_TERMS
+ indexingEnum = mHelper.getAppSearchClass(
+ "AppSearchSchema", "StringPropertyConfig", "INDEXING_TYPE_EXACT_TERMS");
+ } else if (indexingType == 2) { // INDEXING_TYPE_PREFIXES
+ indexingEnum = mHelper.getAppSearchClass(
+ "AppSearchSchema", "StringPropertyConfig", "INDEXING_TYPE_PREFIXES");
+ } else {
+ throw new ProcessingException("Unknown indexing type " + indexingType, property);
+ }
+ codeBlock.add("\n.setIndexingType($T)", indexingEnum);
+
+ } else if (isPropertyDocument) {
+ // TODO(b/177572431): Apply setIndexNestedProperties here
}
- codeBlock.add("\n.setIndexingType($T)", indexingEnum);
// Done!
codeBlock.add("\n.build()");
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
index b30d907..1679c84 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
@@ -16,6 +16,8 @@
package androidx.appsearch.compiler;
+import static androidx.appsearch.compiler.IntrospectionHelper.getDocumentAnnotation;
+
import androidx.annotation.NonNull;
import com.squareup.javapoet.CodeBlock;
@@ -27,6 +29,7 @@
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
@@ -39,28 +42,29 @@
import javax.lang.model.util.Types;
/**
- * Generates java code for a translator from a data class to a
+ * Generates java code for a translator from an instance of a class annotated with
+ * {@link androidx.appsearch.annotation.Document} into a
* {@link androidx.appsearch.app.GenericDocument}.
*/
class ToGenericDocumentCodeGenerator {
private final ProcessingEnvironment mEnv;
private final IntrospectionHelper mHelper;
- private final AppSearchDocumentModel mModel;
-
- public static void generate(
- @NonNull ProcessingEnvironment env,
- @NonNull AppSearchDocumentModel model,
- @NonNull TypeSpec.Builder classBuilder) throws ProcessingException {
- new ToGenericDocumentCodeGenerator(env, model).generate(classBuilder);
- }
+ private final DocumentModel mModel;
private ToGenericDocumentCodeGenerator(
- @NonNull ProcessingEnvironment env, @NonNull AppSearchDocumentModel model) {
+ @NonNull ProcessingEnvironment env, @NonNull DocumentModel model) {
mEnv = env;
mHelper = new IntrospectionHelper(env);
mModel = model;
}
+ public static void generate(
+ @NonNull ProcessingEnvironment env,
+ @NonNull DocumentModel model,
+ @NonNull TypeSpec.Builder classBuilder) throws ProcessingException {
+ new ToGenericDocumentCodeGenerator(env, model).generate(classBuilder);
+ }
+
private void generate(TypeSpec.Builder classBuilder) throws ProcessingException {
classBuilder.addMethod(createToGenericDocumentMethod());
}
@@ -72,17 +76,19 @@
.addModifiers(Modifier.PUBLIC)
.returns(mHelper.getAppSearchClass("GenericDocument"))
.addAnnotation(Override.class)
- .addParameter(classType, "dataClass")
+ .addParameter(classType, "document")
.addException(mHelper.getAppSearchExceptionClass());
- // Construct a new GenericDocument.Builder with the schema type and URI
- methodBuilder.addStatement("$T builder =\nnew $T<>($L, SCHEMA_TYPE)",
+ // Construct a new GenericDocument.Builder with the namespace, id, and schema type
+ methodBuilder.addStatement("$T builder =\nnew $T<>($L, $L, SCHEMA_NAME)",
ParameterizedTypeName.get(
mHelper.getAppSearchClass("GenericDocument", "Builder"),
WildcardTypeName.subtypeOf(Object.class)),
mHelper.getAppSearchClass("GenericDocument", "Builder"),
createAppSearchFieldRead(
- mModel.getSpecialFieldName(AppSearchDocumentModel.SpecialField.URI)));
+ mModel.getSpecialFieldName(DocumentModel.SpecialField.NAMESPACE)),
+ createAppSearchFieldRead(
+ mModel.getSpecialFieldName(DocumentModel.SpecialField.ID)));
setSpecialFields(methodBuilder);
@@ -96,7 +102,7 @@
}
/**
- * Converts a field from a data class into a format suitable for one of the
+ * Converts a field from a document class into a format suitable for one of the
* {@link androidx.appsearch.app.GenericDocument.Builder#setProperty} methods.
*/
private void fieldToGenericDoc(
@@ -117,7 +123,7 @@
// this.
//
// 1c: CollectionForLoopCallToGenericDocument
- // Collection contains a class which is annotated with @AppSearchDocument.
+ // Collection contains a class which is annotated with @Document.
// We have to convert this into an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
//
@@ -141,7 +147,7 @@
// We can directly use this field with no conversion.
//
// 2c: ArrayForLoopCallToGenericDocument
- // Array is of a class which is annotated with @AppSearchDocument.
+ // Array is of a class which is annotated with @Document.
// We have to convert this into an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
//
@@ -164,11 +170,9 @@
// We can use this field directly without testing for null.
//
// 3c: FieldCallToGenericDocument
- // Field is of a class which is annotated with @AppSearchDocument.
+ // Field is of a class which is annotated with @Document.
// We have to convert this into a GenericDocument through the standard conversion
// machinery.
- //
- // 3x: Field is of any other kind of class. This is unsupported and compilation fails.
String propertyName = mModel.getPropertyName(property);
if (tryConvertFromCollection(method, fieldName, propertyName, property)) {
return;
@@ -209,7 +213,7 @@
if (!tryCollectionForLoopAssign(body, fieldName, propertyName, propertyType) // 1a
&& !tryCollectionCallToArray(body, fieldName, propertyName, propertyType) // 1b
&& !tryCollectionForLoopCallToGenericDocument(
- body, fieldName, propertyName, propertyType)) { // 1c
+ body, fieldName, propertyName, propertyType)) { // 1c
// Scenario 1x
throw new ProcessingException(
"Unhandled out property type (1x): " + property.asType().toString(), property);
@@ -304,7 +308,7 @@
}
// 1c: CollectionForLoopCallToGenericDocument
- // Collection contains a class which is annotated with @AppSearchDocument.
+ // Collection contains a class which is annotated with @Document.
// We have to convert this into an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
private boolean tryCollectionForLoopCallToGenericDocument(
@@ -322,28 +326,28 @@
return false;
}
try {
- mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ getDocumentAnnotation(element);
} catch (ProcessingException e) {
- // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 1c
+ // The propertyType doesn't have @Document annotation, this is not a type 1c
// list.
return false;
}
- body.addStatement("GenericDocument[] $NConv = new GenericDocument[$NCopy.size()]",
+ body.addStatement(
+ "GenericDocument[] $NConv = new GenericDocument[$NCopy.size()]",
fieldName, fieldName);
- body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
- ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
- TypeName.get(propertyType)),
- mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
-
body.addStatement("int i = 0");
- body.add("for ($T item : $NCopy) {\n", propertyType, fieldName).indent();
- body.addStatement("$NConv[i++] = factory.toGenericDocument(item)", fieldName);
+ body
+ .add("for ($T item : $NCopy) {\n", propertyType, fieldName).indent()
+ .addStatement(
+ "$NConv[i++] = $T.fromDocumentClass(item)",
+ fieldName, mHelper.getAppSearchClass("GenericDocument"))
+ .unindent().add("}\n");
- body.unindent().add("}\n");
-
- body.addStatement("builder.setPropertyDocument($S, $NConv)", propertyName, fieldName)
- .unindent().add("}\n"); // if ($NCopy != null) {
+ body
+ .addStatement("builder.setPropertyDocument($S, $NConv)", propertyName, fieldName)
+ .unindent()
+ .add("}\n"); // if ($NCopy != null) {
method.add(body.build());
return true;
@@ -379,7 +383,7 @@
if (!tryArrayForLoopAssign(body, fieldName, propertyName, propertyType) // 2a
&& !tryArrayUseDirectly(body, fieldName, propertyName, propertyType) // 2b
&& !tryArrayForLoopCallToGenericDocument(
- body, fieldName, propertyName, propertyType)) { // 2c
+ body, fieldName, propertyName, propertyType)) { // 2c
// Scenario 2x
throw new ProcessingException(
"Unhandled out property type (2x): " + property.asType().toString(), property);
@@ -483,7 +487,7 @@
}
// 2c: ArrayForLoopCallToGenericDocument
- // Array is of a class which is annotated with @AppSearchDocument.
+ // Array is of a class which is annotated with @Document.
// We have to convert this into an array of GenericDocument[], by reading each element
// one-by-one and converting it through the standard conversion machinery.
private boolean tryArrayForLoopCallToGenericDocument(
@@ -501,23 +505,22 @@
return false;
}
try {
- mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ getDocumentAnnotation(element);
} catch (ProcessingException e) {
- // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 1c
+ // The propertyType doesn't have @Document annotation, this is not a type 1c
// list.
return false;
}
- body.addStatement("GenericDocument[] $NConv = new GenericDocument[$NCopy.length]",
+ body.addStatement(
+ "GenericDocument[] $NConv = new GenericDocument[$NCopy.length]",
fieldName, fieldName);
- body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
- ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
- TypeName.get(propertyType)),
- mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
- body.add("for (int i = 0; i < $NConv.length; i++) {\n", fieldName).indent();
- body.addStatement("$NConv[i] = factory.toGenericDocument($NCopy[i])",
- fieldName, fieldName);
- body.unindent().add("}\n");
+ body
+ .add("for (int i = 0; i < $NConv.length; i++) {\n", fieldName).indent()
+ .addStatement(
+ "$NConv[i] = $T.fromDocumentClass($NCopy[i])",
+ fieldName, mHelper.getAppSearchClass("GenericDocument"), fieldName)
+ .unindent().add("}\n");
body.addStatement("builder.setPropertyDocument($S, $NConv)", propertyName, fieldName)
.unindent().add("}\n"); // if ($NCopy != null) {
@@ -540,12 +543,10 @@
if (!tryFieldUseDirectlyWithNullCheck(
body, fieldName, propertyName, property.asType()) // 3a
&& !tryFieldUseDirectlyWithoutNullCheck(
- body, fieldName, propertyName, property.asType()) // 3b
+ body, fieldName, propertyName, property.asType()) // 3b
&& !tryFieldCallToGenericDocument(
- body, fieldName, propertyName, property.asType())) { // 3c
- // Scenario 3x
- throw new ProcessingException(
- "Unhandled out property type (3x): " + property.asType().toString(), property);
+ body, fieldName, propertyName, property.asType())) { // 3c
+ throw new ProcessingException("Unhandled property type.", property);
}
method.addCode(body.build());
}
@@ -627,7 +628,7 @@
}
// 3c: FieldCallToGenericDocument
- // Field is of a class which is annotated with @AppSearchDocument.
+ // Field is of a class which is annotated with @Document.
// We have to convert this into a GenericDocument through the standard conversion
// machinery.
private boolean tryFieldCallToGenericDocument(
@@ -643,47 +644,39 @@
return false;
}
try {
- mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ getDocumentAnnotation(element);
} catch (ProcessingException e) {
- // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 3c
+ // The propertyType doesn't have @Document annotation, this is not a type 3c
// field.
return false;
}
- method.addStatement("$T $NCopy = $L", propertyType, propertyName,
- createAppSearchFieldRead(fieldName));
+ method.addStatement(
+ "$T $NCopy = $L", propertyType, fieldName, createAppSearchFieldRead(fieldName));
- method.add("if ($NCopy != null) {\n", propertyName).indent();
+ method.add("if ($NCopy != null) {\n", fieldName).indent();
- method.addStatement("GenericDocument $NConv = $T.getInstance().getOrCreateFactory($T.class)"
- + ".toGenericDocument($NCopy)", fieldName,
- mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType,
- propertyName);
- method.addStatement("builder.setPropertyDocument($S, $NConv)", propertyName, fieldName);
+ method
+ .addStatement(
+ "GenericDocument $NConv = $T.fromDocumentClass($NCopy)",
+ fieldName, mHelper.getAppSearchClass("GenericDocument"), fieldName)
+ .addStatement("builder.setPropertyDocument($S, $NConv)", propertyName, fieldName);
method.unindent().add("}\n");
return true;
}
private void setSpecialFields(MethodSpec.Builder method) {
- for (AppSearchDocumentModel.SpecialField specialField :
- AppSearchDocumentModel.SpecialField.values()) {
+ for (DocumentModel.SpecialField specialField :
+ DocumentModel.SpecialField.values()) {
String fieldName = mModel.getSpecialFieldName(specialField);
if (fieldName == null) {
- continue; // The data class doesn't have this field, so no need to set it.
+ continue; // The document class doesn't have this field, so no need to set it.
}
switch (specialField) {
- case URI:
+ case ID:
break; // Always provided to builder constructor; cannot be set separately.
case NAMESPACE:
- method.addCode(CodeBlock.builder()
- .addStatement(
- "String $NCopy = $L",
- fieldName, createAppSearchFieldRead(fieldName))
- .add("if ($NCopy != null) {\n", fieldName).indent()
- .addStatement("builder.setNamespace($NCopy)", fieldName)
- .unindent().add("}\n")
- .build());
- break;
+ break; // Always provided to builder constructor; cannot be set separately.
case CREATION_TIMESTAMP_MILLIS:
method.addStatement(
"builder.setCreationTimestampMillis($L)",
@@ -702,12 +695,12 @@
}
private CodeBlock createAppSearchFieldRead(@NonNull String fieldName) {
- switch (mModel.getFieldReadKind(fieldName)) {
+ switch (Objects.requireNonNull(mModel.getFieldReadKind(fieldName))) {
case FIELD:
- return CodeBlock.of("dataClass.$N", fieldName);
+ return CodeBlock.of("document.$N", fieldName);
case GETTER:
- String getter = mModel.getAccessorName(fieldName, /*get=*/ true);
- return CodeBlock.of("dataClass.$N()", getter);
+ String getter = mModel.getGetterForField(fieldName).getSimpleName().toString();
+ return CodeBlock.of("document.$N()", getter);
}
return null;
}
diff --git a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
index 1693cd6..b446553 100644
--- a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
+++ b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
@@ -16,11 +16,13 @@
package androidx.appsearch.compiler;
+import static com.google.testing.compile.CompilationSubject.assertThat;
+
+import com.google.auto.value.processor.AutoValueProcessor;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
import com.google.common.truth.Truth;
import com.google.testing.compile.Compilation;
-import com.google.testing.compile.CompilationSubject;
import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
@@ -57,9 +59,10 @@
@Test
public void testNonClass() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public interface Gift {}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"annotation on something other than a class");
}
@@ -68,311 +71,511 @@
Compilation compilation = compile(
"Wrapper",
"public class Wrapper {\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "private class Gift {}\n"
+ "} // Wrapper\n"
);
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "annotated class is private");
+
+ assertThat(compilation).hadErrorContaining("annotated class is private");
}
@Test
- public void testNoUri() {
+ public void testNoId() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
- + "public class Gift {}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "must have exactly one field annotated with @Uri");
- }
-
- @Test
- public void testManyUri() {
- Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri1;\n"
- + " @AppSearchDocument.Uri String uri2;\n"
+ + " @Document.Namespace String namespace;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "contains multiple fields annotated @Uri");
+
+ assertThat(compilation).hadErrorContaining(
+ "must have exactly one field annotated with @Id");
+ }
+
+ @Test
+ public void testManyIds() {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id1;\n"
+ + " @Document.Id String id2;\n"
+ + "}\n");
+
+ assertThat(compilation).hadErrorContaining(
+ "contains multiple fields annotated @Id");
}
@Test
public void testManyCreationTimestamp() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.CreationTimestampMillis long ts1;\n"
- + " @AppSearchDocument.CreationTimestampMillis long ts2;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.CreationTimestampMillis long ts1;\n"
+ + " @Document.CreationTimestampMillis long ts2;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"contains multiple fields annotated @CreationTimestampMillis");
}
@Test
+ public void testNoNamespace() {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " @Document.Id String id;\n"
+ + "}\n");
+
+ assertThat(compilation).hadErrorContaining(
+ "must have exactly one field annotated with @Namespace");
+ }
+
+ @Test
public void testManyNamespace() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Namespace String ns1;\n"
- + " @AppSearchDocument.Namespace String ns2;\n"
+ + " @Document.Namespace String ns1;\n"
+ + " @Document.Namespace String ns2;\n"
+ + " @Document.Id String id;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"contains multiple fields annotated @Namespace");
}
@Test
public void testManyTtlMillis() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.TtlMillis long ts1;\n"
- + " @AppSearchDocument.TtlMillis long ts2;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.TtlMillis long ts1;\n"
+ + " @Document.TtlMillis long ts2;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"contains multiple fields annotated @TtlMillis");
}
@Test
public void testManyScore() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Score int score1;\n"
- + " @AppSearchDocument.Score int score2;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.Score int score1;\n"
+ + " @Document.Score int score2;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"contains multiple fields annotated @Score");
}
@Test
- public void testPropertyOnField() {
+ public void testPropertyOnFieldForNonAutoValueClass() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int getPrice() { return 0; }\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int getPrice() { return 0; }\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "annotation type not applicable to this kind of declaration");
+
+ assertThat(compilation).hadErrorContaining(
+ "AppSearch annotation is not applicable to methods for Non-AutoValue class");
}
@Test
public void testCantRead_noGetter() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"Field cannot be read: it is private and we failed to find a suitable getter "
- + "named \"getPrice\"");
+ + "for field \"price\"");
}
@Test
public void testCantRead_privateGetter() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ " private int getPrice() { return 0; }\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"Field cannot be read: it is private and we failed to find a suitable getter "
- + "named \"getPrice\"");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
- "Getter cannot be used: private visibility");
+ + "for field \"price\"");
+ assertThat(compilation).hadWarningContaining("Getter cannot be used: private visibility");
}
@Test
public void testCantRead_wrongParamGetter() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ " int getPrice(int n) { return 0; }\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+
+ assertThat(compilation).hadErrorContaining(
"Field cannot be read: it is private and we failed to find a suitable getter "
- + "named \"getPrice\"");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
+ + "for field \"price\"");
+ assertThat(compilation).hadWarningContaining(
"Getter cannot be used: should take no parameters");
}
@Test
public void testRead_MultipleGetters() throws Exception {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ " int getPrice(int n) { return 0; }\n"
+ " int getPrice() { return 0; }\n"
+ " void setPrice(int n) {}\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
+ public void testGetterAndSetterFunctions_withFieldName() throws Exception {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ + " int price() { return 0; }\n"
+ + " void price(int n) {}\n"
+ + "}\n");
+
+ assertThat(compilation).succeededWithoutWarnings();
+ // Check setter function is identified correctly.
+ checkResultContains(/* className= */ "Gift.java",
+ /* content= */ "builder.setPropertyLong(\"price\", document.price());");
+ // Check getter function is identified correctly.
+ checkResultContains(/* className= */ "Gift.java",
+ /* content= */ "document.price(priceConv);");
checkEqualsGolden("Gift.java");
}
@Test
public void testCantWrite_noSetter() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ " int getPrice() { return price; }\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Failed to find any suitable constructors to build this class");
- CompilationSubject.assertThat(compilation).hadWarningContainingMatch(
- "Field cannot be written .* failed to find a suitable setter named \"setPrice\"");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
- "Cannot use this constructor to construct the class: This constructor doesn't have "
+
+ assertThat(compilation).hadErrorContaining(
+ "Failed to find any suitable creation methods to build this class");
+ assertThat(compilation).hadWarningContainingMatch(
+ "Field cannot be written .* failed to find a suitable setter for field \"price\"");
+ assertThat(compilation).hadWarningContaining(
+ "Cannot use this creation method to construct the class: This method doesn't have "
+ "parameters for the following fields: [price]");
}
@Test
public void testCantWrite_privateSetter() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ " int getPrice() { return price; }\n"
+ " private void setPrice(int n) {}\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Failed to find any suitable constructors to build this class");
- CompilationSubject.assertThat(compilation).hadWarningContainingMatch(
- "Field cannot be written .* failed to find a suitable setter named \"setPrice\"");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
+
+ assertThat(compilation).hadErrorContaining(
+ "Failed to find any suitable creation methods to build this class");
+ assertThat(compilation).hadWarningContainingMatch(
+ "Field cannot be written .* failed to find a suitable setter for field \"price\"");
+ assertThat(compilation).hadWarningContaining(
"Setter cannot be used: private visibility");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
- "Cannot use this constructor to construct the class: This constructor doesn't have "
+ assertThat(compilation).hadWarningContaining(
+ "Cannot use this creation method to construct the class: This method doesn't have "
+ "parameters for the following fields: [price]");
}
@Test
public void testCantWrite_wrongParamSetter() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ " int getPrice() { return price; }\n"
+ " void setPrice() {}\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Failed to find any suitable constructors to build this class");
- CompilationSubject.assertThat(compilation).hadWarningContainingMatch(
- "Field cannot be written .* failed to find a suitable setter named \"setPrice\"");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
+
+ assertThat(compilation).hadErrorContaining(
+ "Failed to find any suitable creation methods to build this class");
+ assertThat(compilation).hadWarningContainingMatch(
+ "Field cannot be written .* failed to find a suitable setter for field \"price\"");
+ assertThat(compilation).hadWarningContaining(
"Setter cannot be used: takes 0 parameters instead of 1");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
- "Cannot use this constructor to construct the class: This constructor doesn't have "
+ assertThat(compilation).hadWarningContaining(
+ "Cannot use this creation method to construct the class: This method doesn't have "
+ "parameters for the following fields: [price]");
}
@Test
public void testWrite_multipleSetters() throws Exception {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property private int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty private int price;\n"
+ " int getPrice() { return price; }\n"
+ " void setPrice() {}\n"
+ " void setPrice(int n) {}\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@Test
public void testWrite_privateConstructor() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
+ " private Gift() {}\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty int price;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Failed to find any suitable constructors to build this class");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
- "Constructor is private");
+
+ assertThat(compilation).hadErrorContaining(
+ "Failed to find any suitable creation methods to build this class");
+ assertThat(compilation).hadWarningContaining("Creation method is private");
}
@Test
public void testWrite_constructorMissingParams() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
+ " Gift(int price) {}\n"
- + " @AppSearchDocument.Uri final String uri;\n"
- + " @AppSearchDocument.Property int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id final String id;\n"
+ + " @Document.LongProperty int price;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Failed to find any suitable constructors to build this class");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
- "doesn't have parameters for the following fields: [uri]");
+
+ assertThat(compilation).hadErrorContaining(
+ "Failed to find any suitable creation methods to build this class");
+ assertThat(compilation).hadWarningContaining(
+ "doesn't have parameters for the following fields: [id]");
+ }
+
+ @Test
+ public void testWrite_factoryMethodOnly() throws IOException {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " private Gift(int price, String id, String namespace) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " this.price = price;\n"
+ + " }\n"
+ + " public static Gift create(String id, String namespace, int price) {\n"
+ + " return new Gift(price, id, namespace);"
+ + " }\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id final String id;\n"
+ + " @Document.LongProperty int price;\n"
+ + "}\n");
+
+ assertThat(compilation).succeededWithoutWarnings();
+ checkResultContains(/* className= */ "Gift.java",
+ /* content= */ "Gift document = Gift.create(idConv, namespaceConv, priceConv);");
+ }
+
+ @Test
+ // With golden class for factory method.
+ public void testWrite_bothUsableFactoryMethodAndConstructor_picksFirstUsableCreationMethod()
+ throws IOException {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " Gift(String id, String namespace, int price) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " this.price = price;\n"
+ + " }\n"
+ + " public static Gift create(String id, String namespace, int price) {\n"
+ + " return new Gift(id, namespace, price);"
+ + " }\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.LongProperty int price;\n"
+ + "}\n");
+
+ assertThat(compilation).succeededWithoutWarnings();
+ checkResultContains(/* className= */ "Gift.java",
+ /* content= */ "Gift document = new Gift(idConv, namespaceConv, priceConv);");
+ }
+
+ @Test
+ public void testWrite_usableFactoryMethod_unusableConstructor()
+ throws IOException {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " private Gift(String id, String namespace, int price) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " this.price = price;\n"
+ + " }\n"
+ + " public static Gift create(String id, String namespace, int price) {\n"
+ + " return new Gift(id, namespace, price);"
+ + " }\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id final String id;\n"
+ + " @Document.LongProperty int price;\n"
+ + "}\n");
+
+ assertThat(compilation).succeededWithoutWarnings();
+ checkResultContains(/* className= */ "Gift.java",
+ /* content= */ "Gift document = Gift.create(idConv, namespaceConv, priceConv);");
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
+ public void testWrite_unusableFactoryMethod_usableConstructor()
+ throws IOException {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " Gift(String id, String namespace, int price) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " this.price = price;\n"
+ + " }\n"
+ + " private static Gift create(String id, String namespace, int price){\n"
+ + " return new Gift(id, namespace, price);"
+ + " }\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id final String id;\n"
+ + " @Document.LongProperty int price;\n"
+ + "}\n");
+
+ assertThat(compilation).succeededWithoutWarnings();
+ checkResultContains(/* className= */ "Gift.java",
+ /* content= */ "Gift document = new Gift(idConv, namespaceConv, priceConv);");
}
@Test
public void testWrite_constructorExtraParams() {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " Gift(int price, String uri, int unknownParam) {\n"
- + " this.uri = uri;\n"
+ + " Gift(int price, String id, String namespace, int unknownParam) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ " this.price = price;\n"
+ " }\n"
- + " @AppSearchDocument.Uri final String uri;\n"
- + " @AppSearchDocument.Property int price;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id final String id;\n"
+ + " @Document.LongProperty int price;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Failed to find any suitable constructors to build this class");
- CompilationSubject.assertThat(compilation).hadWarningContaining(
+
+ assertThat(compilation).hadErrorContaining(
+ "Failed to find any suitable creation methods to build this class");
+ assertThat(compilation).hadWarningContaining(
"Parameter \"unknownParam\" is not an AppSearch parameter; don't know how to "
+ "supply it");
}
@Test
+ public void testWrite_multipleConventions() throws Exception {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id private String id_;\n"
+ + " @Document.LongProperty private int price1;\n"
+ + " @Document.LongProperty private int mPrice2;\n"
+ + " @Document.LongProperty private int _price3;\n"
+ + " @Document.LongProperty final int price4_;\n"
+ + " int getPrice1() { return price1; }\n"
+ + " int price2() { return mPrice2; }\n"
+ + " int getPrice3() { return _price3; }\n"
+ + " void setPrice1(int n) {}\n"
+ + " void price2(int n) {}\n"
+ + " void price3(int n) {}\n"
+ + " String getId() {\n"
+ + " return id_;\n"
+ + " }\n"
+ + " public Gift(String id, int price4) {\n"
+ + " id_ = id;"
+ + " price4_ = price4;\n"
+ + " }\n"
+ + "}\n");
+ assertThat(compilation).succeededWithoutWarnings();
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
public void testSuccessSimple() throws Exception {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " Gift(boolean dog, String uri) {\n"
- + " this.uri = uri;\n"
+ + " Gift(boolean dog, String id, String namespace) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ " this.dog = dog;\n"
+ " }\n"
- + " @AppSearchDocument.Uri final String uri;\n"
- + " @AppSearchDocument.Property int price;\n"
- + " @AppSearchDocument.Property boolean cat = false;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id final String id;\n"
+ + " @Document.LongProperty int price;\n"
+ + " @Document.BooleanProperty boolean cat = false;\n"
+ " public void setCat(boolean cat) {}\n"
- + " @AppSearchDocument.Property private final boolean dog;\n"
+ + " @Document.BooleanProperty private final boolean dog;\n"
+ " public boolean getDog() { return dog; }\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@Test
public void testDifferentTypeName() throws Exception {
Compilation compilation = compile(
- "@AppSearchDocument(name=\"DifferentType\")\n"
+ "@Document(name=\"DifferentType\")\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -380,15 +583,17 @@
public void testRepeatedFields() throws Exception {
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property List<String> listOfString;\n"
- + " @AppSearchDocument.Property Collection<Integer> setOfInt;\n"
- + " @AppSearchDocument.Property byte[][] repeatedByteArray;\n"
- + " @AppSearchDocument.Property byte[] byteArray;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty List<String> listOfString;\n"
+ + " @Document.LongProperty Collection<Integer> setOfInt;\n"
+ + " @Document.BytesProperty byte[][] repeatedByteArray;\n"
+ + " @Document.BytesProperty byte[] byteArray;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -396,15 +601,17 @@
public void testCardinality() throws Exception {
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property(required=true) List<String> repeatReq;\n"
- + " @AppSearchDocument.Property(required=false) List<String> repeatNoReq;\n"
- + " @AppSearchDocument.Property(required=true) Float req;\n"
- + " @AppSearchDocument.Property(required=false) Float noReq;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(required=true) List<String> repeatReq;\n"
+ + " @Document.StringProperty(required=false) List<String> repeatNoReq;\n"
+ + " @Document.DoubleProperty(required=true) Float req;\n"
+ + " @Document.DoubleProperty(required=false) Float noReq;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -413,19 +620,21 @@
// TODO(b/156296904): Uncomment Gift in this test when it's supported
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property String stringProp;\n"
- + " @AppSearchDocument.Property Integer integerProp;\n"
- + " @AppSearchDocument.Property Long longProp;\n"
- + " @AppSearchDocument.Property Float floatProp;\n"
- + " @AppSearchDocument.Property Double doubleProp;\n"
- + " @AppSearchDocument.Property Boolean booleanProp;\n"
- + " @AppSearchDocument.Property byte[] bytesProp;\n"
- //+ " @AppSearchDocument.Property Gift documentProp;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty String stringProp;\n"
+ + " @Document.LongProperty Integer integerProp;\n"
+ + " @Document.LongProperty Long longProp;\n"
+ + " @Document.DoubleProperty Float floatProp;\n"
+ + " @Document.DoubleProperty Double doubleProp;\n"
+ + " @Document.BooleanProperty Boolean booleanProp;\n"
+ + " @Document.BytesProperty byte[] bytesProp;\n"
+ //+ " @Document.Property Gift documentProp;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -435,13 +644,15 @@
// by using the integer constants directly.
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property(tokenizerType=0) String tokNone;\n"
- + " @AppSearchDocument.Property(tokenizerType=1) String tokPlain;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(tokenizerType=0) String tokNone;\n"
+ + " @Document.StringProperty(tokenizerType=1) String tokPlain;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -451,13 +662,15 @@
// by using the integer constants directly.
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property(indexingType=1, tokenizerType=100)\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(indexingType=1, tokenizerType=100)\n"
+ " String str;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining("Unknown tokenizer type 100");
+
+ assertThat(compilation).hadErrorContaining("Unknown tokenizer type 100");
}
@Test
@@ -466,14 +679,16 @@
// by using the integer constants directly.
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property(indexingType=0) String indexNone;\n"
- + " @AppSearchDocument.Property(indexingType=1) String indexExact;\n"
- + " @AppSearchDocument.Property(indexingType=2) String indexPrefix;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(indexingType=0) String indexNone;\n"
+ + " @Document.StringProperty(indexingType=1) String indexExact;\n"
+ + " @Document.StringProperty(indexingType=2) String indexPrefix;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -483,25 +698,29 @@
// by using the integer constants directly.
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property(indexingType=100, tokenizerType=1)\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(indexingType=100, tokenizerType=1)\n"
+ " String str;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining("Unknown indexing type 100");
+
+ assertThat(compilation).hadErrorContaining("Unknown indexing type 100");
}
@Test
public void testPropertyName() throws Exception {
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Property(name=\"newName\") String oldName;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(name=\"newName\") String oldName;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -511,146 +730,143 @@
Compilation compilation = compile(
"import java.util.*;\n"
+ "import androidx.appsearch.app.GenericDocument;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @Uri String uri;\n"
+ + " @Namespace String namespace;\n"
+ + " @Id String id;\n"
+ "\n"
+ " // Collections\n"
- + " @Property Collection<Long> collectLong;\n" // 1a
- + " @Property Collection<Integer> collectInteger;\n" // 1a
- + " @Property Collection<Double> collectDouble;\n" // 1a
- + " @Property Collection<Float> collectFloat;\n" // 1a
- + " @Property Collection<Boolean> collectBoolean;\n" // 1a
- + " @Property Collection<byte[]> collectByteArr;\n" // 1a
- + " @Property Collection<String> collectString;\n" // 1b
- + " @Property Collection<Gift> collectGift;\n" // 1c
+ + " @LongProperty Collection<Long> collectLong;\n" // 1a
+ + " @LongProperty Collection<Integer> collectInteger;\n" // 1a
+ + " @DoubleProperty Collection<Double> collectDouble;\n" // 1a
+ + " @DoubleProperty Collection<Float> collectFloat;\n" // 1a
+ + " @BooleanProperty Collection<Boolean> collectBoolean;\n" // 1a
+ + " @BytesProperty Collection<byte[]> collectByteArr;\n" // 1a
+ + " @StringProperty Collection<String> collectString;\n" // 1b
+ + " @DocumentProperty Collection<Gift> collectGift;\n" // 1c
+ "\n"
+ " // Arrays\n"
- + " @Property Long[] arrBoxLong;\n" // 2a
- + " @Property long[] arrUnboxLong;\n" // 2b
- + " @Property Integer[] arrBoxInteger;\n" // 2a
- + " @Property int[] arrUnboxInt;\n" // 2a
- + " @Property Double[] arrBoxDouble;\n" // 2a
- + " @Property double[] arrUnboxDouble;\n" // 2b
- + " @Property Float[] arrBoxFloat;\n" // 2a
- + " @Property float[] arrUnboxFloat;\n" // 2a
- + " @Property Boolean[] arrBoxBoolean;\n" // 2a
- + " @Property boolean[] arrUnboxBoolean;\n" // 2b
- + " @Property byte[][] arrUnboxByteArr;\n" // 2b
- + " @Property Byte[] boxByteArr;\n" // 2a
- + " @Property String[] arrString;\n" // 2b
- + " @Property Gift[] arrGift;\n" // 2c
+ + " @LongProperty Long[] arrBoxLong;\n" // 2a
+ + " @LongProperty long[] arrUnboxLong;\n" // 2b
+ + " @LongProperty Integer[] arrBoxInteger;\n" // 2a
+ + " @LongProperty int[] arrUnboxInt;\n" // 2a
+ + " @DoubleProperty Double[] arrBoxDouble;\n" // 2a
+ + " @DoubleProperty double[] arrUnboxDouble;\n" // 2b
+ + " @DoubleProperty Float[] arrBoxFloat;\n" // 2a
+ + " @DoubleProperty float[] arrUnboxFloat;\n" // 2a
+ + " @BooleanProperty Boolean[] arrBoxBoolean;\n" // 2a
+ + " @BooleanProperty boolean[] arrUnboxBoolean;\n" // 2b
+ + " @BytesProperty byte[][] arrUnboxByteArr;\n" // 2b
+ + " @BytesProperty Byte[] boxByteArr;\n" // 2a
+ + " @StringProperty String[] arrString;\n" // 2b
+ + " @DocumentProperty Gift[] arrGift;\n" // 2c
+ "\n"
+ " // Single values\n"
- + " @Property String string;\n" // 3a
- + " @Property Long boxLong;\n" // 3a
- + " @Property long unboxLong;\n" // 3b
- + " @Property Integer boxInteger;\n" // 3a
- + " @Property int unboxInt;\n" // 3b
- + " @Property Double boxDouble;\n" // 3a
- + " @Property double unboxDouble;\n" // 3b
- + " @Property Float boxFloat;\n" // 3a
- + " @Property float unboxFloat;\n" // 3b
- + " @Property Boolean boxBoolean;\n" // 3a
- + " @Property boolean unboxBoolean;\n" // 3b
- + " @Property byte[] unboxByteArr;\n" // 3a
- + " @Property Gift gift;\n" // 3c
+ + " @StringProperty String string;\n" // 3a
+ + " @LongProperty Long boxLong;\n" // 3a
+ + " @LongProperty long unboxLong;\n" // 3b
+ + " @LongProperty Integer boxInteger;\n" // 3a
+ + " @LongProperty int unboxInt;\n" // 3b
+ + " @DoubleProperty Double boxDouble;\n" // 3a
+ + " @DoubleProperty double unboxDouble;\n" // 3b
+ + " @DoubleProperty Float boxFloat;\n" // 3a
+ + " @DoubleProperty float unboxFloat;\n" // 3b
+ + " @BooleanProperty Boolean boxBoolean;\n" // 3a
+ + " @BooleanProperty boolean unboxBoolean;\n" // 3b
+ + " @BytesProperty byte[] unboxByteArr;\n" // 3a
+ + " @DocumentProperty Gift gift;\n" // 3c
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@Test
+ public void testPropertyAnnotation_invalidType() {
+ Compilation compilation = compile(
+ "import java.util.*;\n"
+ + "@Document\n"
+ + "public class Gift {\n"
+ + " @Namespace String namespace;\n"
+ + " @Id String id;\n"
+ + " @BooleanProperty String[] arrString;\n"
+ + "}\n");
+
+ assertThat(compilation).hadErrorContaining(
+ "Property Annotation androidx.appsearch.annotation.Document.BooleanProperty "
+ + "doesn't accept the data type of property field arrString");
+ }
+
+ @Test
public void testToGenericDocument_invalidTypes() {
Compilation compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @Uri String uri;\n"
- + " @Property Collection<Byte[]> collectBoxByteArr;\n" // 1x
+ + " @Namespace String namespace;\n"
+ + " @Id String id;\n"
+ + " @BytesProperty Collection<Byte[]> collectBoxByteArr;\n" // 1x
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+ assertThat(compilation).hadErrorContaining(
"Unhandled out property type (1x): java.util.Collection<java.lang.Byte[]>");
compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @Uri String uri;\n"
- + " @Property Collection<Byte> collectByte;\n" // 1x
+ + " @Namespace String namespace;\n"
+ + " @Id String id;\n"
+ + " @BytesProperty Collection<Byte> collectByte;\n" // 1x
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+ assertThat(compilation).hadErrorContaining(
"Unhandled out property type (1x): java.util.Collection<java.lang.Byte>");
compilation = compile(
"import java.util.*;\n"
- + "@AppSearchDocument\n"
+ + "@Document\n"
+ "public class Gift {\n"
- + " @Uri String uri;\n"
- + " @Property Collection<Object> collectObject;\n" // 1x
+ + " @Namespace String namespace;\n"
+ + " @Id String id;\n"
+ + " @BytesProperty Byte[][] arrBoxByteArr;\n" // 2x
+ "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Unhandled out property type (1x): java.util.Collection<java.lang.Object>");
-
- compilation = compile(
- "import java.util.*;\n"
- + "@AppSearchDocument\n"
- + "public class Gift {\n"
- + " @Uri String uri;\n"
- + " @Property Byte[][] arrBoxByteArr;\n" // 2x
- + "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
+ assertThat(compilation).hadErrorContaining(
"Unhandled out property type (2x): java.lang.Byte[][]");
-
- compilation = compile(
- "import java.util.*;\n"
- + "@AppSearchDocument\n"
- + "public class Gift {\n"
- + " @Uri String uri;\n"
- + " @Property Object[] arrObject;\n" // 2x
- + "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Unhandled out property type (2x): java.lang.Object[]");
-
- compilation = compile(
- "import java.util.*;\n"
- + "@AppSearchDocument\n"
- + "public class Gift {\n"
- + " @Uri String uri;\n"
- + " @Property Object object;\n" // 3x
- + "}\n");
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Unhandled out property type (3x): java.lang.Object");
}
@Test
public void testAllSpecialFields_field() throws Exception {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @AppSearchDocument.Namespace String namespace;\n"
- + " @AppSearchDocument.CreationTimestampMillis long creationTs;\n"
- + " @AppSearchDocument.TtlMillis int ttlMs;\n"
- + " @AppSearchDocument.Property int price;\n"
- + " @AppSearchDocument.Score int score;\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.CreationTimestampMillis long creationTs;\n"
+ + " @Document.TtlMillis int ttlMs;\n"
+ + " @Document.LongProperty int price;\n"
+ + " @Document.Score int score;\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@Test
public void testAllSpecialFields_getter() throws Exception {
Compilation compilation = compile(
- "@AppSearchDocument\n"
+ "@Document\n"
+ "public class Gift {\n"
- + " @AppSearchDocument.Uri private String uri;\n"
- + " @AppSearchDocument.Score private int score;\n"
- + " @AppSearchDocument.CreationTimestampMillis private long creationTs;\n"
- + " @AppSearchDocument.TtlMillis private int ttlMs;\n"
- + " @AppSearchDocument.Property private int price;\n"
- + " public String getUri() { return uri; }\n"
- + " public void setUri(String uri) { this.uri = uri; }\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id private String id;\n"
+ + " @Document.Score private int score;\n"
+ + " @Document.CreationTimestampMillis private long creationTs;\n"
+ + " @Document.TtlMillis private int ttlMs;\n"
+ + " @Document.LongProperty private int price;\n"
+ + " public String getId() { return id; }\n"
+ + " public void setId(String id) { this.id = id; }\n"
+ + " public String getNamespace() { return namespace; }\n"
+ + " public void setNamespace(String namespace) {\n"
+ + " this.namespace = namespace;\n"
+ + " }\n"
+ " public int getScore() { return score; }\n"
+ " public void setScore(int score) { this.score = score; }\n"
+ " public long getCreationTs() { return creationTs; }\n"
@@ -662,7 +878,30 @@
+ " public int getPrice() { return price; }\n"
+ " public void setPrice(int price) { this.price = price; }\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
+ public void testAutoValueDocument() throws IOException {
+ Compilation compilation = compile(
+ "import com.google.auto.value.AutoValue;\n"
+ + "import com.google.auto.value.AutoValue.*;\n"
+ + "@Document\n"
+ + "@AutoValue\n"
+ + "public abstract class Gift {\n"
+ + " @CopyAnnotations @Document.Id abstract String id();\n"
+ + " @CopyAnnotations @Document.Namespace abstract String namespace();\n"
+ + " @CopyAnnotations\n"
+ + " @Document.StringProperty abstract String property();\n"
+ + " public static Gift create(String id, String namespace, String"
+ + " property) {\n"
+ + " return new AutoValue_Gift(id, namespace, property);\n"
+ + " }\n"
+ + "}\n");
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift.java");
}
@@ -672,13 +911,15 @@
"import java.util.*;\n"
+ "import androidx.appsearch.app.GenericDocument;\n"
+ "public class Gift {\n"
- + " @AppSearchDocument\n"
+ + " @Document\n"
+ " public static class InnerGift{\n"
- + " @AppSearchDocument.Uri String uri;\n"
- + " @Property String[] arrString;\n" // 2b
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @StringProperty String[] arrString;\n" // 2b
+ " }\n"
+ "}\n");
- CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+
+ assertThat(compilation).succeededWithoutWarnings();
checkEqualsGolden("Gift$$__InnerGift.java");
}
@@ -688,8 +929,8 @@
private Compilation compile(String classSimpleName, String classBody) {
String src = "package com.example.appsearch;\n"
- + "import androidx.appsearch.annotation.AppSearchDocument;\n"
- + "import androidx.appsearch.annotation.AppSearchDocument.*;\n"
+ + "import androidx.appsearch.annotation.Document;\n"
+ + "import androidx.appsearch.annotation.Document.*;\n"
+ classBody;
JavaFileObject jfo = JavaFileObjects.forSourceString(
"com.example.appsearch." + classSimpleName,
@@ -702,7 +943,7 @@
AppSearchCompiler.OUTPUT_DIR_OPTION,
mGenFilesDir.getAbsolutePath());
return Compiler.javac()
- .withProcessors(new AppSearchCompiler())
+ .withProcessors(new AppSearchCompiler(), new AutoValueProcessor())
.withOptions(outputDirFlag)
.compile(jfo);
}
@@ -722,7 +963,8 @@
// Get the actual file contents
File actualPackageDir = new File(mGenFilesDir, "com/example/appsearch");
- File actualPath = new File(actualPackageDir, CodeGenerator.GEN_CLASS_PREFIX + className);
+ File actualPath =
+ new File(actualPackageDir, IntrospectionHelper.GEN_CLASS_PREFIX + className);
Truth.assertWithMessage("Path " + actualPath + " is not a file")
.that(actualPath.isFile()).isTrue();
String actual = Files.asCharSource(actualPath, StandardCharsets.UTF_8).read();
@@ -751,4 +993,16 @@
Truth.assertThat(actual).isEqualTo(expected);
}
}
+
+ private void checkResultContains(String className, String content) throws IOException {
+ // Get the actual file contents
+ File actualPackageDir = new File(mGenFilesDir, "com/example/appsearch");
+ File actualPath =
+ new File(actualPackageDir, IntrospectionHelper.GEN_CLASS_PREFIX + className);
+ Truth.assertWithMessage("Path " + actualPath + " is not a file")
+ .that(actualPath.isFile()).isTrue();
+ String actual = Files.asCharSource(actualPath, StandardCharsets.UTF_8).read();
+
+ Truth.assertThat(actual).contains(content);
+ }
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
index b256fa5..47ce7aa 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
@@ -1,7 +1,7 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Boolean;
@@ -11,92 +11,75 @@
import java.lang.Long;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("stringProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("stringProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("integerProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("integerProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("longProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("longProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("floatProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("floatProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("doubleProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("doubleProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("booleanProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("booleanProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("bytesProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("bytesProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- String stringPropCopy = dataClass.stringProp;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ String stringPropCopy = document.stringProp;
if (stringPropCopy != null) {
builder.setPropertyString("stringProp", stringPropCopy);
}
- Integer integerPropCopy = dataClass.integerProp;
+ Integer integerPropCopy = document.integerProp;
if (integerPropCopy != null) {
builder.setPropertyLong("integerProp", integerPropCopy);
}
- Long longPropCopy = dataClass.longProp;
+ Long longPropCopy = document.longProp;
if (longPropCopy != null) {
builder.setPropertyLong("longProp", longPropCopy);
}
- Float floatPropCopy = dataClass.floatProp;
+ Float floatPropCopy = document.floatProp;
if (floatPropCopy != null) {
builder.setPropertyDouble("floatProp", floatPropCopy);
}
- Double doublePropCopy = dataClass.doubleProp;
+ Double doublePropCopy = document.doubleProp;
if (doublePropCopy != null) {
builder.setPropertyDouble("doubleProp", doublePropCopy);
}
- Boolean booleanPropCopy = dataClass.booleanProp;
+ Boolean booleanPropCopy = document.booleanProp;
if (booleanPropCopy != null) {
builder.setPropertyBoolean("booleanProp", booleanPropCopy);
}
- byte[] bytesPropCopy = dataClass.bytesProp;
+ byte[] bytesPropCopy = document.bytesProp;
if (bytesPropCopy != null) {
builder.setPropertyBytes("bytesProp", bytesPropCopy);
}
@@ -105,7 +88,8 @@
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
String[] stringPropCopy = genericDoc.getPropertyStringArray("stringProp");
String stringPropConv = null;
if (stringPropCopy != null && stringPropCopy.length != 0) {
@@ -141,15 +125,16 @@
if (bytesPropCopy != null && bytesPropCopy.length != 0) {
bytesPropConv = bytesPropCopy[0];
}
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.stringProp = stringPropConv;
- dataClass.integerProp = integerPropConv;
- dataClass.longProp = longPropConv;
- dataClass.floatProp = floatPropConv;
- dataClass.doubleProp = doublePropConv;
- dataClass.booleanProp = booleanPropConv;
- dataClass.bytesProp = bytesPropConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.stringProp = stringPropConv;
+ document.integerProp = integerPropConv;
+ document.longProp = longPropConv;
+ document.floatProp = floatPropConv;
+ document.doubleProp = doublePropConv;
+ document.booleanProp = booleanPropConv;
+ document.bytesProp = bytesPropConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_field.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_field.JAVA
index e315345..1814a8e 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_field.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_field.JAVA
@@ -1,62 +1,57 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- String namespaceCopy = dataClass.namespace;
- if (namespaceCopy != null) {
- builder.setNamespace(namespaceCopy);
- }
- builder.setCreationTimestampMillis(dataClass.creationTs);
- builder.setTtlMillis(dataClass.ttlMs);
- builder.setScore(dataClass.score);
- builder.setPropertyLong("price", dataClass.price);
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ builder.setCreationTimestampMillis(document.creationTs);
+ builder.setTtlMillis(document.ttlMs);
+ builder.setScore(document.score);
+ builder.setPropertyLong("price", document.price);
return builder.build();
}
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
String namespaceConv = genericDoc.getNamespace();
long creationTsConv = genericDoc.getCreationTimestampMillis();
long ttlMsConv = genericDoc.getTtlMillis();
int scoreConv = genericDoc.getScore();
int priceConv = (int) genericDoc.getPropertyLong("price");
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.namespace = namespaceConv;
- dataClass.creationTs = creationTsConv;
- dataClass.ttlMs = ttlMsConv;
- dataClass.price = priceConv;
- dataClass.score = scoreConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.creationTs = creationTsConv;
+ document.ttlMs = ttlMsConv;
+ document.price = priceConv;
+ document.score = scoreConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_getter.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_getter.JAVA
index 1cf9253..e442931 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_getter.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_getter.JAVA
@@ -1,56 +1,57 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.getUri(), SCHEMA_TYPE);
- builder.setCreationTimestampMillis(dataClass.getCreationTs());
- builder.setTtlMillis(dataClass.getTtlMs());
- builder.setScore(dataClass.getScore());
- builder.setPropertyLong("price", dataClass.getPrice());
+ new GenericDocument.Builder<>(document.namespace, document.getId(), SCHEMA_NAME);
+ builder.setCreationTimestampMillis(document.getCreationTs());
+ builder.setTtlMillis(document.getTtlMs());
+ builder.setScore(document.getScore());
+ builder.setPropertyLong("price", document.getPrice());
return builder.build();
}
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
long creationTsConv = genericDoc.getCreationTimestampMillis();
long ttlMsConv = genericDoc.getTtlMillis();
int scoreConv = genericDoc.getScore();
int priceConv = (int) genericDoc.getPropertyLong("price");
- Gift dataClass = new Gift();
- dataClass.setUri(uriConv);
- dataClass.setScore(scoreConv);
- dataClass.setCreationTs(creationTsConv);
- dataClass.setTtlMs(ttlMsConv);
- dataClass.setPrice(priceConv);
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.setId(idConv);
+ document.setScore(scoreConv);
+ document.setCreationTs(creationTsConv);
+ document.setTtlMs(ttlMsConv);
+ document.setPrice(priceConv);
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAutoValueDocument.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAutoValueDocument.JAVA
new file mode 100644
index 0000000..47e6df5
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAutoValueDocument.JAVA
@@ -0,0 +1,54 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DocumentClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Override;
+import java.lang.String;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
+
+ @Override
+ public String getSchemaName() {
+ return SCHEMA_NAME;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("property")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(document.namespace(), document.id(), SCHEMA_NAME);
+ String propertyCopy = document.property();
+ if (propertyCopy != null) {
+ builder.setPropertyString("property", propertyCopy);
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
+ String[] propertyCopy = genericDoc.getPropertyStringArray("property");
+ String propertyConv = null;
+ if (propertyCopy != null && propertyCopy.length != 0) {
+ propertyConv = propertyCopy[0];
+ }
+ Gift document = Gift.create(idConv, namespaceConv, propertyConv);
+ return document;
+ }
+}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
index 13f4f18..1e87ce2 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
@@ -1,7 +1,7 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Float;
@@ -9,64 +9,58 @@
import java.lang.String;
import java.util.Arrays;
import java.util.List;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatReq")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("repeatReq")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatNoReq")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("repeatNoReq")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("req")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("req")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("noReq")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("noReq")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- List<String> repeatReqCopy = dataClass.repeatReq;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ List<String> repeatReqCopy = document.repeatReq;
if (repeatReqCopy != null) {
String[] repeatReqConv = repeatReqCopy.toArray(new String[0]);
builder.setPropertyString("repeatReq", repeatReqConv);
}
- List<String> repeatNoReqCopy = dataClass.repeatNoReq;
+ List<String> repeatNoReqCopy = document.repeatNoReq;
if (repeatNoReqCopy != null) {
String[] repeatNoReqConv = repeatNoReqCopy.toArray(new String[0]);
builder.setPropertyString("repeatNoReq", repeatNoReqConv);
}
- Float reqCopy = dataClass.req;
+ Float reqCopy = document.req;
if (reqCopy != null) {
builder.setPropertyDouble("req", reqCopy);
}
- Float noReqCopy = dataClass.noReq;
+ Float noReqCopy = document.noReq;
if (noReqCopy != null) {
builder.setPropertyDouble("noReq", noReqCopy);
}
@@ -75,7 +69,8 @@
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
String[] repeatReqCopy = genericDoc.getPropertyStringArray("repeatReq");
List<String> repeatReqConv = null;
if (repeatReqCopy != null) {
@@ -96,12 +91,13 @@
if (noReqCopy != null && noReqCopy.length != 0) {
noReqConv = (float) noReqCopy[0];
}
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.repeatReq = repeatReqConv;
- dataClass.repeatNoReq = repeatNoReqConv;
- dataClass.req = reqConv;
- dataClass.noReq = noReqConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.repeatReq = repeatReqConv;
+ document.repeatNoReq = repeatNoReqConv;
+ document.req = reqConv;
+ document.noReq = noReqConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
index 2c55500..6441fce 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
@@ -1,38 +1,42 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "DifferentType";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "DifferentType";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
return builder.build();
}
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- return dataClass;
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testGetterAndSetterFunctions_withFieldName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testGetterAndSetterFunctions_withFieldName.JAVA
new file mode 100644
index 0000000..8b49559
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testGetterAndSetterFunctions_withFieldName.JAVA
@@ -0,0 +1,48 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DocumentClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Override;
+import java.lang.String;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
+
+ @Override
+ public String getSchemaName() {
+ return SCHEMA_NAME;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .build();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ builder.setPropertyLong("price", document.price());
+ return builder.build();
+ }
+
+ @Override
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
+ int priceConv = (int) genericDoc.getPropertyLong("price");
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.price(priceConv);
+ return document;
+ }
+}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
index 87283d4..662376d 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
@@ -1,57 +1,56 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexNone")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("indexNone")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexExact")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("indexExact")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexPrefix")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("indexPrefix")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- String indexNoneCopy = dataClass.indexNone;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ String indexNoneCopy = document.indexNone;
if (indexNoneCopy != null) {
builder.setPropertyString("indexNone", indexNoneCopy);
}
- String indexExactCopy = dataClass.indexExact;
+ String indexExactCopy = document.indexExact;
if (indexExactCopy != null) {
builder.setPropertyString("indexExact", indexExactCopy);
}
- String indexPrefixCopy = dataClass.indexPrefix;
+ String indexPrefixCopy = document.indexPrefix;
if (indexPrefixCopy != null) {
builder.setPropertyString("indexPrefix", indexPrefixCopy);
}
@@ -60,7 +59,8 @@
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
String[] indexNoneCopy = genericDoc.getPropertyStringArray("indexNone");
String indexNoneConv = null;
if (indexNoneCopy != null && indexNoneCopy.length != 0) {
@@ -76,11 +76,12 @@
if (indexPrefixCopy != null && indexPrefixCopy.length != 0) {
indexPrefixConv = indexPrefixCopy[0];
}
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.indexNone = indexNoneConv;
- dataClass.indexExact = indexExactConv;
- dataClass.indexPrefix = indexPrefixConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.indexNone = indexNoneConv;
+ document.indexExact = indexExactConv;
+ document.indexPrefix = indexPrefixConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA
index 8900092..08987f0 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA
@@ -1,37 +1,38 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift$$__InnerGift implements DataClassFactory<Gift.InnerGift> {
- private static final String SCHEMA_TYPE = "InnerGift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift$$__InnerGift implements DocumentClassFactory<Gift.InnerGift> {
+ public static final String SCHEMA_NAME = "InnerGift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("arrString")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift.InnerGift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift.InnerGift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- String[] arrStringCopy = dataClass.arrString;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ String[] arrStringCopy = document.arrString;
if (arrStringCopy != null) {
builder.setPropertyString("arrString", arrStringCopy);
}
@@ -40,11 +41,13 @@
@Override
public Gift.InnerGift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
String[] arrStringConv = genericDoc.getPropertyStringArray("arrString");
- Gift.InnerGift dataClass = new Gift.InnerGift();
- dataClass.uri = uriConv;
- dataClass.arrString = arrStringConv;
- return dataClass;
+ Gift.InnerGift document = new Gift.InnerGift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.arrString = arrStringConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
index d843153..155394b 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
@@ -1,37 +1,38 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("newName")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("newName")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- String oldNameCopy = dataClass.oldName;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ String oldNameCopy = document.oldName;
if (oldNameCopy != null) {
builder.setPropertyString("newName", oldNameCopy);
}
@@ -40,15 +41,17 @@
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
String[] oldNameCopy = genericDoc.getPropertyStringArray("newName");
String oldNameConv = null;
if (oldNameCopy != null && oldNameCopy.length != 0) {
oldNameConv = oldNameCopy[0];
}
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.oldName = oldNameConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.oldName = oldNameConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
index 890d43d..9ab9158 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
@@ -1,47 +1,48 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- builder.setPropertyLong("price", dataClass.getPrice());
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ builder.setPropertyLong("price", document.getPrice());
return builder.build();
}
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
int priceConv = (int) genericDoc.getPropertyLong("price");
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.setPrice(priceConv);
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.setPrice(priceConv);
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
index be28a52..e12c97f 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
@@ -1,7 +1,7 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Integer;
@@ -11,55 +11,47 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("listOfString")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("listOfString")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("setOfInt")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("setOfInt")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatedByteArray")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("repeatedByteArray")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("byteArray")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("byteArray")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- List<String> listOfStringCopy = dataClass.listOfString;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ List<String> listOfStringCopy = document.listOfString;
if (listOfStringCopy != null) {
String[] listOfStringConv = listOfStringCopy.toArray(new String[0]);
builder.setPropertyString("listOfString", listOfStringConv);
}
- Collection<Integer> setOfIntCopy = dataClass.setOfInt;
+ Collection<Integer> setOfIntCopy = document.setOfInt;
if (setOfIntCopy != null) {
long[] setOfIntConv = new long[setOfIntCopy.size()];
int i = 0;
@@ -68,11 +60,11 @@
}
builder.setPropertyLong("setOfInt", setOfIntConv);
}
- byte[][] repeatedByteArrayCopy = dataClass.repeatedByteArray;
+ byte[][] repeatedByteArrayCopy = document.repeatedByteArray;
if (repeatedByteArrayCopy != null) {
builder.setPropertyBytes("repeatedByteArray", repeatedByteArrayCopy);
}
- byte[] byteArrayCopy = dataClass.byteArray;
+ byte[] byteArrayCopy = document.byteArray;
if (byteArrayCopy != null) {
builder.setPropertyBytes("byteArray", byteArrayCopy);
}
@@ -81,7 +73,8 @@
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
String[] listOfStringCopy = genericDoc.getPropertyStringArray("listOfString");
List<String> listOfStringConv = null;
if (listOfStringCopy != null) {
@@ -101,12 +94,13 @@
if (byteArrayCopy != null && byteArrayCopy.length != 0) {
byteArrayConv = byteArrayCopy[0];
}
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.listOfString = listOfStringConv;
- dataClass.setOfInt = setOfIntConv;
- dataClass.repeatedByteArray = repeatedByteArrayConv;
- dataClass.byteArray = byteArrayConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.listOfString = listOfStringConv;
+ document.setOfInt = setOfIntConv;
+ document.repeatedByteArray = repeatedByteArrayConv;
+ document.byteArray = byteArrayConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
index 8499df6..49a157ac 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
@@ -1,63 +1,58 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("cat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("cat")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("dog")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("dog")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- builder.setPropertyLong("price", dataClass.price);
- builder.setPropertyBoolean("cat", dataClass.cat);
- builder.setPropertyBoolean("dog", dataClass.getDog());
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ builder.setPropertyLong("price", document.price);
+ builder.setPropertyBoolean("cat", document.cat);
+ builder.setPropertyBoolean("dog", document.getDog());
return builder.build();
}
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
int priceConv = (int) genericDoc.getPropertyLong("price");
boolean catConv = genericDoc.getPropertyBoolean("cat");
boolean dogConv = genericDoc.getPropertyBoolean("dog");
- Gift dataClass = new Gift(dogConv, uriConv);
- dataClass.price = priceConv;
- dataClass.cat = catConv;
- return dataClass;
+ Gift document = new Gift(dogConv, idConv, namespaceConv);
+ document.namespace = namespaceConv;
+ document.price = priceConv;
+ document.cat = catConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_allSupportedTypes.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_allSupportedTypes.JAVA
index d3ee29b..8b8c007 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_allSupportedTypes.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_allSupportedTypes.JAVA
@@ -1,8 +1,7 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
-import androidx.appsearch.app.DataClassFactoryRegistry;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Boolean;
@@ -17,239 +16,139 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("collectLong")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectInteger")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("collectInteger")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("collectDouble")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("collectFloat")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("collectBoolean")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("collectByteArr")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectString")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("collectString")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectGift")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
- .setSchemaType(DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class).getSchemaType())
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder("collectGift", $$__AppSearch__Gift.SCHEMA_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("arrBoxLong")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("arrUnboxLong")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxInteger")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("arrBoxInteger")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxInt")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("arrUnboxInt")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("arrBoxDouble")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("arrUnboxDouble")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("arrBoxFloat")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("arrUnboxFloat")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("arrBoxBoolean")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("arrUnboxBoolean")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("arrUnboxByteArr")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("boxByteArr")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("arrString")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrGift")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
- .setSchemaType(DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class).getSchemaType())
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder("arrGift", $$__AppSearch__Gift.SCHEMA_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("string")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("string")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("boxLong")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("unboxLong")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxInteger")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("boxInteger")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxInt")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("unboxInt")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("boxDouble")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("unboxDouble")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("boxFloat")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("unboxFloat")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("boxBoolean")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("unboxBoolean")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .addProperty(new AppSearchSchema.BytesPropertyConfig.Builder("unboxByteArr")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("gift")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
- .setSchemaType(DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class).getSchemaType())
+ .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder("gift", $$__AppSearch__Gift.SCHEMA_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- Collection<Long> collectLongCopy = dataClass.collectLong;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ Collection<Long> collectLongCopy = document.collectLong;
if (collectLongCopy != null) {
long[] collectLongConv = new long[collectLongCopy.size()];
int i = 0;
@@ -258,7 +157,7 @@
}
builder.setPropertyLong("collectLong", collectLongConv);
}
- Collection<Integer> collectIntegerCopy = dataClass.collectInteger;
+ Collection<Integer> collectIntegerCopy = document.collectInteger;
if (collectIntegerCopy != null) {
long[] collectIntegerConv = new long[collectIntegerCopy.size()];
int i = 0;
@@ -267,7 +166,7 @@
}
builder.setPropertyLong("collectInteger", collectIntegerConv);
}
- Collection<Double> collectDoubleCopy = dataClass.collectDouble;
+ Collection<Double> collectDoubleCopy = document.collectDouble;
if (collectDoubleCopy != null) {
double[] collectDoubleConv = new double[collectDoubleCopy.size()];
int i = 0;
@@ -276,7 +175,7 @@
}
builder.setPropertyDouble("collectDouble", collectDoubleConv);
}
- Collection<Float> collectFloatCopy = dataClass.collectFloat;
+ Collection<Float> collectFloatCopy = document.collectFloat;
if (collectFloatCopy != null) {
double[] collectFloatConv = new double[collectFloatCopy.size()];
int i = 0;
@@ -285,7 +184,7 @@
}
builder.setPropertyDouble("collectFloat", collectFloatConv);
}
- Collection<Boolean> collectBooleanCopy = dataClass.collectBoolean;
+ Collection<Boolean> collectBooleanCopy = document.collectBoolean;
if (collectBooleanCopy != null) {
boolean[] collectBooleanConv = new boolean[collectBooleanCopy.size()];
int i = 0;
@@ -294,7 +193,7 @@
}
builder.setPropertyBoolean("collectBoolean", collectBooleanConv);
}
- Collection<byte[]> collectByteArrCopy = dataClass.collectByteArr;
+ Collection<byte[]> collectByteArrCopy = document.collectByteArr;
if (collectByteArrCopy != null) {
byte[][] collectByteArrConv = new byte[collectByteArrCopy.size()][];
int i = 0;
@@ -303,22 +202,21 @@
}
builder.setPropertyBytes("collectByteArr", collectByteArrConv);
}
- Collection<String> collectStringCopy = dataClass.collectString;
+ Collection<String> collectStringCopy = document.collectString;
if (collectStringCopy != null) {
String[] collectStringConv = collectStringCopy.toArray(new String[0]);
builder.setPropertyString("collectString", collectStringConv);
}
- Collection<Gift> collectGiftCopy = dataClass.collectGift;
+ Collection<Gift> collectGiftCopy = document.collectGift;
if (collectGiftCopy != null) {
GenericDocument[] collectGiftConv = new GenericDocument[collectGiftCopy.size()];
- DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
int i = 0;
for (Gift item : collectGiftCopy) {
- collectGiftConv[i++] = factory.toGenericDocument(item);
+ collectGiftConv[i++] = GenericDocument.fromDocumentClass(item);
}
builder.setPropertyDocument("collectGift", collectGiftConv);
}
- Long[] arrBoxLongCopy = dataClass.arrBoxLong;
+ Long[] arrBoxLongCopy = document.arrBoxLong;
if (arrBoxLongCopy != null) {
long[] arrBoxLongConv = new long[arrBoxLongCopy.length];
for (int i = 0 ; i < arrBoxLongCopy.length ; i++) {
@@ -326,11 +224,11 @@
}
builder.setPropertyLong("arrBoxLong", arrBoxLongConv);
}
- long[] arrUnboxLongCopy = dataClass.arrUnboxLong;
+ long[] arrUnboxLongCopy = document.arrUnboxLong;
if (arrUnboxLongCopy != null) {
builder.setPropertyLong("arrUnboxLong", arrUnboxLongCopy);
}
- Integer[] arrBoxIntegerCopy = dataClass.arrBoxInteger;
+ Integer[] arrBoxIntegerCopy = document.arrBoxInteger;
if (arrBoxIntegerCopy != null) {
long[] arrBoxIntegerConv = new long[arrBoxIntegerCopy.length];
for (int i = 0 ; i < arrBoxIntegerCopy.length ; i++) {
@@ -338,7 +236,7 @@
}
builder.setPropertyLong("arrBoxInteger", arrBoxIntegerConv);
}
- int[] arrUnboxIntCopy = dataClass.arrUnboxInt;
+ int[] arrUnboxIntCopy = document.arrUnboxInt;
if (arrUnboxIntCopy != null) {
long[] arrUnboxIntConv = new long[arrUnboxIntCopy.length];
for (int i = 0 ; i < arrUnboxIntCopy.length ; i++) {
@@ -346,7 +244,7 @@
}
builder.setPropertyLong("arrUnboxInt", arrUnboxIntConv);
}
- Double[] arrBoxDoubleCopy = dataClass.arrBoxDouble;
+ Double[] arrBoxDoubleCopy = document.arrBoxDouble;
if (arrBoxDoubleCopy != null) {
double[] arrBoxDoubleConv = new double[arrBoxDoubleCopy.length];
for (int i = 0 ; i < arrBoxDoubleCopy.length ; i++) {
@@ -354,11 +252,11 @@
}
builder.setPropertyDouble("arrBoxDouble", arrBoxDoubleConv);
}
- double[] arrUnboxDoubleCopy = dataClass.arrUnboxDouble;
+ double[] arrUnboxDoubleCopy = document.arrUnboxDouble;
if (arrUnboxDoubleCopy != null) {
builder.setPropertyDouble("arrUnboxDouble", arrUnboxDoubleCopy);
}
- Float[] arrBoxFloatCopy = dataClass.arrBoxFloat;
+ Float[] arrBoxFloatCopy = document.arrBoxFloat;
if (arrBoxFloatCopy != null) {
double[] arrBoxFloatConv = new double[arrBoxFloatCopy.length];
for (int i = 0 ; i < arrBoxFloatCopy.length ; i++) {
@@ -366,7 +264,7 @@
}
builder.setPropertyDouble("arrBoxFloat", arrBoxFloatConv);
}
- float[] arrUnboxFloatCopy = dataClass.arrUnboxFloat;
+ float[] arrUnboxFloatCopy = document.arrUnboxFloat;
if (arrUnboxFloatCopy != null) {
double[] arrUnboxFloatConv = new double[arrUnboxFloatCopy.length];
for (int i = 0 ; i < arrUnboxFloatCopy.length ; i++) {
@@ -374,7 +272,7 @@
}
builder.setPropertyDouble("arrUnboxFloat", arrUnboxFloatConv);
}
- Boolean[] arrBoxBooleanCopy = dataClass.arrBoxBoolean;
+ Boolean[] arrBoxBooleanCopy = document.arrBoxBoolean;
if (arrBoxBooleanCopy != null) {
boolean[] arrBoxBooleanConv = new boolean[arrBoxBooleanCopy.length];
for (int i = 0 ; i < arrBoxBooleanCopy.length ; i++) {
@@ -382,15 +280,15 @@
}
builder.setPropertyBoolean("arrBoxBoolean", arrBoxBooleanConv);
}
- boolean[] arrUnboxBooleanCopy = dataClass.arrUnboxBoolean;
+ boolean[] arrUnboxBooleanCopy = document.arrUnboxBoolean;
if (arrUnboxBooleanCopy != null) {
builder.setPropertyBoolean("arrUnboxBoolean", arrUnboxBooleanCopy);
}
- byte[][] arrUnboxByteArrCopy = dataClass.arrUnboxByteArr;
+ byte[][] arrUnboxByteArrCopy = document.arrUnboxByteArr;
if (arrUnboxByteArrCopy != null) {
builder.setPropertyBytes("arrUnboxByteArr", arrUnboxByteArrCopy);
}
- Byte[] boxByteArrCopy = dataClass.boxByteArr;
+ Byte[] boxByteArrCopy = document.boxByteArr;
if (boxByteArrCopy != null) {
byte[] boxByteArrConv = new byte[boxByteArrCopy.length];
for (int i = 0 ; i < boxByteArrCopy.length ; i++) {
@@ -398,55 +296,54 @@
}
builder.setPropertyBytes("boxByteArr", boxByteArrConv);
}
- String[] arrStringCopy = dataClass.arrString;
+ String[] arrStringCopy = document.arrString;
if (arrStringCopy != null) {
builder.setPropertyString("arrString", arrStringCopy);
}
- Gift[] arrGiftCopy = dataClass.arrGift;
+ Gift[] arrGiftCopy = document.arrGift;
if (arrGiftCopy != null) {
GenericDocument[] arrGiftConv = new GenericDocument[arrGiftCopy.length];
- DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
for (int i = 0; i < arrGiftConv.length; i++) {
- arrGiftConv[i] = factory.toGenericDocument(arrGiftCopy[i]);
+ arrGiftConv[i] = GenericDocument.fromDocumentClass(arrGiftCopy[i]);
}
builder.setPropertyDocument("arrGift", arrGiftConv);
}
- String stringCopy = dataClass.string;
+ String stringCopy = document.string;
if (stringCopy != null) {
builder.setPropertyString("string", stringCopy);
}
- Long boxLongCopy = dataClass.boxLong;
+ Long boxLongCopy = document.boxLong;
if (boxLongCopy != null) {
builder.setPropertyLong("boxLong", boxLongCopy);
}
- builder.setPropertyLong("unboxLong", dataClass.unboxLong);
- Integer boxIntegerCopy = dataClass.boxInteger;
+ builder.setPropertyLong("unboxLong", document.unboxLong);
+ Integer boxIntegerCopy = document.boxInteger;
if (boxIntegerCopy != null) {
builder.setPropertyLong("boxInteger", boxIntegerCopy);
}
- builder.setPropertyLong("unboxInt", dataClass.unboxInt);
- Double boxDoubleCopy = dataClass.boxDouble;
+ builder.setPropertyLong("unboxInt", document.unboxInt);
+ Double boxDoubleCopy = document.boxDouble;
if (boxDoubleCopy != null) {
builder.setPropertyDouble("boxDouble", boxDoubleCopy);
}
- builder.setPropertyDouble("unboxDouble", dataClass.unboxDouble);
- Float boxFloatCopy = dataClass.boxFloat;
+ builder.setPropertyDouble("unboxDouble", document.unboxDouble);
+ Float boxFloatCopy = document.boxFloat;
if (boxFloatCopy != null) {
builder.setPropertyDouble("boxFloat", boxFloatCopy);
}
- builder.setPropertyDouble("unboxFloat", dataClass.unboxFloat);
- Boolean boxBooleanCopy = dataClass.boxBoolean;
+ builder.setPropertyDouble("unboxFloat", document.unboxFloat);
+ Boolean boxBooleanCopy = document.boxBoolean;
if (boxBooleanCopy != null) {
builder.setPropertyBoolean("boxBoolean", boxBooleanCopy);
}
- builder.setPropertyBoolean("unboxBoolean", dataClass.unboxBoolean);
- byte[] unboxByteArrCopy = dataClass.unboxByteArr;
+ builder.setPropertyBoolean("unboxBoolean", document.unboxBoolean);
+ byte[] unboxByteArrCopy = document.unboxByteArr;
if (unboxByteArrCopy != null) {
builder.setPropertyBytes("unboxByteArr", unboxByteArrCopy);
}
- Gift giftCopy = dataClass.gift;
+ Gift giftCopy = document.gift;
if (giftCopy != null) {
- GenericDocument giftConv = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class).toGenericDocument(giftCopy);
+ GenericDocument giftConv = GenericDocument.fromDocumentClass(giftCopy);
builder.setPropertyDocument("gift", giftConv);
}
return builder.build();
@@ -454,7 +351,8 @@
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
long[] collectLongCopy = genericDoc.getPropertyLongArray("collectLong");
List<Long> collectLongConv = null;
if (collectLongCopy != null) {
@@ -511,10 +409,9 @@
GenericDocument[] collectGiftCopy = genericDoc.getPropertyDocumentArray("collectGift");
List<Gift> collectGiftConv = null;
if (collectGiftCopy != null) {
- DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
collectGiftConv = new ArrayList<>(collectGiftCopy.length);
for (int i = 0; i < collectGiftCopy.length; i++) {
- collectGiftConv.add(factory.fromGenericDocument(collectGiftCopy[i]));
+ collectGiftConv.add(collectGiftCopy[i].toDocumentClass(Gift.class));
}
}
long[] arrBoxLongCopy = genericDoc.getPropertyLongArray("arrBoxLong");
@@ -590,9 +487,8 @@
Gift[] arrGiftConv = null;
if (arrGiftCopy != null) {
arrGiftConv = new Gift[arrGiftCopy.length];
- DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
for (int i = 0; i < arrGiftCopy.length; i++) {
- arrGiftConv[i] = factory.fromGenericDocument(arrGiftCopy[i]);
+ arrGiftConv[i] = arrGiftCopy[i].toDocumentClass(Gift.class);
}
}
String[] stringCopy = genericDoc.getPropertyStringArray("string");
@@ -638,45 +534,46 @@
GenericDocument giftCopy = genericDoc.getPropertyDocument("gift");
Gift giftConv = null;
if (giftCopy != null) {
- giftConv = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class).fromGenericDocument(giftCopy);
+ giftConv = giftCopy.toDocumentClass(Gift.class);
}
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.collectLong = collectLongConv;
- dataClass.collectInteger = collectIntegerConv;
- dataClass.collectDouble = collectDoubleConv;
- dataClass.collectFloat = collectFloatConv;
- dataClass.collectBoolean = collectBooleanConv;
- dataClass.collectByteArr = collectByteArrConv;
- dataClass.collectString = collectStringConv;
- dataClass.collectGift = collectGiftConv;
- dataClass.arrBoxLong = arrBoxLongConv;
- dataClass.arrUnboxLong = arrUnboxLongConv;
- dataClass.arrBoxInteger = arrBoxIntegerConv;
- dataClass.arrUnboxInt = arrUnboxIntConv;
- dataClass.arrBoxDouble = arrBoxDoubleConv;
- dataClass.arrUnboxDouble = arrUnboxDoubleConv;
- dataClass.arrBoxFloat = arrBoxFloatConv;
- dataClass.arrUnboxFloat = arrUnboxFloatConv;
- dataClass.arrBoxBoolean = arrBoxBooleanConv;
- dataClass.arrUnboxBoolean = arrUnboxBooleanConv;
- dataClass.arrUnboxByteArr = arrUnboxByteArrConv;
- dataClass.boxByteArr = boxByteArrConv;
- dataClass.arrString = arrStringConv;
- dataClass.arrGift = arrGiftConv;
- dataClass.string = stringConv;
- dataClass.boxLong = boxLongConv;
- dataClass.unboxLong = unboxLongConv;
- dataClass.boxInteger = boxIntegerConv;
- dataClass.unboxInt = unboxIntConv;
- dataClass.boxDouble = boxDoubleConv;
- dataClass.unboxDouble = unboxDoubleConv;
- dataClass.boxFloat = boxFloatConv;
- dataClass.unboxFloat = unboxFloatConv;
- dataClass.boxBoolean = boxBooleanConv;
- dataClass.unboxBoolean = unboxBooleanConv;
- dataClass.unboxByteArr = unboxByteArrConv;
- dataClass.gift = giftConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.collectLong = collectLongConv;
+ document.collectInteger = collectIntegerConv;
+ document.collectDouble = collectDoubleConv;
+ document.collectFloat = collectFloatConv;
+ document.collectBoolean = collectBooleanConv;
+ document.collectByteArr = collectByteArrConv;
+ document.collectString = collectStringConv;
+ document.collectGift = collectGiftConv;
+ document.arrBoxLong = arrBoxLongConv;
+ document.arrUnboxLong = arrUnboxLongConv;
+ document.arrBoxInteger = arrBoxIntegerConv;
+ document.arrUnboxInt = arrUnboxIntConv;
+ document.arrBoxDouble = arrBoxDoubleConv;
+ document.arrUnboxDouble = arrUnboxDoubleConv;
+ document.arrBoxFloat = arrBoxFloatConv;
+ document.arrUnboxFloat = arrUnboxFloatConv;
+ document.arrBoxBoolean = arrBoxBooleanConv;
+ document.arrUnboxBoolean = arrUnboxBooleanConv;
+ document.arrUnboxByteArr = arrUnboxByteArrConv;
+ document.boxByteArr = boxByteArrConv;
+ document.arrString = arrStringConv;
+ document.arrGift = arrGiftConv;
+ document.string = stringConv;
+ document.boxLong = boxLongConv;
+ document.unboxLong = unboxLongConv;
+ document.boxInteger = boxIntegerConv;
+ document.unboxInt = unboxIntConv;
+ document.boxDouble = boxDoubleConv;
+ document.unboxDouble = unboxDoubleConv;
+ document.boxFloat = boxFloatConv;
+ document.unboxFloat = unboxFloatConv;
+ document.boxBoolean = boxBooleanConv;
+ document.unboxBoolean = unboxBooleanConv;
+ document.unboxByteArr = unboxByteArrConv;
+ document.gift = giftConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
index 9be6cdb..3f4b783 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
@@ -1,47 +1,47 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokNone")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokNone")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokPlain")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokPlain")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- String tokNoneCopy = dataClass.tokNone;
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ String tokNoneCopy = document.tokNone;
if (tokNoneCopy != null) {
builder.setPropertyString("tokNone", tokNoneCopy);
}
- String tokPlainCopy = dataClass.tokPlain;
+ String tokPlainCopy = document.tokPlain;
if (tokPlainCopy != null) {
builder.setPropertyString("tokPlain", tokPlainCopy);
}
@@ -50,7 +50,8 @@
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
String[] tokNoneCopy = genericDoc.getPropertyStringArray("tokNone");
String tokNoneConv = null;
if (tokNoneCopy != null && tokNoneCopy.length != 0) {
@@ -61,10 +62,11 @@
if (tokPlainCopy != null && tokPlainCopy.length != 0) {
tokPlainConv = tokPlainCopy[0];
}
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.tokNone = tokNoneConv;
- dataClass.tokPlain = tokPlainConv;
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.tokNone = tokNoneConv;
+ document.tokPlain = tokPlainConv;
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_multipleConventions.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_multipleConventions.JAVA
new file mode 100644
index 0000000..049d8d1
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_multipleConventions.JAVA
@@ -0,0 +1,64 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DocumentClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Override;
+import java.lang.String;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
+
+ @Override
+ public String getSchemaName() {
+ return SCHEMA_NAME;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price1")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price2")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price3")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price4")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .build();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(document.namespace, document.getId(), SCHEMA_NAME);
+ builder.setPropertyLong("price1", document.getPrice1());
+ builder.setPropertyLong("price2", document.price2());
+ builder.setPropertyLong("price3", document.getPrice3());
+ builder.setPropertyLong("price4", document.price4_);
+ return builder.build();
+ }
+
+ @Override
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String id_Conv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
+ int price1Conv = (int) genericDoc.getPropertyLong("price1");
+ int mPrice2Conv = (int) genericDoc.getPropertyLong("price2");
+ int _price3Conv = (int) genericDoc.getPropertyLong("price3");
+ int price4_Conv = (int) genericDoc.getPropertyLong("price4");
+ Gift document = new Gift(id_Conv, price4_Conv);
+ document.namespace = namespaceConv;
+ document.setPrice1(price1Conv);
+ document.price2(mPrice2Conv);
+ document.price3(_price3Conv);
+ return document;
+ }
+}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_multipleSetters.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_multipleSetters.JAVA
index 890d43d..9ab9158 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_multipleSetters.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_multipleSetters.JAVA
@@ -1,47 +1,48 @@
package com.example.appsearch;
import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
+import javax.annotation.processing.Generated;
-public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
- private static final String SCHEMA_TYPE = "Gift";
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
@Override
- public String getSchemaType() {
- return SCHEMA_TYPE;
+ public String getSchemaName() {
+ return SCHEMA_NAME;
}
@Override
public AppSearchSchema getSchema() throws AppSearchException {
- return new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build())
.build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
GenericDocument.Builder<?> builder =
- new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
- builder.setPropertyLong("price", dataClass.getPrice());
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ builder.setPropertyLong("price", document.getPrice());
return builder.build();
}
@Override
public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
- String uriConv = genericDoc.getUri();
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
int priceConv = (int) genericDoc.getPropertyLong("price");
- Gift dataClass = new Gift();
- dataClass.uri = uriConv;
- dataClass.setPrice(priceConv);
- return dataClass;
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.setPrice(priceConv);
+ return document;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_usableFactoryMethod_unusableConstructor.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_usableFactoryMethod_unusableConstructor.JAVA
new file mode 100644
index 0000000..83bbb53
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_usableFactoryMethod_unusableConstructor.JAVA
@@ -0,0 +1,47 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DocumentClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Override;
+import java.lang.String;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
+
+ @Override
+ public String getSchemaName() {
+ return SCHEMA_NAME;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .build();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ builder.setPropertyLong("price", document.price);
+ return builder.build();
+ }
+
+ @Override
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
+ int priceConv = (int) genericDoc.getPropertyLong("price");
+ Gift document = Gift.create(idConv, namespaceConv, priceConv);
+ document.namespace = namespaceConv;
+ document.price = priceConv;
+ return document;
+ }
+}
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/appsearch/debug-view/api/current.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to appsearch/debug-view/api/current.txt
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/appsearch/debug-view/api/public_plus_experimental_current.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to appsearch/debug-view/api/public_plus_experimental_current.txt
diff --git a/slice/slice-builders/ktx/api/res-current.txt b/appsearch/debug-view/api/res-current.txt
similarity index 100%
copy from slice/slice-builders/ktx/api/res-current.txt
copy to appsearch/debug-view/api/res-current.txt
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/appsearch/debug-view/api/restricted_current.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to appsearch/debug-view/api/restricted_current.txt
diff --git a/appsearch/debug-view/build.gradle b/appsearch/debug-view/build.gradle
new file mode 100644
index 0000000..49ab889
--- /dev/null
+++ b/appsearch/debug-view/build.gradle
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+import androidx.build.LibraryVersions
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+}
+
+android {
+ defaultConfig {
+ multiDexEnabled true
+ }
+}
+
+dependencies {
+ implementation project(':appsearch:appsearch')
+ implementation project(':appsearch:appsearch-local-storage')
+ implementation project(':appsearch:appsearch-platform-storage')
+ implementation('androidx.concurrent:concurrent-futures:1.0.0')
+ implementation('androidx.core:core:1.5.0')
+ implementation('androidx.fragment:fragment:1.3.0')
+ implementation('androidx.legacy:legacy-support-v4:1.0.0')
+ implementation("androidx.lifecycle:lifecycle-livedata:2.0.0")
+ implementation('com.google.android.material:material:1.0.0')
+ implementation(libs.constraintLayout)
+ implementation(libs.guavaAndroid)
+ androidTestImplementation(libs.multidex)
+}
+
+androidx {
+ name = "AndroidX AppSearch Debug View"
+ type = LibraryType.PUBLISHED_LIBRARY
+ mavenGroup = LibraryGroups.APPSEARCH
+ mavenVersion = LibraryVersions.APPSEARCH
+ inceptionYear = "2021"
+ description = "A support library for AndroidX AppSearch that contains activities and views " +
+ "for debugging an application's integration with AppSearch."
+}
diff --git a/appsearch/debug-view/samples/build.gradle b/appsearch/debug-view/samples/build.gradle
new file mode 100644
index 0000000..43071a4
--- /dev/null
+++ b/appsearch/debug-view/samples/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+import androidx.build.LibraryVersions
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+}
+
+android {
+ defaultConfig {
+ multiDexEnabled true
+ }
+}
+
+dependencies {
+ annotationProcessor project(":appsearch:appsearch-compiler")
+
+ api('androidx.annotation:annotation:1.1.0')
+
+ implementation(libs.multidex)
+ implementation project(':appsearch:appsearch')
+ implementation project(':appsearch:appsearch-local-storage')
+ implementation project(':appsearch:appsearch-debug-view')
+ implementation('androidx.appcompat:appcompat:1.2.0')
+ implementation('androidx.concurrent:concurrent-futures:1.0.0')
+ implementation('com.google.android.material:material:1.0.0')
+ implementation('com.google.code.gson:gson:2.6.2')
+ implementation(libs.constraintLayout)
+ implementation(libs.guavaAndroid)
+}
+
+androidx {
+ name = "AndroidX AppSearch Debug View Sample App"
+ type = LibraryType.SAMPLES
+ mavenGroup = LibraryGroups.APPSEARCH
+ mavenVersion = LibraryVersions.APPSEARCH
+ inceptionYear = "2021"
+ description = "Contains a sample app for integrating the Androidx AppSearch Debug View"
+}
diff --git a/appsearch/debug-view/samples/src/main/AndroidManifest.xml b/appsearch/debug-view/samples/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..66ce4b5
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.appsearch.debugview.samples">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".NotesActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="androidx.appsearch.debugview.view.AppSearchDebugActivity" />
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/assets/sample_notes.json b/appsearch/debug-view/samples/src/main/assets/sample_notes.json
new file mode 100644
index 0000000..18438c0
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/assets/sample_notes.json
@@ -0,0 +1,34 @@
+{
+ "data" : [
+ {
+ "noteText": "Don't forget to grab lunch!",
+ "namespace": "namespace1",
+ "id": "note1"
+ },
+ {
+ "noteText": "I wonder what food I should get.",
+ "namespace": "namespace1",
+ "id": "note2"
+ },
+ {
+ "noteText": "Apples are my favorite fruit.",
+ "namespace": "namespace1",
+ "id": "note3"
+ },
+ {
+ "noteText": "The weather is great!",
+ "namespace": "namespace2",
+ "id": "note1"
+ },
+ {
+ "noteText": "I hope it doesn't rain.",
+ "namespace": "namespace2",
+ "id": "note2"
+ },
+ {
+ "noteText": "Tomorrow will be hot.",
+ "namespace": "namespace2",
+ "id": "note3"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesActivity.java b/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesActivity.java
new file mode 100644
index 0000000..bddb5fb
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesActivity.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.samples;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appsearch.debugview.samples.model.Note;
+import androidx.appsearch.debugview.view.AppSearchDebugActivity;
+import androidx.core.content.ContextCompat;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+
+/**
+ * Default Activity for AppSearch Debug View Sample App
+ *
+ * <p>This activity reads sample data, converts it into {@link Note} objects, and then indexes
+ * them into AppSearch.
+ *
+ * <p>Each sample note's text is added to the list view for display.
+ */
+public class NotesActivity extends AppCompatActivity {
+ private static final String DB_NAME = "notesDb";
+ private static final String SAMPLE_NOTES_FILENAME = "sample_notes.json";
+ private static final String TAG = "NotesActivity";
+
+ private final SettableFuture<NotesAppSearchManager> mNotesAppSearchManagerFuture =
+ SettableFuture.create();
+ private ArrayAdapter<Note> mNotesAdapter;
+ private ListView mListView;
+ private TextView mLoadingView;
+ private ListeningExecutorService mBackgroundExecutor;
+ private List<Note> mSampleNotes;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_notes);
+
+ mListView = findViewById(R.id.list_view);
+ mLoadingView = findViewById(R.id.text_view);
+
+ mBackgroundExecutor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+
+ mNotesAppSearchManagerFuture.setFuture(NotesAppSearchManager.createNotesAppSearchManager(
+ getApplicationContext(), mBackgroundExecutor));
+ ListenableFuture<List<Note>> sampleNotesFuture =
+ mBackgroundExecutor.submit(() -> loadSampleNotes());
+
+ ListenableFuture<Void> insertNotesFuture =
+ Futures.whenAllSucceed(mNotesAppSearchManagerFuture, sampleNotesFuture).call(
+ () -> {
+ mSampleNotes = Futures.getDone(sampleNotesFuture);
+ Futures.getDone(mNotesAppSearchManagerFuture).insertNotes(
+ mSampleNotes).get();
+ return null;
+ }, mBackgroundExecutor);
+
+ Futures.addCallback(insertNotesFuture,
+ new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {
+ displayNotes();
+ }
+
+ @Override
+ public void onFailure(@NonNull Throwable t) {
+ Toast.makeText(NotesActivity.this, "Failed to insert notes "
+ + "into AppSearch.", Toast.LENGTH_LONG).show();
+ Log.e(TAG, "Failed to insert notes into AppSearch.", t);
+ }
+ }, ContextCompat.getMainExecutor(this));
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(@NonNull Menu menu) {
+ getMenuInflater().inflate(R.menu.debug_menu, menu);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ switch (item.getItemId()) {
+ case (R.id.app_search_debug):
+ Intent intent = new Intent(this, AppSearchDebugActivity.class);
+ intent.putExtra(AppSearchDebugActivity.DB_INTENT_KEY, DB_NAME);
+ intent.putExtra(AppSearchDebugActivity.STORAGE_TYPE_INTENT_KEY,
+ AppSearchDebugActivity.STORAGE_TYPE_LOCAL);
+ startActivity(intent);
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void onStop() {
+ Futures.whenAllSucceed(mNotesAppSearchManagerFuture).call(() -> {
+ Futures.getDone(mNotesAppSearchManagerFuture).close();
+ return null;
+ }, mBackgroundExecutor);
+
+ super.onStop();
+ }
+
+ @WorkerThread
+ private List<Note> loadSampleNotes() {
+ List<Note> sampleNotes = new ArrayList<>();
+ Gson gson = new Gson();
+ try (InputStreamReader r = new InputStreamReader(
+ getAssets().open(SAMPLE_NOTES_FILENAME))) {
+ JsonObject samplesJson = gson.fromJson(r, JsonObject.class);
+ JsonArray sampleJsonArr = samplesJson.getAsJsonArray("data");
+ for (int i = 0; i < sampleJsonArr.size(); ++i) {
+ JsonObject noteJson = sampleJsonArr.get(i).getAsJsonObject();
+ sampleNotes.add(new Note.Builder().setId(noteJson.get("id").getAsString())
+ .setNamespace(noteJson.get("namespace").getAsString())
+ .setText(noteJson.get("noteText").getAsString())
+ .build()
+ );
+ }
+ } catch (IOException e) {
+ Toast.makeText(NotesActivity.this, "Failed to load sample notes ",
+ Toast.LENGTH_LONG).show();
+ Log.e(TAG, "Sample notes IO failed: ", e);
+ }
+ return sampleNotes;
+ }
+
+ private void displayNotes() {
+ mNotesAdapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_list_item_1, mSampleNotes);
+ mListView.setAdapter(mNotesAdapter);
+
+ mLoadingView.setVisibility(View.GONE);
+ mListView.setVisibility(View.VISIBLE);
+ }
+}
diff --git a/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesAppSearchManager.java b/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesAppSearchManager.java
new file mode 100644
index 0000000..7aba8a7
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesAppSearchManager.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.samples;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.appsearch.debugview.samples.model.Note;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.LocalStorage;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.io.Closeable;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Manages interactions with AppSearch.
+ */
+public class NotesAppSearchManager implements Closeable {
+ private static final String DB_NAME = "notesDb";
+ private static final boolean FORCE_OVERRIDE = true;
+
+ private final Context mContext;
+ private final Executor mExecutor;
+ private final SettableFuture<AppSearchSession> mAppSearchSessionFuture =
+ SettableFuture.create();
+
+ private NotesAppSearchManager(@NonNull Context context, @NonNull Executor executor) {
+ mContext = context;
+ mExecutor = executor;
+ }
+
+ /**
+ * Factory for creating a {@link NotesAppSearchManager} instance.
+ *
+ * <p>This creates and initializes an {@link AppSearchSession}. It also resets existing
+ * {@link Note} objects from the index and re-adds the {@link Note} document class to the
+ * AppSearch schema.
+ *
+ * @param executor to run AppSearch operations on.
+ */
+ @NonNull
+ public static ListenableFuture<NotesAppSearchManager> createNotesAppSearchManager(
+ @NonNull Context context, @NonNull Executor executor) {
+ NotesAppSearchManager notesAppSearchManager = new NotesAppSearchManager(context, executor);
+ return Futures.transform(notesAppSearchManager.initialize(),
+ unused -> notesAppSearchManager, executor);
+ }
+
+ /**
+ * Closes the AppSearch session.
+ */
+ @Override
+ public void close() {
+ Futures.whenAllSucceed(mAppSearchSessionFuture).call(() -> {
+ Futures.getDone(mAppSearchSessionFuture).close();
+ return null;
+ }, mExecutor);
+ }
+
+ /**
+ * Inserts {@link Note} documents into the AppSearch database.
+ *
+ * @param notes list of notes to index in AppSearch.
+ */
+ @NonNull
+ public ListenableFuture<AppSearchBatchResult<String, Void>> insertNotes(
+ @NonNull List<Note> notes) {
+ try {
+ PutDocumentsRequest request = new PutDocumentsRequest.Builder().addDocuments(notes)
+ .build();
+ return Futures.transformAsync(mAppSearchSessionFuture,
+ session -> session.put(request), mExecutor);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+ }
+
+ @NonNull
+ private ListenableFuture<Void> initialize() {
+ return Futures.transformAsync(createLocalSession(), session -> {
+ mAppSearchSessionFuture.set(session);
+ return Futures.transformAsync(resetDocuments(),
+ unusedResetResult -> Futures.transform(setSchema(),
+ unusedSetSchemaResult -> null,
+ mExecutor),
+ mExecutor);
+ }, mExecutor);
+ }
+
+ private ListenableFuture<AppSearchSession> createLocalSession() {
+ return LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(mContext, DB_NAME)
+ .build()
+ );
+ }
+
+ private ListenableFuture<SetSchemaResponse> resetDocuments() {
+ SetSchemaRequest request =
+ new SetSchemaRequest.Builder().setForceOverride(FORCE_OVERRIDE).build();
+ return Futures.transformAsync(mAppSearchSessionFuture,
+ session -> session.setSchema(request),
+ mExecutor);
+ }
+
+ private ListenableFuture<SetSchemaResponse> setSchema() {
+ try {
+ SetSchemaRequest request = new SetSchemaRequest.Builder().addDocumentClasses(Note.class)
+ .build();
+ return Futures.transformAsync(mAppSearchSessionFuture,
+ session -> session.setSchema(request), mExecutor);
+ } catch (AppSearchException e) {
+ return Futures.immediateFailedFuture(e);
+ }
+ }
+}
diff --git a/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/model/Note.java b/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/model/Note.java
new file mode 100644
index 0000000..07cf0a2
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/model/Note.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.debugview.samples.model;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.annotation.Document;
+import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
+import androidx.core.util.Preconditions;
+
+/**
+ * Encapsulates a Note document.
+ */
+@Document
+public class Note {
+
+ Note(@NonNull String namespace, @NonNull String id, @NonNull String text) {
+ mId = Preconditions.checkNotNull(id);
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mText = Preconditions.checkNotNull(text);
+ }
+
+ @Document.Id
+ private final String mId;
+
+ @Document.Namespace
+ private final String mNamespace;
+
+ @Document.StringProperty(indexingType = StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ private final String mText;
+
+ /** Returns the ID of the {@link Note} object. */
+ @NonNull
+ public String getId() {
+ return mId;
+ }
+
+ /** Returns the namespace of the {@link Note} object. */
+ @NonNull
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ /** Returns the text of the {@link Note} object. */
+ @NonNull
+ public String getText() {
+ return mText;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return mText;
+ }
+
+ /** Builder for {@link Note} objects. */
+ public static final class Builder {
+ private String mNamespace = "";
+ private String mId = "";
+ private String mText = "";
+
+ /** Sets the namespace of the {@link Note} object. */
+ @NonNull
+ public Note.Builder setNamespace(@NonNull String namespace) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ return this;
+ }
+
+ /** Sets the ID of the {@link Note} object. */
+ @NonNull
+ public Note.Builder setId(@NonNull String id) {
+ mId = Preconditions.checkNotNull(id);
+ return this;
+ }
+
+ /** Sets the text of the {@link Note} object. */
+ @NonNull
+ public Note.Builder setText(@NonNull String text) {
+ mText = Preconditions.checkNotNull(text);
+ return this;
+ }
+
+ /** Creates a new {@link Note} object. */
+ @NonNull
+ public Note build() {
+ return new Note(mNamespace, mId, mText);
+ }
+ }
+}
diff --git a/appsearch/debug-view/samples/src/main/res/drawable-v24/ic_launcher_foreground.xml b/appsearch/debug-view/samples/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..cb0581c
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108">
+ <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="85.84757"
+ android:endY="92.4963"
+ android:startX="42.9492"
+ android:startY="49.59793"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+ android:strokeColor="#00000000"
+ android:strokeWidth="1" />
+</vector>
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/res/drawable/ic_launcher_background.xml b/appsearch/debug-view/samples/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..6dcf0d3
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108">
+ <path
+ android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+</vector>
diff --git a/appsearch/debug-view/samples/src/main/res/layout/activity_notes.xml b/appsearch/debug-view/samples/src/main/res/layout/activity_notes.xml
new file mode 100644
index 0000000..6ce0f0f4
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/layout/activity_notes.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".NotesActivity">
+
+ <TextView
+ android:id="@+id/text_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="Loading sample notes..."
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <ListView
+ android:id="@+id/list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.appcompat.widget.LinearLayoutCompat>
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/res/menu/debug_menu.xml b/appsearch/debug-view/samples/src/main/res/menu/debug_menu.xml
new file mode 100644
index 0000000..6ba449f
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/menu/debug_menu.xml
@@ -0,0 +1,7 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/app_search_debug"
+ android:title="AppSearch Debug View"
+ >
+ </item>
+</menu>
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/appsearch/debug-view/samples/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..8da4add9
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/appsearch/debug-view/samples/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..8da4add9
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-hdpi/ic_launcher.png b/appsearch/debug-view/samples/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-hdpi/ic_launcher_round.png b/appsearch/debug-view/samples/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-mdpi/ic_launcher.png b/appsearch/debug-view/samples/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-mdpi/ic_launcher_round.png b/appsearch/debug-view/samples/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-xhdpi/ic_launcher.png b/appsearch/debug-view/samples/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/appsearch/debug-view/samples/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-xxhdpi/ic_launcher.png b/appsearch/debug-view/samples/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/appsearch/debug-view/samples/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/appsearch/debug-view/samples/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/appsearch/debug-view/samples/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/appsearch/debug-view/samples/src/main/res/values/colors.xml b/appsearch/debug-view/samples/src/main/res/values/colors.xml
new file mode 100644
index 0000000..cde477b
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+</resources>
\ No newline at end of file
diff --git a/appsearch/debug-view/samples/src/main/res/values/strings.xml b/appsearch/debug-view/samples/src/main/res/values/strings.xml
new file mode 100644
index 0000000..41c6b20
--- /dev/null
+++ b/appsearch/debug-view/samples/src/main/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="app_name">AppSearch Debug View Sample App</string>
+</resources>
\ No newline at end of file
diff --git a/appsearch/debug-view/src/main/AndroidManifest.xml b/appsearch/debug-view/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..043ccbf
--- /dev/null
+++ b/appsearch/debug-view/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest package="androidx.appsearch.debugview" />
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/DebugAppSearchManager.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/DebugAppSearchManager.java
new file mode 100644
index 0000000..11b6755
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/DebugAppSearchManager.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview;
+
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.GetByDocumentIdRequest;
+import androidx.appsearch.app.GetSchemaResponse;
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.debugview.view.AppSearchDebugActivity;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.LocalStorage;
+import androidx.appsearch.platformstorage.PlatformStorage;
+import androidx.core.os.BuildCompat;
+import androidx.core.util.Preconditions;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Manages interactions with AppSearch.
+ *
+ * <p>Instances of {@link DebugAppSearchManager} are created by calling {@link #create}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class DebugAppSearchManager implements Closeable {
+ private static final int PAGE_SIZE = 100;
+
+ private final Context mContext;
+ private final ExecutorService mExecutor;
+ private final SettableFuture<AppSearchSession> mAppSearchSessionFuture =
+ SettableFuture.create();
+
+ private DebugAppSearchManager(@NonNull Context context, @NonNull ExecutorService executor) {
+ mContext = Preconditions.checkNotNull(context);
+ mExecutor = Preconditions.checkNotNull(executor);
+ }
+
+ /**
+ * Factory for creating a {@link DebugAppSearchManager} instance.
+ *
+ * <p>This factory creates an {@link AppSearchSession} instance with the provided
+ * database name.
+ *
+ * @param context application context.
+ * @param executor executor to run AppSearch operations on.
+ * @param databaseName name of the database to open AppSearch debugging for.
+ * @param storageType constant of the storage type to start session for.
+ * @throws AppSearchException if the storage type is invalid, or a R- device selects platform
+ * storage as the storage type for debugging.
+ */
+ @NonNull
+ public static ListenableFuture<DebugAppSearchManager> create(
+ @NonNull Context context,
+ @NonNull ExecutorService executor, @NonNull String databaseName,
+ @AppSearchDebugActivity.StorageType int storageType) throws AppSearchException {
+ Preconditions.checkNotNull(context);
+ Preconditions.checkNotNull(executor);
+ Preconditions.checkNotNull(databaseName);
+
+ DebugAppSearchManager debugAppSearchManager =
+ new DebugAppSearchManager(context, executor);
+
+ ListenableFuture<DebugAppSearchManager> debugAppSearchManagerListenableFuture;
+
+ switch (storageType) {
+ case AppSearchDebugActivity.STORAGE_TYPE_LOCAL:
+ debugAppSearchManagerListenableFuture =
+ Futures.transform(
+ debugAppSearchManager.initializeLocalStorage(databaseName),
+ unused -> debugAppSearchManager, executor);
+ break;
+ case AppSearchDebugActivity.STORAGE_TYPE_PLATFORM:
+ if (BuildCompat.isAtLeastS()) {
+ debugAppSearchManagerListenableFuture =
+ Futures.transform(
+ debugAppSearchManager.initializePlatformStorage(databaseName),
+ unused -> debugAppSearchManager, executor);
+ } else {
+ throw new AppSearchException(AppSearchResult.RESULT_INVALID_ARGUMENT,
+ "Platform Storage debugging only valid for S+ devices.");
+ }
+ break;
+ default:
+ throw new AppSearchException(AppSearchResult.RESULT_INVALID_ARGUMENT,
+ "Invalid storage type specified. Verify that the "
+ + "storage type that has been passed in the intent is valid.");
+ }
+ return debugAppSearchManagerListenableFuture;
+ }
+
+ /**
+ * Searches for all documents in the AppSearch database.
+ *
+ * <p>Each {@link GenericDocument} object is truncated of its properties by adding
+ * projection to the request.
+ *
+ * @return the {@link SearchResults} instance for exploring pages of results. Call
+ * {@link #getNextPage} to retrieve the {@link GenericDocument} objects for each page.
+ */
+ @NonNull
+ public ListenableFuture<SearchResults> getAllDocumentsSearchResults() {
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setResultCountPerPage(PAGE_SIZE)
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addProjection(SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD, Collections.emptyList())
+ .build();
+ String retrieveAllQueryString = "";
+
+ return Futures.transform(mAppSearchSessionFuture,
+ session -> session.search(retrieveAllQueryString, searchSpec), mExecutor);
+ }
+
+
+ /**
+ * Converts the next page from the provided {@link SearchResults} instance to a list of
+ * {@link GenericDocument} objects.
+ *
+ * @param results results to get next page for, and convert to a list of
+ * {@link GenericDocument} objects.
+ */
+ @NonNull
+ public ListenableFuture<List<GenericDocument>> getNextPage(@NonNull SearchResults results) {
+ Preconditions.checkNotNull(results);
+
+ return Futures.transform(results.getNextPage(),
+ DebugAppSearchManager::convertResultsToGenericDocuments, mExecutor);
+ }
+
+ /**
+ * Gets a document from the AppSearch database by namespace and ID.
+ */
+ @NonNull
+ public ListenableFuture<GenericDocument> getDocument(@NonNull String namespace,
+ @NonNull String id) {
+ Preconditions.checkNotNull(id);
+ Preconditions.checkNotNull(namespace);
+ GetByDocumentIdRequest request =
+ new GetByDocumentIdRequest.Builder(namespace).addIds(id).build();
+
+ return Futures.transformAsync(mAppSearchSessionFuture,
+ session -> Futures.transform(session.getByDocumentId(request),
+ response -> response.getSuccesses().get(id), mExecutor), mExecutor);
+ }
+
+ /**
+ * Gets the schema of the AppSearch database.
+ */
+ @NonNull
+ public ListenableFuture<GetSchemaResponse> getSchema() {
+ return Futures.transformAsync(mAppSearchSessionFuture,
+ session -> session.getSchema(), mExecutor);
+ }
+
+ /**
+ * Closes the AppSearch session.
+ */
+ @Override
+ public void close() {
+ Futures.whenAllSucceed(mAppSearchSessionFuture).call(() -> {
+ Futures.getDone(mAppSearchSessionFuture).close();
+ return null;
+ }, mExecutor);
+ }
+
+ @NonNull
+ private ListenableFuture<AppSearchSession> initializeLocalStorage(
+ @NonNull String databaseName) {
+ mAppSearchSessionFuture.setFuture(LocalStorage.createSearchSession(
+ new LocalStorage.SearchContext.Builder(mContext, databaseName)
+ .build())
+ );
+ return mAppSearchSessionFuture;
+ }
+
+ @NonNull
+ @RequiresApi(Build.VERSION_CODES.S)
+ private ListenableFuture<AppSearchSession> initializePlatformStorage(
+ @NonNull String databaseName) {
+ mAppSearchSessionFuture.setFuture(PlatformStorage.createSearchSession(
+ new PlatformStorage.SearchContext.Builder(mContext, databaseName)
+ .build())
+ );
+ return mAppSearchSessionFuture;
+ }
+
+ private static List<GenericDocument> convertResultsToGenericDocuments(
+ List<SearchResult> results) {
+ List<GenericDocument> docs = new ArrayList<>(results.size());
+
+ for (SearchResult result : results) {
+ docs.add(result.getGenericDocument());
+ }
+
+ return docs;
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/DocumentListModel.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/DocumentListModel.java
new file mode 100644
index 0000000..5a23cb0
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/DocumentListModel.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.model;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.debugview.DebugAppSearchManager;
+import androidx.core.util.Preconditions;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Documents ViewModel for the database's {@link GenericDocument} objects.
+ *
+ * <p>This model captures the data for displaying lists of {@link GenericDocument} objects. Each
+ * {@link GenericDocument} object is truncated of all properties.
+ *
+ * <p>Instances of {@link DocumentListModel} are created by {@link DocumentListModelFactory}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class DocumentListModel extends ViewModel {
+ private static final String TAG = "DocumentListModel";
+
+ private final ExecutorService mExecutor;
+ private final DebugAppSearchManager mDebugAppSearchManager;
+ final MutableLiveData<List<GenericDocument>> mDocumentsLiveData =
+ new MutableLiveData<>();
+ final MutableLiveData<SearchResults> mDocumentsSearchResultsLiveData =
+ new MutableLiveData<>();
+ volatile boolean mHasAdditionalPages = true;
+
+ public DocumentListModel(@NonNull ExecutorService executor,
+ @NonNull DebugAppSearchManager debugAppSearchManager) {
+ mExecutor = Preconditions.checkNotNull(executor);
+ mDebugAppSearchManager = Preconditions.checkNotNull(debugAppSearchManager);
+ }
+
+ /**
+ * Gets the {@link SearchResults} instance for a search over all documents in the AppSearch
+ * database.
+ *
+ * <p>Call {@link #addAdditionalResultsPage} to get the next page of documents from the
+ * {@link SearchResults} instance.
+ *
+ * <p>This should only be called once per fragment.
+ */
+ @NonNull
+ public LiveData<SearchResults> getAllDocumentsSearchResults() {
+ Futures.addCallback(mDebugAppSearchManager.getAllDocumentsSearchResults(),
+ new FutureCallback<SearchResults>() {
+ @Override
+ public void onSuccess(SearchResults result) {
+ // There should only be one active observer to post this value to as its
+ // called only once per fragment, ensuring a safe null check.
+ if (mDocumentsSearchResultsLiveData.getValue() == null) {
+ mDocumentsSearchResultsLiveData.postValue(result);
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Throwable t) {
+ Log.e(TAG, "Failed to get all documents.", t);
+ }
+ }, mExecutor);
+ return mDocumentsSearchResultsLiveData;
+ }
+
+ /**
+ * Adds the next page of documents for the provided {@link SearchResults} instance to the
+ * running list of retrieved {@link GenericDocument} objects.
+ *
+ * <p>Each page is represented as a list of {@link GenericDocument} objects.
+ *
+ * @return a {@link LiveData} encapsulating the list of {@link GenericDocument} objects for
+ * documents retrieved from all previous pages and this additional page.
+ */
+ @NonNull
+ public LiveData<List<GenericDocument>> addAdditionalResultsPage(
+ @NonNull SearchResults results) {
+ Futures.addCallback(mDebugAppSearchManager.getNextPage(results),
+ new FutureCallback<List<GenericDocument>>() {
+ @Override
+ public void onSuccess(List<GenericDocument> result) {
+ if (mDocumentsLiveData.getValue() == null) {
+ mDocumentsLiveData.postValue(result);
+ } else {
+ if (result.isEmpty()) {
+ mHasAdditionalPages = false;
+ }
+ mDocumentsLiveData.getValue().addAll(result);
+ mDocumentsLiveData.postValue(mDocumentsLiveData.getValue());
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Throwable t) {
+ Log.e(TAG, "Failed to get next page of documents.", t);
+ }
+ }, mExecutor);
+
+ return mDocumentsLiveData;
+ }
+
+ /**
+ * Returns whether there are additional pages to load to the document list.
+ */
+ public boolean hasAdditionalPages() {
+ return mHasAdditionalPages;
+ }
+
+ /**
+ * Gets all {@link GenericDocument} objects that have been loaded.
+ *
+ * <p>If the underlying list of the Documents LiveData is {@code null}, this returns an
+ * empty list as a placeholder.
+ */
+ @NonNull
+ public List<GenericDocument> getAllLoadedDocuments() {
+ if (mDocumentsLiveData.getValue() == null) {
+ return Collections.emptyList();
+ }
+ return mDocumentsLiveData.getValue();
+ }
+
+ /**
+ * Factory for creating a {@link DocumentListModel} instance.
+ */
+ public static class DocumentListModelFactory extends ViewModelProvider.NewInstanceFactory {
+ private final DebugAppSearchManager mDebugAppSearchManager;
+ private final ListeningExecutorService mExecutorService;
+
+ public DocumentListModelFactory(@NonNull ListeningExecutorService executor,
+ @NonNull DebugAppSearchManager debugAppSearchManager) {
+ mDebugAppSearchManager = debugAppSearchManager;
+ mExecutorService = executor;
+ }
+
+ @SuppressWarnings("unchecked")
+ @NonNull
+ @Override
+ public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
+ if (modelClass == DocumentListModel.class) {
+ return (T) new DocumentListModel(mExecutorService, mDebugAppSearchManager);
+ } else {
+ throw new IllegalArgumentException("Expected class: DocumentListModel.");
+ }
+ }
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/DocumentModel.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/DocumentModel.java
new file mode 100644
index 0000000..a8c03dc
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/DocumentModel.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.model;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.debugview.DebugAppSearchManager;
+import androidx.core.util.Preconditions;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Document ViewModel for displaying a {@link GenericDocument} object.
+ *
+ * <p>Instances of the ViewModel are created by {@link DocumentModelFactory}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class DocumentModel extends ViewModel {
+ private static final String TAG = "AppSearchDocumentModel";
+
+ private final ExecutorService mExecutor;
+ private final DebugAppSearchManager mDebugAppSearchManager;
+ final MutableLiveData<GenericDocument> mDocumentLiveData = new MutableLiveData<>();
+
+ public DocumentModel(@NonNull ExecutorService executor,
+ @NonNull DebugAppSearchManager debugAppSearchManager) {
+ mExecutor = Preconditions.checkNotNull(executor);
+ mDebugAppSearchManager = Preconditions.checkNotNull(debugAppSearchManager);
+ }
+
+ /**
+ * Gets a {@link GenericDocument} object by namespace and ID.
+ */
+ @NonNull
+ public LiveData<GenericDocument> getDocument(@NonNull String namespace, @NonNull String id) {
+ Futures.addCallback(mDebugAppSearchManager.getDocument(namespace, id),
+ new FutureCallback<GenericDocument>() {
+ @Override
+ public void onSuccess(GenericDocument result) {
+ mDocumentLiveData.postValue(result);
+ }
+
+ @Override
+ public void onFailure(@Nullable Throwable t) {
+ Log.e(TAG,
+ "Failed to get document with namespace: " + namespace + " and "
+ + "id: " + id, t);
+ }
+ }, mExecutor);
+ return mDocumentLiveData;
+ }
+
+ /**
+ * Factory for creating a {@link DocumentModel} instance.
+ */
+ public static class DocumentModelFactory extends ViewModelProvider.NewInstanceFactory {
+ private final DebugAppSearchManager mDebugAppSearchManager;
+ private final ListeningExecutorService mExecutorService;
+
+ public DocumentModelFactory(@NonNull ListeningExecutorService executor,
+ @NonNull DebugAppSearchManager debugAppSearchManager) {
+ mDebugAppSearchManager = debugAppSearchManager;
+ mExecutorService = executor;
+ }
+
+ @SuppressWarnings("unchecked")
+ @NonNull
+ @Override
+ public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
+ if (modelClass == DocumentModel.class) {
+ return (T) new DocumentModel(mExecutorService, mDebugAppSearchManager);
+ } else {
+ throw new IllegalArgumentException("Expected class: DocumentModel.");
+ }
+ }
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/SchemaTypeListModel.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/SchemaTypeListModel.java
new file mode 100644
index 0000000..16e0b66
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/model/SchemaTypeListModel.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.model;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GetSchemaResponse;
+import androidx.appsearch.debugview.DebugAppSearchManager;
+import androidx.core.util.Preconditions;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Schema Type List ViewModel for the database schema's.
+ *
+ * <p>This model captures the data for displaying a list of {@link AppSearchSchema} objects that
+ * compose of the schema. This also captures the overall schema version.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SchemaTypeListModel extends ViewModel {
+ private static final String TAG = "AppSearchSchemaTypeList";
+
+ private final ExecutorService mExecutor;
+ private final DebugAppSearchManager mDebugAppSearchManager;
+ final MutableLiveData<GetSchemaResponse> mSchemaResponseMutableLiveData =
+ new MutableLiveData<>();
+
+ public SchemaTypeListModel(@NonNull ExecutorService executor,
+ @NonNull DebugAppSearchManager debugAppSearchManager) {
+ mExecutor = Preconditions.checkNotNull(executor);
+ mDebugAppSearchManager = Preconditions.checkNotNull(debugAppSearchManager);
+ }
+
+ /**
+ * Gets list of {@link AppSearchSchema} objects that compose of the schema.
+ *
+ * @return live data of list of {@link AppSearchSchema} objects.
+ */
+ @NonNull
+ public LiveData<List<AppSearchSchema>> getSchemaTypes() {
+ return Transformations.map(getSchema(),
+ input -> new ArrayList<>(input.getSchemas()));
+ }
+
+ /**
+ * Gets overall schema version.
+ *
+ * @return live data of {@link Integer} representing the overall schema version.
+ */
+ @NonNull
+ public LiveData<Integer> getSchemaVersion() {
+ return Transformations.map(getSchema(), GetSchemaResponse::getVersion);
+ }
+
+ /**
+ * Gets schema of database.
+ *
+ * @return live data of {@link GetSchemaResponse}
+ */
+ @NonNull
+ private LiveData<GetSchemaResponse> getSchema() {
+ Futures.addCallback(mDebugAppSearchManager.getSchema(),
+ new FutureCallback<GetSchemaResponse>() {
+ @Override
+ public void onSuccess(GetSchemaResponse result) {
+ mSchemaResponseMutableLiveData.postValue(result);
+ }
+
+ @Override
+ public void onFailure(@Nullable Throwable t) {
+ Log.e(TAG, "Failed to get schema.", t);
+ }
+ }, mExecutor);
+ return mSchemaResponseMutableLiveData;
+ }
+
+ /**
+ * Factory for creating a {@link SchemaTypeListModel} instance.
+ */
+ public static class SchemaTypeListModelFactory extends ViewModelProvider.NewInstanceFactory {
+ private final DebugAppSearchManager mDebugAppSearchManager;
+ private final ListeningExecutorService mExecutorService;
+
+ public SchemaTypeListModelFactory(@NonNull ListeningExecutorService executor,
+ @NonNull DebugAppSearchManager debugAppSearchManager) {
+ mDebugAppSearchManager = debugAppSearchManager;
+ mExecutorService = executor;
+ }
+
+ @SuppressWarnings("unchecked")
+ @NonNull
+ @Override
+ public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
+ if (modelClass == SchemaTypeListModel.class) {
+ return (T) new SchemaTypeListModel(mExecutorService, mDebugAppSearchManager);
+ } else {
+ throw new IllegalArgumentException("Expected class: SchemaTypeListModel.");
+ }
+ }
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/AppSearchDebugActivity.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/AppSearchDebugActivity.java
new file mode 100644
index 0000000..20ea01f
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/AppSearchDebugActivity.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.debugview.DebugAppSearchManager;
+import androidx.appsearch.debugview.R;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.fragment.app.FragmentActivity;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executors;
+
+/**
+ * Debug Activity for AppSearch.
+ *
+ * <p>This activity provides a view of all the documents that have been put into an application's
+ * AppSearch database. The database is specified by creating an {@link android.content.Intent}
+ * with extras specifying the database name and the AppSearch storage type.
+ *
+ * <p>To launch this activity, declare it in the application's manifest:
+ * <pre>
+ * <activity android:name="androidx.appsearch.debugview.view.AppSearchDebugActivity" />
+ * </pre>
+ *
+ * <p>Next, create an {@link android.content.Intent} from the activity that will launch the debug
+ * activity. Add the database name as an extra with key: {@link #DB_INTENT_KEY} and the storage
+ * type, which can be either {@link #STORAGE_TYPE_LOCAL} or {@link #STORAGE_TYPE_PLATFORM} with
+ * key: {@link #STORAGE_TYPE_INTENT_KEY}.
+ *
+ * <p>Example of launching the debug activity for local storage:
+ * <pre>
+ * Intent intent = new Intent(this, AppSearchDebugActivity.class);
+ * intent.putExtra(AppSearchDebugActivity.DB_INTENT_KEY, DB_NAME);
+ * intent.putExtra(AppSearchDebugActivity.STORAGE_TYPE_INTENT_KEY,
+ * AppSearchDebugActivity.STORAGE_TYPE_LOCAL);
+ * startActivity(intent);
+ * </pre>
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class AppSearchDebugActivity extends FragmentActivity {
+ private static final String TAG = "AppSearchDebugActivity";
+ public static final String DB_INTENT_KEY = "databaseName";
+ public static final String STORAGE_TYPE_INTENT_KEY = "storageType";
+
+ private String mDbName;
+ private ListenableFuture<DebugAppSearchManager> mDebugAppSearchManager;
+ private ListeningExecutorService mBackgroundExecutor;
+
+ @IntDef(value = {
+ STORAGE_TYPE_LOCAL,
+ STORAGE_TYPE_PLATFORM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StorageType {
+ }
+
+ public static final int STORAGE_TYPE_LOCAL = 0;
+ public static final int STORAGE_TYPE_PLATFORM = 1;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_appsearchdebug);
+
+ mBackgroundExecutor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+ mDbName = getIntent().getExtras().getString(DB_INTENT_KEY);
+ @StorageType int storageType =
+ getIntent().getExtras().getInt(STORAGE_TYPE_INTENT_KEY);
+ try {
+ mDebugAppSearchManager = DebugAppSearchManager.create(
+ getApplicationContext(), mBackgroundExecutor, mDbName, storageType);
+ } catch (AppSearchException e) {
+ Toast.makeText(getApplicationContext(),
+ "Failed to initialize AppSearch: " + e.getMessage(),
+ Toast.LENGTH_LONG).show();
+ Log.e(TAG, "Failed to initialize AppSearch.", e);
+ }
+
+ MenuFragment menuFragment = new MenuFragment();
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragment_container, menuFragment)
+ .commit();
+ }
+
+ @Override
+ protected void onStop() {
+ Futures.whenAllSucceed(mDebugAppSearchManager).call(() -> {
+ Futures.getDone(mDebugAppSearchManager).close();
+ return null;
+ }, mBackgroundExecutor);
+
+ super.onStop();
+ }
+
+ /**
+ * Gets the {@link DebugAppSearchManager} instance created by the activity.
+ */
+ @NonNull
+ public ListenableFuture<DebugAppSearchManager> getDebugAppSearchManager() {
+ return mDebugAppSearchManager;
+ }
+
+ /**
+ * Gets the {@link ListeningExecutorService} instance created by the activity.
+ */
+ @NonNull
+ public ListeningExecutorService getBackgroundExecutor() {
+ return mBackgroundExecutor;
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentFragment.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentFragment.java
new file mode 100644
index 0000000..7ba316f
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentFragment.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.debugview.DebugAppSearchManager;
+import androidx.appsearch.debugview.R;
+import androidx.appsearch.debugview.model.DocumentModel;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+/**
+ * A fragment for displaying a {@link GenericDocument} object.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class DocumentFragment extends Fragment {
+ private static final String TAG = "AppSearchDocumentFrag";
+ private static final String ARG_NAMESPACE = "document_namespace";
+ private static final String ARG_ID = "document_id";
+
+ private String mNamespace;
+ private String mId;
+ private ListeningExecutorService mExecutor;
+ private ListenableFuture<DebugAppSearchManager> mDebugAppSearchManager;
+ private DocumentModel mDocumentModel;
+
+ /**
+ * Factory for creating a {@link DocumentFragment} instance.
+ */
+ @NonNull
+ public static DocumentFragment createDocumentFragment(
+ @NonNull String namespace, @NonNull String id) {
+ DocumentFragment documentFragment = new DocumentFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_NAMESPACE, namespace);
+ args.putString(ARG_ID, id);
+ documentFragment.setArguments(args);
+ return documentFragment;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mId = getArguments().getString(ARG_ID);
+ mNamespace = getArguments().getString(ARG_NAMESPACE);
+ }
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_document, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mExecutor = ((AppSearchDebugActivity) getActivity()).getBackgroundExecutor();
+ mDebugAppSearchManager =
+ ((AppSearchDebugActivity) getActivity()).getDebugAppSearchManager();
+
+ Futures.addCallback(mDebugAppSearchManager,
+ new FutureCallback<DebugAppSearchManager>() {
+ @Override
+ public void onSuccess(DebugAppSearchManager debugAppSearchManager) {
+ displayDocument(debugAppSearchManager);
+ }
+
+ @Override
+ public void onFailure(@NonNull Throwable t) {
+ Toast.makeText(getContext(),
+ "Failed to initialize AppSearch: " + t.getMessage(),
+ Toast.LENGTH_LONG).show();
+ Log.e(TAG,
+ "Failed to initialize AppSearch. Verify that the database name "
+ + "has been provided in the intent with key: databaseName",
+ t);
+ }
+ }, ContextCompat.getMainExecutor(getActivity()));
+ }
+
+ protected void displayDocument(@NonNull DebugAppSearchManager debugAppSearchManager) {
+ mDocumentModel =
+ new ViewModelProvider(this,
+ new DocumentModel.DocumentModelFactory(mExecutor, debugAppSearchManager)
+ ).get(DocumentModel.class);
+
+ mDocumentModel.getDocument(mNamespace, mId).observe(this, document -> {
+ TextView documentView = getView().findViewById(R.id.document_string);
+ documentView.setText(document.toString());
+ });
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentListFragment.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentListFragment.java
new file mode 100644
index 0000000..6a89d55
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentListFragment.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.debugview.DebugAppSearchManager;
+import androidx.appsearch.debugview.R;
+import androidx.appsearch.debugview.model.DocumentListModel;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+import java.util.Collections;
+
+/**
+ * A fragment for displaying a list of {@link GenericDocument} objects.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class DocumentListFragment extends Fragment {
+ private static final String TAG = "DocumentListFragment";
+
+ private TextView mLoadingView;
+ private TextView mEmptyDocumentsView;
+ private RecyclerView mDocumentListRecyclerView;
+ private LinearLayoutManager mLinearLayoutManager;
+ private DocumentListItemAdapter mDocumentListItemAdapter;
+ private ListeningExecutorService mExecutor;
+ private ListenableFuture<DebugAppSearchManager> mDebugAppSearchManager;
+ private AppSearchDebugActivity mAppSearchDebugActivity;
+
+ protected boolean mLoadingPage = false;
+
+ @Nullable
+ protected DocumentListModel mDocumentListModel;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_document_list, container, /*attachToRoot=*/
+ false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mLoadingView = getView().findViewById(R.id.loading_text_view);
+ mEmptyDocumentsView = getView().findViewById(R.id.empty_documents_text_view);
+ mDocumentListRecyclerView = getView().findViewById(R.id.document_list_recycler_view);
+
+ mAppSearchDebugActivity = (AppSearchDebugActivity) getActivity();
+ mExecutor = mAppSearchDebugActivity.getBackgroundExecutor();
+ mDebugAppSearchManager = mAppSearchDebugActivity.getDebugAppSearchManager();
+
+ initDocumentListRecyclerView();
+
+ Futures.addCallback(mDebugAppSearchManager,
+ new FutureCallback<DebugAppSearchManager>() {
+ @Override
+ public void onSuccess(DebugAppSearchManager debugAppSearchManager) {
+ readDocuments(debugAppSearchManager);
+ }
+
+ @Override
+ public void onFailure(@NonNull Throwable t) {
+ Toast.makeText(getContext(),
+ "Failed to initialize AppSearch: " + t.getMessage(),
+ Toast.LENGTH_LONG).show();
+ Log.e(TAG,
+ "Failed to initialize AppSearch. Verify that the database name "
+ + "has been"
+ + " provided in the intent with key: databaseName", t);
+ }
+ }, ContextCompat.getMainExecutor(mAppSearchDebugActivity));
+ }
+
+ /**
+ * Initializes a {@link DocumentListModel} ViewModel instance and sets observer for updating UI
+ * with document data.
+ */
+ protected void readDocuments(@NonNull DebugAppSearchManager debugAppSearchManager) {
+ mDocumentListModel =
+ new ViewModelProvider(this,
+ new DocumentListModel.DocumentListModelFactory(mExecutor,
+ debugAppSearchManager)).get(DocumentListModel.class);
+
+ if (mDocumentListModel.hasAdditionalPages()) {
+ mDocumentListModel.getAllDocumentsSearchResults().observe(this, results -> {
+ mLoadingView.setVisibility(View.GONE);
+ displayNextSearchResultsPage(results);
+ });
+ } else {
+ mLoadingView.setVisibility(View.GONE);
+ mDocumentListItemAdapter.setDocuments(mDocumentListModel.getAllLoadedDocuments());
+ }
+ }
+
+ private void displayNextSearchResultsPage(@NonNull SearchResults searchResults) {
+ mDocumentListModel.addAdditionalResultsPage(searchResults).observe(this, docs -> {
+ mDocumentListItemAdapter.setDocuments(docs);
+ if (docs.size() == 0) {
+ mEmptyDocumentsView.setVisibility(View.VISIBLE);
+ mDocumentListRecyclerView.setVisibility(View.GONE);
+ }
+ mLoadingPage = false;
+ });
+
+ mDocumentListRecyclerView.addOnScrollListener(
+ new ScrollListener(mLinearLayoutManager) {
+ @Override
+ public void loadNextPage() {
+ mLoadingPage = true;
+ mDocumentListModel.addAdditionalResultsPage(searchResults);
+ }
+
+ @Override
+ public boolean isLoading() {
+ return mLoadingPage;
+ }
+
+ @Override
+ public boolean hasAdditionalPages() {
+ return mDocumentListModel.hasAdditionalPages();
+ }
+ });
+ }
+
+ private void initDocumentListRecyclerView() {
+ mLinearLayoutManager = new LinearLayoutManager(mAppSearchDebugActivity);
+ mLinearLayoutManager.setOrientation(RecyclerView.VERTICAL);
+
+ mDocumentListItemAdapter = new DocumentListItemAdapter(Collections.emptyList(), this);
+
+ mDocumentListRecyclerView.setAdapter(mDocumentListItemAdapter);
+ mDocumentListRecyclerView.setLayoutManager(mLinearLayoutManager);
+ DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
+ mAppSearchDebugActivity, mLinearLayoutManager.getOrientation());
+ mDocumentListRecyclerView.addItemDecoration(dividerItemDecoration);
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentListItemAdapter.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentListItemAdapter.java
new file mode 100644
index 0000000..b30152b
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/DocumentListItemAdapter.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.debugview.R;
+import androidx.core.util.Preconditions;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+/**
+ * Adapter for displaying a list of {@link GenericDocument} objects.
+ *
+ * <p>This adapter displays each item as a namespace and document ID.
+ *
+ * <p>Documents can be manually changed by calling {@link #setDocuments}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class DocumentListItemAdapter extends
+ RecyclerView.Adapter<DocumentListItemAdapter.ViewHolder> {
+ private List<GenericDocument> mDocuments;
+ private DocumentListFragment mDocumentListFragment;
+
+ DocumentListItemAdapter(@NonNull List<GenericDocument> documents,
+ @NonNull DocumentListFragment documentListFragment) {
+ mDocuments = Preconditions.checkNotNull(documents);
+ mDocumentListFragment = Preconditions.checkNotNull(documentListFragment);
+ }
+
+ /**
+ * Sets the adapter's document list.
+ *
+ * @param documents list of {@link GenericDocument} objects to update adapter with.
+ */
+ public void setDocuments(@NonNull List<GenericDocument> documents) {
+ mDocuments = Preconditions.checkNotNull(documents);
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.adapter_document_list_item, parent, /*attachToRoot=*/false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ String namespace = mDocuments.get(position).getNamespace();
+ String id = mDocuments.get(position).getId();
+ holder.getNamespaceLabel().setText(
+ "Namespace: \"" + namespace + "\"");
+ holder.getIdLabel().setText("ID: \"" + id + "\"");
+
+ holder.itemView.setOnClickListener(unusedView -> {
+ DocumentFragment documentFragment =
+ DocumentFragment.createDocumentFragment(namespace, id);
+ mDocumentListFragment.getActivity().getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragment_container, documentFragment)
+ .addToBackStack(/*name=*/null)
+ .commit();
+ }
+ );
+ }
+
+ @Override
+ public int getItemCount() {
+ return mDocuments.size();
+ }
+
+ /**
+ * ViewHolder for {@link DocumentListItemAdapter}.
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ private final TextView mNamespaceLabel;
+ private final TextView mIdLabel;
+
+ public ViewHolder(@NonNull View view) {
+ super(view);
+
+ Preconditions.checkNotNull(view);
+
+ mNamespaceLabel = view.findViewById(R.id.doc_item_namespace);
+ mIdLabel = view.findViewById(R.id.doc_item_id);
+ }
+
+ @NonNull
+ public TextView getNamespaceLabel() {
+ return mNamespaceLabel;
+ }
+
+ @NonNull
+ public TextView getIdLabel() {
+ return mIdLabel;
+ }
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/MenuFragment.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/MenuFragment.java
new file mode 100644
index 0000000..c7abf48
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/MenuFragment.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.debugview.R;
+import androidx.fragment.app.Fragment;
+
+/**
+ * A fragment for displaying page navigation shortcuts of the debug view.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class MenuFragment extends Fragment {
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_menu, container, /*attachToRoot=*/false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ Button documentListButton = getView().findViewById(R.id.view_documents_button);
+ documentListButton.setOnClickListener(
+ unusedView -> {
+ DocumentListFragment documentListFragment = new DocumentListFragment();
+ navigateToFragment(documentListFragment);
+ });
+
+ Button schemaTypeListButton = getView().findViewById(R.id.view_schema_types_button);
+ schemaTypeListButton.setOnClickListener(
+ unusedView -> {
+ SchemaTypeListFragment schemaTypeListFragment = new SchemaTypeListFragment();
+ navigateToFragment(schemaTypeListFragment);
+ });
+ }
+
+ private void navigateToFragment(Fragment fragment) {
+ getActivity().getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragment_container, fragment)
+ .addToBackStack(/*name=*/null)
+ .commit();
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/SchemaTypeListFragment.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/SchemaTypeListFragment.java
new file mode 100644
index 0000000..9bc7100
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/SchemaTypeListFragment.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.debugview.DebugAppSearchManager;
+import androidx.appsearch.debugview.R;
+import androidx.appsearch.debugview.model.SchemaTypeListModel;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+import java.util.Collections;
+
+/**
+ * A fragment for displaying a list of {@link AppSearchSchema} objects.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SchemaTypeListFragment extends Fragment {
+ private static final String TAG = "AppSearchSchemaTypeFrag";
+
+ private TextView mLoadingView;
+ private TextView mEmptySchemaTypesView;
+ private TextView mSchemaVersionView;
+ private RecyclerView mSchemaTypeListRecyclerView;
+ private LinearLayoutManager mLinearLayoutManager;
+ private SchemaTypeListItemAdapter mSchemaTypeListItemAdapter;
+ private ListeningExecutorService mExecutor;
+ private ListenableFuture<DebugAppSearchManager> mDebugAppSearchManager;
+ private AppSearchDebugActivity mAppSearchDebugActivity;
+
+ @Nullable
+ protected SchemaTypeListModel mSchemaTypeListModel;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_schema_type_list, container, /*attachToRoot=*/
+ false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ mLoadingView = getView().findViewById(R.id.loading_schema_types_text_view);
+ mEmptySchemaTypesView = getView().findViewById(R.id.empty_schema_types_text_view);
+ mSchemaTypeListRecyclerView = getView().findViewById(R.id.schema_type_list_recycler_view);
+ mSchemaVersionView = getView().findViewById(R.id.schema_version_view);
+
+ mAppSearchDebugActivity = (AppSearchDebugActivity) getActivity();
+ mExecutor = mAppSearchDebugActivity.getBackgroundExecutor();
+ mDebugAppSearchManager = mAppSearchDebugActivity.getDebugAppSearchManager();
+
+ initSchemaTypeListRecyclerView();
+
+ Futures.addCallback(mDebugAppSearchManager,
+ new FutureCallback<DebugAppSearchManager>() {
+ @Override
+ public void onSuccess(DebugAppSearchManager debugAppSearchManager) {
+ readSchema(debugAppSearchManager);
+ }
+
+ @Override
+ public void onFailure(@NonNull Throwable t) {
+ Toast.makeText(getContext(),
+ "Failed to initialize AppSearch: " + t.getMessage(),
+ Toast.LENGTH_LONG).show();
+ Log.e(TAG, "Failed to initialize AppSearch. Verify that the database name "
+ + "has been provided in the intent with key: databaseName", t);
+ }
+ }, ContextCompat.getMainExecutor(mAppSearchDebugActivity));
+ }
+
+ /**
+ * Initializes a {@link SchemaTypeListModel} ViewModel instance and sets observer for updating
+ * UI with the schema.
+ */
+ protected void readSchema(@NonNull DebugAppSearchManager debugAppSearchManager) {
+ mSchemaTypeListModel =
+ new ViewModelProvider(this,
+ new SchemaTypeListModel.SchemaTypeListModelFactory(mExecutor,
+ debugAppSearchManager)).get(SchemaTypeListModel.class);
+
+ mSchemaTypeListModel.getSchemaTypes().observe(this, schemaTypeList -> {
+ mLoadingView.setVisibility(View.GONE);
+
+ if (schemaTypeList.size() == 0) {
+ mEmptySchemaTypesView.setVisibility(View.VISIBLE);
+ mSchemaTypeListRecyclerView.setVisibility(View.GONE);
+ } else {
+ mSchemaTypeListItemAdapter.setSchemaTypes(schemaTypeList);
+ }
+ });
+
+ mSchemaTypeListModel.getSchemaVersion().observe(this, version -> {
+ mSchemaVersionView.setText(
+ getString(R.string.appsearch_schema_version, version));
+ mSchemaVersionView.setVisibility(View.VISIBLE);
+ });
+ }
+
+ private void initSchemaTypeListRecyclerView() {
+ mLinearLayoutManager = new LinearLayoutManager(mAppSearchDebugActivity);
+ mLinearLayoutManager.setOrientation(RecyclerView.VERTICAL);
+
+ mSchemaTypeListItemAdapter = new SchemaTypeListItemAdapter(Collections.emptyList());
+
+ mSchemaTypeListRecyclerView.setAdapter(mSchemaTypeListItemAdapter);
+ mSchemaTypeListRecyclerView.setLayoutManager(mLinearLayoutManager);
+ DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
+ mAppSearchDebugActivity, mLinearLayoutManager.getOrientation());
+ mSchemaTypeListRecyclerView.addItemDecoration(dividerItemDecoration);
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/SchemaTypeListItemAdapter.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/SchemaTypeListItemAdapter.java
new file mode 100644
index 0000000..277b050
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/SchemaTypeListItemAdapter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.debugview.R;
+import androidx.core.util.Preconditions;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+/**
+ * Adapter for displaying a list of {@link AppSearchSchema} objects.
+ *
+ * <p>This adapter displays each schema type with its name.
+ *
+ * <p>Schema types can be manually changed by calling {@link #setSchemaTypes}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SchemaTypeListItemAdapter extends
+ RecyclerView.Adapter<SchemaTypeListItemAdapter.ViewHolder> {
+ private List<AppSearchSchema> mSchemaTypes;
+
+ SchemaTypeListItemAdapter(@NonNull List<AppSearchSchema> schemaTypes) {
+ mSchemaTypes = Preconditions.checkNotNull(schemaTypes);
+ }
+
+ /**
+ * Sets the adapter's schema type list.
+ *
+ * @param schemaTypes list of {@link AppSearchSchema} objects to update adapter with.
+ */
+ public void setSchemaTypes(@NonNull List<AppSearchSchema> schemaTypes) {
+ mSchemaTypes = Preconditions.checkNotNull(schemaTypes);
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.adapter_schema_type_list_item, parent, /*attachToRoot=*/false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ String schemaType = mSchemaTypes.get(position).getSchemaType();
+
+ holder.getSchemaTypeLabel().setText(schemaType);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mSchemaTypes.size();
+ }
+
+ /**
+ * ViewHolder for {@link SchemaTypeListItemAdapter}.
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ private final TextView mSchemaTypeLabel;
+
+ public ViewHolder(@NonNull View view) {
+ super(view);
+
+ Preconditions.checkNotNull(view);
+
+ mSchemaTypeLabel = view.findViewById(R.id.schema_type_item_title);
+ }
+
+ @NonNull
+ public TextView getSchemaTypeLabel() {
+ return mSchemaTypeLabel;
+ }
+ }
+}
diff --git a/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/ScrollListener.java b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/ScrollListener.java
new file mode 100644
index 0000000..a2dd0e98
--- /dev/null
+++ b/appsearch/debug-view/src/main/java/androidx/appsearch/debugview/view/ScrollListener.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.debugview.view;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.util.Preconditions;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Listens for scrolling and loads the next page of results if the end of the view is reached.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public abstract class ScrollListener extends RecyclerView.OnScrollListener {
+ private final LinearLayoutManager mLayoutManager;
+
+ public ScrollListener(@NonNull LinearLayoutManager layoutManager) {
+ mLayoutManager = Preconditions.checkNotNull(layoutManager);
+ }
+
+ @Override
+ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+ super.onScrolled(recyclerView, dx, dy);
+
+ int itemsVisible = mLayoutManager.getChildCount();
+ int totalItems = mLayoutManager.getItemCount();
+ int firstItemInViewIndex = mLayoutManager.findFirstVisibleItemPosition();
+
+ // This value is true when the RecyclerView has additional rows that can be filled and
+ // the underlying adapter does not have sufficient items to fill them.
+ boolean hasAdditionalRowsToFill = (firstItemInViewIndex + itemsVisible) >= totalItems;
+
+ if (!isLoading() && hasAdditionalPages()) {
+ if (hasAdditionalRowsToFill && firstItemInViewIndex >= 0) {
+ loadNextPage();
+ }
+ }
+ }
+
+ /**
+ * Defines how to load the next page of results to display.
+ */
+ public abstract void loadNextPage();
+
+ /**
+ * Indicates whether a page is currently be loading.
+ *
+ * <p>{@link #loadNextPage()} will not be called if this is {@code true}.
+ */
+ public abstract boolean isLoading();
+
+ /**
+ * Indicates whether there are additional pages to load.
+ *
+ * <p>{@link #loadNextPage()} will not be called if this is {@code true}.
+ */
+ public abstract boolean hasAdditionalPages();
+}
diff --git a/appsearch/debug-view/src/main/res/layout/activity_appsearchdebug.xml b/appsearch/debug-view/src/main/res/layout/activity_appsearchdebug.xml
new file mode 100644
index 0000000..ca53b16
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/layout/activity_appsearchdebug.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".view.AppSearchDebugActivity" >
+
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/appsearch/debug-view/src/main/res/layout/adapter_document_list_item.xml b/appsearch/debug-view/src/main/res/layout/adapter_document_list_item.xml
new file mode 100644
index 0000000..7060743
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/layout/adapter_document_list_item.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="2px"
+ android:minHeight="42px" >
+
+ <TextView
+ android:id="@+id/doc_item_namespace"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <TextView
+ android:id="@+id/doc_item_id"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/appsearch/debug-view/src/main/res/layout/adapter_schema_type_list_item.xml b/appsearch/debug-view/src/main/res/layout/adapter_schema_type_list_item.xml
new file mode 100644
index 0000000..2d60d60
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/layout/adapter_schema_type_list_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:padding="4dp" >
+
+ <TextView
+ android:id="@+id/schema_type_item_title"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/appsearch/debug-view/src/main/res/layout/fragment_document.xml b/appsearch/debug-view/src/main/res/layout/fragment_document.xml
new file mode 100644
index 0000000..22b8d67
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/layout/fragment_document.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".view.DocumentFragment"
+ android:padding="6px" >
+
+ <TextView
+ android:id="@+id/document_string"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Loading document..." />
+
+</LinearLayout>
diff --git a/appsearch/debug-view/src/main/res/layout/fragment_document_list.xml b/appsearch/debug-view/src/main/res/layout/fragment_document_list.xml
new file mode 100644
index 0000000..78d2431
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/layout/fragment_document_list.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".view.AppSearchDebugActivity" >
+
+ <TextView
+ android:id="@+id/loading_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/appsearch_documents_loading"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/document_list_recycler_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/empty_documents_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/appsearch_no_documents_error"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/appsearch/debug-view/src/main/res/layout/fragment_menu.xml b/appsearch/debug-view/src/main/res/layout/fragment_menu.xml
new file mode 100644
index 0000000..e57a8bc9
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/layout/fragment_menu.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ tools:context=".view.MenuFragment">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_horizontal" >
+
+ <Button
+ android:id="@+id/view_documents_button"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="VIEW DOCUMENTS" />
+
+ <Button
+ android:id="@+id/view_schema_types_button"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="VIEW SCHEMA TYPES" />
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/appsearch/debug-view/src/main/res/layout/fragment_schema_type_list.xml b/appsearch/debug-view/src/main/res/layout/fragment_schema_type_list.xml
new file mode 100644
index 0000000..5b85784
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/layout/fragment_schema_type_list.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".view.AppSearchDebugActivity" >
+
+ <TextView
+ android:id="@+id/loading_schema_types_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/appsearch_schema_types_loading"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/schema_version_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="@string/appsearch_schema_version"
+ android:minHeight="64px"
+ android:textFontWeight="700"
+ android:background="@color/design_default_color_primary_dark"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/schema_type_list_recycler_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/empty_schema_types_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/appsearch_no_schema_types_error"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/appsearch/debug-view/src/main/res/values-af/strings.xml b/appsearch/debug-view/src/main/res/values-af/strings.xml
new file mode 100644
index 0000000..51f5f48
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-af/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Geen AppSearch-dokumente in databasis gekry nie. Verifieer dat die databasisnaam geldig is en die regte bergingtipe gekies is."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Geen AppSearch-skematipes gekry nie. Verifieer dat die databasisnaam geldig is en die regte bergingtipe gekies is."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Laai tans AppSearch-dokumente …"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Laai tans AppSearch-skematipes …"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Skemaweergawe: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-am/strings.xml b/appsearch/debug-view/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000..cb135d5
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-am/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"በመረጃ ጎታ ውስጥ ምንም የመተግበሪያ ፍለጋ ሰነዶች አልተገኙም። የመረጃ ጎታ ስም ትክክለኛ መሆኑን እና ትክክለኛው የማከማቻ ዓይነት መመረጡን ያረጋግጡ።"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"ምንም የመተግበሪያ ፍለጋ የንድፍ አይነቶች አልተገኙም። የመረጃ ጎታ ስም ትክክለኛ መሆኑን እና ትክክለኛው የማከማቻ ዓይነት መመረጡን ያረጋግጡ።"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"የመተግበሪያ ፍለጋ ሰነዶችን በመጫን ላይ..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"የመተግበሪያ ፍለጋ የንድፍ ዓይነቶችን በመጫን ላይ..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"የንድፍ ስሪት፦ %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ar/strings.xml b/appsearch/debug-view/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..ea253a8
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ar/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"لم يتم العثور على مستندات AppSearch في قاعدة البيانات. تأكّد من أن اسم قاعدة البيانات صالح ومن اختيار نوع وحدة تخزين صحيح."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"لم يتم العثور على أنواع مخططات AppSearch. تأكّد من أن اسم قاعدة البيانات صالح ومن اختيار نوع وحدة تخزين صحيح."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"جارٍ تحميل مستندات AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"جارٍ تحميل أنواع مخططات AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"إصدار المخطط: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-as/strings.xml b/appsearch/debug-view/src/main/res/values-as/strings.xml
new file mode 100644
index 0000000..a2d4396
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-as/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ডেটাবেছত কোনো AppSearchৰ নথি পোৱা নগ’ল। সত্যাপন কৰক যে ডেটাবেছৰ নামটো মান্য আৰু ষ্ট’ৰেজৰ সঠিক প্ৰকাৰটো বাছনি কৰা হৈছে।"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearchৰ স্কীমাৰ কোনো প্ৰকাৰ পোৱা নগ’ল। সত্যাপন কৰক যে ডেটাবেছৰ নামটো মান্য আৰু ষ্ট’ৰেজৰ সঠিক প্ৰকাৰটো বাছনি কৰা হৈছে।"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearchৰ নথি ল’ড কৰি থকা হৈছে..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearchৰ স্কীমাৰ প্ৰকাৰ ল’ড কৰি থকা হৈছে..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"স্কীমাৰ সংস্কৰণ: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-az/strings.xml b/appsearch/debug-view/src/main/res/values-az/strings.xml
new file mode 100644
index 0000000..b7744fe
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-az/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Data bazasında AppSearch sənədləri tapılmadı. Data bazası adının doğru olduğunu və düzgün yaddaş növünün seçildiyini doğrulayın."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch sxem növləri tapılmadı. Data bazası adının doğru olduğunu və düzgün yaddaş növünün seçildiyini doğrulayın."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch sənədləri yüklənir..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch sxem növləri yüklənir..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Sxem Versiyası: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-b+sr+Latn/strings.xml b/appsearch/debug-view/src/main/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..b1344d4
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Nije pronađet nijedan AppSearch dokument u bazi podataka. Verifikujte da je baza podataka važeća i da je izabran ispravan tip memorijskog prostora."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nije pronađen nijedan tip AppSearch šeme. Verifikujte da je baza podataka važeća i da je izabran ispravan tip memorijskog prostora."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Učitavaju se AppSearch dokumenti..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Tipovi AppSearch šeme se učitavaju..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Verzija šeme: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-be/strings.xml b/appsearch/debug-view/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000..461f4e4
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-be/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Дакументы AppSearch не знойдзены ў базе даных. Пераканайцеся ў тым, што вы ўвялі сапраўдную назву базы даных і выбралі правільны тып сховішча."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Тыпы схемы AppSearch не знойдзены. Пераканайцеся ў тым, што вы ўвялі сапраўдную назву базы даных і выбралі правільны тып сховішча."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Загрузка дакументаў AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Загрузка тыпаў схемы AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Версія схемы: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-bg/strings.xml b/appsearch/debug-view/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000..8773eb6
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-bg/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"В базата от данни не бяха намерени документи от AppSearch. Уверете се, че името на базата от данни е валидно и сте избрали правилния тип на хранилището."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Не бяха открити типове схема за AppSearch. Уверете се, че името на базата от данни е валидно и сте избрали правилния тип на хранилището."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Документите от AppSearch се зареждат…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Типовете схема за AppSearch се зареждат…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Версия на схемата: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-bn/strings.xml b/appsearch/debug-view/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000..0ff4244
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-bn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ডেটাবেসে AppSearch-এর কোনও ডকুমেন্ট খুঁজে পাওয়া যায়নি। ডেটাবেসের নাম ঠিক আছে এবং স্টোরেজের সঠিক ধরন সঠিক বেছে নেওয়া হয়েছে কিনা তা যাচাই করুন।"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"কোনও AppSearch স্কিমা খুঁজে পাওয়া যায়নি। ডেটাবেসের নাম ঠিক আছে এবং স্টোরেজের সঠিক ধরন সঠিক বেছে নেওয়া হয়েছে কিনা তা যাচাই করুন।"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch-এর ডকুমেন্ট লোড করা হচ্ছে..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"বিভিন্ন ধরনের AppSearch স্কিমা লোড করা হচ্ছে..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"স্কিমা ভার্সন: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-bs/strings.xml b/appsearch/debug-view/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000..5c643b0
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-bs/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Nijedan dokument na usluzi AppSearch nije pronađen u bazi podataka. Potvrdite da je naziv baze podataka važeći i da je odabrana ispravna vrsta pohrane."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nije pronađena nijedna vrsta šema na usluzi AppSearch. Potvrdite da je naziv baze podataka važeći i da je odabrana ispravna vrsta pohrane."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Učitavanje dokumenata na usluzi AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Učitavanje vrsta šema na usluzi AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Verzija šeme: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ca/strings.xml b/appsearch/debug-view/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000..6e81fa0
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ca/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No s\'ha trobat cap document d\'AppSearch a la base de dades. Comprova que el nom de la base de dades sigui vàlid i que hagis seleccionat el tipus d\'emmagatzematge correcte."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No s\'ha trobat cap tipus d\'esquema d\'AppSearch. Comprova que el nom de la base de dades sigui vàlid i que hagis seleccionat el tipus d\'emmagatzematge correcte."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"S\'estan carregant els documents d\'AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"S\'estan carregant els tipus d\'esquema d\'AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versió de l\'esquema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-cs/strings.xml b/appsearch/debug-view/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000..162dfa0
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-cs/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"V databázi nebyly nalezeny žádné dokumenty AppSearch. Zkontrolujte, zda je název databáze platný a zda byl vybrán správný typ úložiště."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nebyly nalezeny žádné typy schémat AppSearch. Zkontrolujte, zda je název databáze platný a zda byl vybrán správný typ úložiště."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Načítání dokumentů AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Načítání typů schémat AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Verze schématu: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-da/strings.xml b/appsearch/debug-view/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000..54bccbc
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-da/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Der blev ikke fundet nogen AppSearch-dokumenter i databasen. Bekræft, at databasens navn er gyldigt, og at du har valgt den korrekte lagertype."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Der blev ikke fundet nogen AppSearch-skematyper. Bekræft, at databasens navn er gyldigt, og at du har valgt den korrekte lagertype."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Indlæser AppSearch-dokumenter…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Indlæser AppSearch-skematyper…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Skemaversion: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-de/strings.xml b/appsearch/debug-view/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..04b2784
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-de/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"In der Datenbank wurden keine AppSearch-Dokumente gefunden. Überprüfe, ob der Name der Datenbank gültig ist und der richtige Speichertyp ausgewählt wurde."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Es wurden keine AppSearch-Schematypen gefunden. Überprüfe, ob der Name der Datenbank gültig ist und der richtige Speichertyp ausgewählt wurde."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch-Dokumente werden geladen…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch-Schematypen werden geladen…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schemaversion: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-el/strings.xml b/appsearch/debug-view/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000..11e3c8b
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-el/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Δεν βρέθηκαν έγγραφα AppSearch στη βάση δεδομένων. Επαληθεύστε ότι το όνομα της βάσης δεδομένων είναι έγκυρο και ότι έχει επιλεγεί ο σωστός τύπος αποθηκευτικού χώρου."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Δεν βρέθηκαν τύποι σχήματος AppSearch. Επαληθεύστε ότι το όνομα της βάσης δεδομένων είναι έγκυρο και ότι έχει επιλεγεί ο σωστός τύπος αποθηκευτικού χώρου."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Φόρτωση εγγράφων AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Φόρτωση τύπων σχήματος AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Έκδοση σχήματος: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-en-rAU/strings.xml b/appsearch/debug-view/src/main/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..81d3a2d
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-en-rAU/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No AppSearch documents found in database. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No AppSearch schema types found. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Loading AppSearch documents…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Loading AppSearch schema types…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schema version: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-en-rCA/strings.xml b/appsearch/debug-view/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..81d3a2d
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-en-rCA/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No AppSearch documents found in database. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No AppSearch schema types found. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Loading AppSearch documents…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Loading AppSearch schema types…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schema version: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-en-rGB/strings.xml b/appsearch/debug-view/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..81d3a2d
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No AppSearch documents found in database. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No AppSearch schema types found. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Loading AppSearch documents…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Loading AppSearch schema types…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schema version: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-en-rIN/strings.xml b/appsearch/debug-view/src/main/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..81d3a2d
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-en-rIN/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No AppSearch documents found in database. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No AppSearch schema types found. Verify that the database name is valid and that the correct storage type was selected."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Loading AppSearch documents…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Loading AppSearch schema types…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schema version: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-en-rXC/strings.xml b/appsearch/debug-view/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..b65f0b8
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-en-rXC/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No AppSearch documents found in database. Verify that the database name is valid and the correct storage type was selected."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No AppSearch schema types found. Verify that the database name is valid and the correct storage type was selected."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Loading AppSearch documents..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Loading AppSearch schema types..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schema Version: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-es-rUS/strings.xml b/appsearch/debug-view/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..432a7b6
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-es-rUS/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No se encontró ningún documento de AppSearch en la base de datos. Verifica que el nombre de la base de datos sea válido y que hayas seleccionado el tipo de almacenamiento correcto."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No se encontró ningún tipo de esquema de AppSearch. Verifica que el nombre de la base de datos sea válido y que hayas seleccionado el tipo de almacenamiento correcto."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Cargando documentos de AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Cargando tipos de esquema de AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versión del esquema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-es/strings.xml b/appsearch/debug-view/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..b37ba84b
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-es/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"No se ha encontrado ningún documento de AppSearch en la base de datos. Comprueba que el nombre de la base de datos sea válido y que esté seleccionado el tipo de almacenamiento correcto."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"No se han encontrado ningún tipo de esquema de AppSearch. Comprueba que el nombre de la base de datos sea válido y que esté seleccionado el tipo de almacenamiento correcto."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Cargando documentos de AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Cargando tipos de esquema de AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versión del esquema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-et/strings.xml b/appsearch/debug-view/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000..bbe743b
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-et/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Andmebaasist ei leitud ühtegi AppSearchi dokumenti. Veenduge, et andmebaasi nimi oleks kehtiv ja valitud oleks õige salvestusruumi tüüp."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Ühtegi AppSearchi skeemi tüüpi ei leitud. Veenduge, et andmebaasi nimi oleks kehtiv ja valitud oleks õige salvestusruumi tüüp."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearchi dokumentide laadimine …"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearchi skeemi tüüpide laadimine …"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Skeemi versioon: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-eu/strings.xml b/appsearch/debug-view/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000..757465d
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-eu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Ez da aurkitu AppSearch-eko dokumenturik datu-basean. Egiaztatu datu-basearen izenak balio duela eta biltegiratze mota zuzena hautatu dela."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Ez da aurkitu AppSearch-en eskema motarik. Egiaztatu datu-basearen izenak balio duela eta biltegiratze mota zuzena hautatu dela."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch-eko dokumentuak kargatzen…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch-en eskema motak kargatzen…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Eskemaren bertsioa: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-fa/strings.xml b/appsearch/debug-view/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000..48e62ff
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-fa/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"هیچ سندی از AppSearch در پایگاه داده پیدا نشد. تأیید کنید که نام پایگاه داده معتبر است و نوع صحیح فضای ذخیرهسازی انتخاب شده است."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"هیچ نوعی از طرح AppSearch پیدا نشد. تأیید کنید که نام پایگاه داده معتبر است و نوع صحیح فضای ذخیرهسازی انتخاب شده است."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"درحال بار کردن اسناد AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"درحال بار کردن انواع طرح AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"نسخه طرح: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-fi/strings.xml b/appsearch/debug-view/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..3fda0ea
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-fi/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"AppSearchin dokumentteja ei löytynyt tietokannasta. Varmista, että tietokannan nimi on oikea ja että olet valinnut oikean tallennustilatyypin."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearchin mallityyppejä ei löytynyt tietokannasta. Varmista, että tietokannan nimi on oikea ja että olet valinnut oikean tallennustilatyypin."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Ladataan AppSearchin dokumentteja…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Ladataan AppSearchin mallityyppejä…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Mallin versio: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-fr-rCA/strings.xml b/appsearch/debug-view/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..b306b21
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-fr-rCA/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Aucun document AppSearch trouvé dans la base de données. Vérifiez que le nom de la base de données est correct et que le bon type d\'espace de stockage a été sélectionné."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Aucun type de schéma AppSearch trouvé. Vérifiez que le nom de la base de données est correct et que le bon type d\'espace de stockage a été sélectionné."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Chargement des documents AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Chargement des types de schémas AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Version du schéma : %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-fr/strings.xml b/appsearch/debug-view/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..96553cc
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-fr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Aucun document AppSearch trouvé dans la base de données. Vérifiez que le nom de la base de données est valide et que vous avez sélectionné le type d\'espace de stockage correct."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Aucun type de schéma AppSearch trouvé. Vérifiez que le nom de la base de données est valide et que vous avez sélectionné le type d\'espace de stockage correct."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Chargement des documents AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Chargement des types de schémas AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Version du schéma : %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-gl/strings.xml b/appsearch/debug-view/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000..ce3ecf9
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-gl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Non se atoparon documentos de AppSearch na base de datos. Comproba que o nome da base de datos sexa válido e que se seleccionase o tipo de almacenamento correcto."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Non se atoparon tipos de esquemas de AppSearch. Comproba que o nome da base de datos sexa válido e que se seleccionase o tipo de almacenamento correcto."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Cargando documentos de AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Cargando tipos de esquemas de AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versión do esquema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-gu/strings.xml b/appsearch/debug-view/src/main/res/values-gu/strings.xml
new file mode 100644
index 0000000..4aeaffa
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-gu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ડેટાબેઝમાં AppSearchના કોઈ દસ્તાવેજ મળ્યા નથી. ડેટાબેઝનું નામ માન્ય હોવાની અને પસંદ કરેલા સ્ટોરેજનો પ્રકાર યોગ્ય હોવાની ચકાસણી કરો."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch સ્કીમાના કોઈ પ્રકાર મળ્યા નથી. ડેટાબેઝનું નામ માન્ય હોવાની અને પસંદ કરેલા સ્ટોરેજનો પ્રકાર યોગ્ય હોવાની ચકાસણી કરો."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearchના દસ્તાવેજો લોડ કરી રહ્યાં છીએ…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch સ્કીમાના પ્રકારો લોડ કરી રહ્યાં છીએ…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"સ્કીમા વર્ઝન: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-hi/strings.xml b/appsearch/debug-view/src/main/res/values-hi/strings.xml
new file mode 100644
index 0000000..c2c5525
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-hi/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"डेटाबेस में, AppSearch का कोई दस्तावेज़ नहीं मिला. पुष्टि करें कि डेटाबेस का नाम मान्य है और डिवाइस के स्टोरेज का सही टाइप चुना गया है."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch का कोई स्कीमा टाइप नहीं मिला. पुष्टि करें कि डेटाबेस का नाम मान्य है और डिवाइस के स्टोरेज का सही टाइप चुना गया है."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch के दस्तावेज़ लोड हो रहे हैं..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch के स्कीमा टाइप लोड हो रहे हैं..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"स्कीमा वर्शन %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-hr/strings.xml b/appsearch/debug-view/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000..0ebf67a4
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-hr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"U bazi podataka nije pronađen nijedan AppSearch dokument. Potvrdite da je naziv baze podataka važeći i da je odabrana točna vrsta pohrane."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nije pronađena nijedna vrsta AppSearch sheme. Potvrdite da je naziv baze podataka važeći i da je odabrana točna vrsta pohrane."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Učitavanje AppSearch dokumenata..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Učitavanje vrsta AppSearch shema..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Verzija sheme: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-hu/strings.xml b/appsearch/debug-view/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000..d6c2de3
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-hu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Nem találhatók Alkalmazáskereső-dokumentumok az adatbázisban. Ellenőrizze az adatbázis nevének érvényességét és a kiválasztott tárhelytípus helyességét."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nem találhatók Alkalmazáskereső-sématípusok. Ellenőrizze az adatbázis nevének érvényességét és a kiválasztott tárhelytípus helyességét."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Alkalmazáskereső-dokumentumok betöltése…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Alkalmazáskereső-sématípusok betöltése…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Séma-verziószám: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-hy/strings.xml b/appsearch/debug-view/src/main/res/values-hy/strings.xml
new file mode 100644
index 0000000..f078b38
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-hy/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Տվյալների շտեմարանում AppSearch-ի փաստաթղթեր չեն գտնվել։ Համոզվեք, որ տվյալների շտեմարանի անունը վավեր է և հիշողության ճիշտ տեսակն է ընտրված։"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch-ի սխեմաների տեսակներ չեն գտնվել։ Համոզվեք, որ տվյալների շտեմարանի անունը վավեր է և հիշողության ճիշտ տեսակն է ընտրված։"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch-ի փաստաթղթերը բեռնվում են..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch-ի սխեմաների տեսակները բեռնվում են..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Սխեմայի տարբերակը՝ %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-in/strings.xml b/appsearch/debug-view/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000..f01fd3c
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-in/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Tidak ada dokumen AppSearch yang ditemukan di database. Pastikan nama database valid dan jenis penyimpanan yang tepat telah dipilih."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Tidak ada jenis skema AppSearch yang ditemukan. Pastikan nama database valid dan jenis penyimpanan yang tepat telah dipilih."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Memuat dokumen AppSearch ..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Memuat jenis skema AppSearch ..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versi Skema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-is/strings.xml b/appsearch/debug-view/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000..81160a7
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-is/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Engin skjöl forritaleitar fundust í gagnagrunni. Staðfestu að heiti gagnagrunns sé gilt og að rétt geymslugerð sé valin."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Engar skemagerðir forritaleitar fundust. Staðfestu að heiti gagnagrunns sé gilt og að rétt geymslugerð sé valin."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Hleður skjölum forritaleitar..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Hleður skemagerðum forritaleitar..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Útgáfa skema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-it/strings.xml b/appsearch/debug-view/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..2924f40
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-it/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Nessun documento AppSearch trovato nel database. Verifica che il nome del database sia valido e di aver selezionato il tipo di spazio di archiviazione corretto."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nessun tipo di schema AppSearch trovato. Verifica che il nome del database sia valido e di aver selezionato il tipo di spazio di archiviazione corretto."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Caricamento dei documenti AppSearch in corso…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Caricamento dei tipi di schemi AppSearch in corso…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versione schema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-iw/strings.xml b/appsearch/debug-view/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000..0db6e25
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-iw/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"לא נמצאו מסמכי AppSearch במסד הנתונים. צריך לוודא שהשם של מסד הנתונים תקין ושבחרת בסוג האחסון הנכון."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"לא נמצאו סוגי סכימה של AppSearch. צריך לוודא שהשם של מסד הנתונים תקין ושבחרת בסוג האחסון הנכון."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"מסמכי AppSearch נטענים…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"סוגי הסכימה של AppSearch נטענים…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"גרסת הסכימה: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ja/strings.xml b/appsearch/debug-view/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..f5fad78
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ja/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"データベースに AppSearch ドキュメントはありませんでした。データベース名が有効であり、正しいストレージのタイプが選択されていることをご確認ください。"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch スキーマタイプは見つかりませんでした。データベース名が有効であり、正しいストレージのタイプが選択されていることをご確認ください。"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch ドキュメントを読み込んでいます..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch スキーマタイプを読み込んでいます..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"スキーマ バージョン: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ka/strings.xml b/appsearch/debug-view/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..ec7b4d4
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ka/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"AppSearch დოკუმენტები მონაცემთა ბაზაში ვერ მოიძებნა. დაადასტურეთ, რომ მონაცემთა ბაზის სახელი სწორია და არჩეულია მეხსიერების საჭირო ტიპი."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch-ის სქემის ტიპი ვერ მოიძებნა. დაადასტურეთ, რომ მონაცემთა ბაზის სახელი სწორია და არჩეულია მეხსიერების საჭირო ტიპი."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"მიმდინარეობს AppSearch დოკუმენტების ჩატვირთვა..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"მიმდინარეობს AppSearch-ის სქემის ტიპების ჩატვირთვა..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"სქემის ვერსია: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-kk/strings.xml b/appsearch/debug-view/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000..150203b
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-kk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Дерекқорда ешбір AppSearch құжаты табылмады. Дерекқор атауы жарамды екенін және дұрыс жад түрі таңдалғанын растаңыз."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Ешбір AppSearch схема түрі табылмады. Дерекқор атауы жарамды екенін және дұрыс жад түрі таңдалғанын растаңыз."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch құжаттары жүктелуде…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch схема түрлері жүктелуде…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Схема нұсқасы: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-km/strings.xml b/appsearch/debug-view/src/main/res/values-km/strings.xml
new file mode 100644
index 0000000..b8c14f9
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-km/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"រកមិនឃើញឯកសារ AppSearch នៅក្នុងមូលដ្ឋានទិន្នន័យទេ។ ផ្ទៀងផ្ទាត់ថាឈ្មោះមូលដ្ឋានទិន្នន័យមានភាពត្រឹមត្រូវ និងបានជ្រើសរើសប្រភេទទំហំផ្ទុកដែលត្រឹមត្រូវ។"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"រកមិនឃើញប្រភេទគ្រោងតាង AppSearch ទេ។ ផ្ទៀងផ្ទាត់ថាឈ្មោះមូលដ្ឋានទិន្នន័យមានភាពត្រឹមត្រូវ និងបានជ្រើសរើសប្រភេទទំហំផ្ទុកដែលត្រឹមត្រូវ។"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"កំពុងផ្ទុកឯកសារ AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"កំពុងផ្ទុកប្រភេទគ្រោងតាង AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"កំណែគ្រោងតាង៖ %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-kn/strings.xml b/appsearch/debug-view/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000..3b80458
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-kn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ಡೇಟಾಬೇಸ್ನಲ್ಲಿ ಯಾವುದೇ AppSearch ಡಾಕ್ಯುಮೆಂಟ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ. ಡೇಟಾಬೇಸ್ ಹೆಸರು ಮಾನ್ಯವಾಗಿದೆಯೆ ಮತ್ತು ಸರಿಯಾದ ಸಂಗ್ರಹಣೆಯ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"ಯಾವುದೇ AppSearch ರೂಪುರೇಷೆ ಪ್ರಕಾರಗಳು ಕಂಡುಬಂದಿಲ್ಲ. ಡೇಟಾಬೇಸ್ ಹೆಸರು ಮಾನ್ಯವಾಗಿದೆಯೆ ಮತ್ತು ಸರಿಯಾದ ಸಂಗ್ರಹಣೆಯ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch ಡಾಕ್ಯುಮೆಂಟ್ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch ರೂಪುರೇಷೆ ಪ್ರಕಾರಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"ರೂಪುರೇಷೆ ಆವೃತ್ತಿ: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ko/strings.xml b/appsearch/debug-view/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000..906947a
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ko/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"데이터베이스에서 AppSearch 문서를 찾을 수 없습니다. 데이터베이스 이름이 유효하고 올바른 저장공간 유형이 선택되어 있는지 확인하세요."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch 스키마 유형을 찾을 수 없습니다. 데이터베이스 이름이 유효하고 올바른 저장공간 유형이 선택되어 있는지 확인하세요."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch 문서 로드 중..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch 스키마 유형 로드 중..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"스키마 버전: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ky/strings.xml b/appsearch/debug-view/src/main/res/values-ky/strings.xml
new file mode 100644
index 0000000..499749c
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ky/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Дайындар базасынан AppSearch документтери табылган жок. Дайындар базасынын аталышы жарактуу экенин жана сактагычтын түрү туура тандалганын текшериңиз."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch cхемаларынын түрлөрү табылган жок. Дайындар базасынын аталышы жарактуу экенин жана сактагычтын түрү туура тандалганын текшериңиз."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch документтери жүктөлүүдө..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch cхемаларынын түрлөрү жүктөлүүдө..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Схеманын версиясы: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-lo/strings.xml b/appsearch/debug-view/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000..f69e046
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-lo/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ບໍ່ພົບເອກະສານ AppSearch ໃນຖານຂໍ້ມູນ. ກະລຸນາຢັ້ງຢືນວ່າຊື່ຖານຂໍ້ມູນນັ້ນຖືກຕ້ອງ ແລະ ໄດ້ເລືອກປະເພດບ່ອນຈັດເກັບຂໍ້ມູນທີ່ຖືກຕ້ອງແລ້ວ."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"ບໍ່ພົບປະເພດຮູບແບບ AppSearch. ກະລຸນາຢັ້ງຢືນວ່າຊື່ຖານຂໍ້ມູນນັ້ນຖືກຕ້ອງ ແລະ ໄດ້ເລືອກປະເພດບ່ອນຈັດເກັບຂໍ້ມູນທີ່ຖືກຕ້ອງແລ້ວ."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"ກຳລັງໂຫຼດເອກະສານ AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"ກຳລັງໂຫຼດປະເພດຮູບແບບ AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"ເວີຊັນຮູບແບບ: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-lt/strings.xml b/appsearch/debug-view/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000..c4f1d03
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-lt/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Duomenų bazėje nerasta jokių „AppSearch“ dokumentų. Įsitikinkite, kad nurodytas tinkamas duomenų bazės pavadinimas ir kad pasirinktas tinkamas saugyklos tipas."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nerasta jokių „AppSearch“ schemos tipų. Įsitikinkite, kad nurodytas tinkamas duomenų bazės pavadinimas ir kad pasirinktas tinkamas saugyklos tipas."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Įkeliami „AppSearch“ dokumentai..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Įkeliami „AppSearch“ schemos tipai..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schemos versija: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-lv/strings.xml b/appsearch/debug-view/src/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..b156b36
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-lv/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Datu bāzē netika atrasts neviens AppSearch dokuments. Pārbaudiet, vai datu bāzes nosaukums ir derīgs un vai tika atlasīts pareizais krātuves veids."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Netika atrasts neviens AppSearch shēmas veids. Pārbaudiet, vai datu bāzes nosaukums ir derīgs un vai tika atlasīts pareizais krātuves veids."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Notiek AppSearch dokumentu ielāde..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Notiek AppSearch shēmu veidu ielāde..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Shēmas versija: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-mk/strings.xml b/appsearch/debug-view/src/main/res/values-mk/strings.xml
new file mode 100644
index 0000000..e9ffe20
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-mk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Нема документи за AppSearch во базата на податоци. Потврдете дека името на базата на податоци е точно и дека е избран точниот вид меморија."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Не се пронајдени видови шема за AppSearch. Потврдете дека името на базата на податоци е точно и дека е избран точниот вид меморија."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Се вчитуваат документи за AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Се вчитуваат видови шема за AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Верзија на шема: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ml/strings.xml b/appsearch/debug-view/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..2a61573
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ml/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ഡാറ്റാബേസിൽ AppSearch ഡോക്യുമെന്റുകളൊന്നും കണ്ടെത്തിയില്ല. ഡാറ്റാബേസിന്റെ പേര് സാധുവാണെന്നും ശരിയായ സ്റ്റോറേജ് തരമാണ് തിരഞ്ഞെടുത്തതെന്നും പരിശോധിച്ചുറപ്പിക്കുക."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch സ്കീമ തരങ്ങളൊന്നും കണ്ടെത്തിയില്ല. ഡാറ്റാബേസിന്റെ പേര് സാധുവാണെന്നും ശരിയായ സ്റ്റോറേജ് തരമാണ് തിരഞ്ഞെടുത്തതെന്നും പരിശോധിച്ചുറപ്പിക്കുക."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch ഡോക്യുമെന്റുകൾ ലോഡ് ചെയ്യുന്നു..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch സ്കീമ തരങ്ങൾ ലോഡ് ചെയ്യുന്നു..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"സ്കീമ പതിപ്പ്: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-mn/strings.xml b/appsearch/debug-view/src/main/res/values-mn/strings.xml
new file mode 100644
index 0000000..04b5530
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-mn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Өгөгдлийн баазаас AppSearch-н документ олдсонгүй. Өгөгдлийн нэр хүчинтэй бөгөөд хадгалах сангийн зөв төрөл сонгосон эсэхийг баталгаажуулна уу."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch-н схемийн төрөл олдсонгүй. Өгөгдлийн нэр хүчинтэй бөгөөд хадгалах сангийн зөв төрөл сонгосон эсэхийг баталгаажуулна уу."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch-н документуудыг ачаалж байна..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch-н схемийн төрлийг ачаалж байна..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Схемийн хувилбар: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-mr/strings.xml b/appsearch/debug-view/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000..c0bee96
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-mr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"डेटाबेसमध्ये कोणतेही AppSearch दस्तऐवज मिळाले नाहीत. डेटाबेसचे नाव वैध असल्याची आणि योग्य स्टोरेज प्रकार निवडला असल्याची पडताळणी करा."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"कोणतेही AppSearch स्कीमा प्रकार आढळले नाहीत. डेटाबेसचे नाव वैध असल्याची आणि योग्य स्टोरेज प्रकार निवडला असल्याची पडताळणी करा."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch दस्तऐवज लोड करत आहे..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch स्कीमा प्रकार लोड करत आहे..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"स्कीमा आवृत्ती: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ms/strings.xml b/appsearch/debug-view/src/main/res/values-ms/strings.xml
new file mode 100644
index 0000000..e0396b3
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ms/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Tiada dokumen AppSearch dijumpai dalam pangkalan data. Sahkan bahawa nama pangkalan data adalah sah dan jenis storan yang dipilih adalah betul."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Jenis skema AppSearch tidak dijumpai. Sahkan bahawa nama pangkalan data adalah sah dan jenis storan yang dipilih adalah betul."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Memuatkan dokumen AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Memuatkan jenis skema AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versi Skema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-my/strings.xml b/appsearch/debug-view/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000..ae265a1
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-my/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ဒေတာဘေ့စ်တွင် AppSearch မှတ်တမ်းများ မတွေ့ပါ။ ဒေတာဘေ့စ် အမည်သည် မှန်ကန်ပြီး မှန်ကန်သော သိုလှောင်ခန်းအမျိုးအစားကို ရွေးထားကြောင်း အတည်ပြုရန် စစ်ဆေးပါ။"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch ရှေမားအမျိုးအစားများ မတွေ့ပါ။ ဒေတာဘေ့စ် အမည်သည် မှန်ကန်ပြီး မှန်ကန်သော သိုလှောင်ခန်းအမျိုးအစားကို ရွေးထားကြောင်း အတည်ပြုရန် စစ်ဆေးပါ။"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch မှတ်တမ်းများကို ဖွင့်နေသည်..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch ရှေမားအမျိုးအစားများကို ဖွင့်နေသည်..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"ရှေမား ဗားရှင်း- %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-nb/strings.xml b/appsearch/debug-view/src/main/res/values-nb/strings.xml
new file mode 100644
index 0000000..7950119
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-nb/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Fant ingen AppSearch-dokumenter i databasen. Bekreft at databasenavnet er gyldig, og at riktig lagringstype er valgt."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Fant ingen AppSearch-oppsettyper. Bekreft at databasenavnet er gyldig, og at riktig lagringstype er valgt."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Laster inn AppSearch-dokumenter …"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Laster inn AppSearch-oppsettyper …"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Oppsettversjon: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ne/strings.xml b/appsearch/debug-view/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..f96675e
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ne/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"डेटाबेसमा कुनै पनि AppSearch डकुमेन्ट फेला परेन। डेटाबेसको नाम वैध छ र डिभाइसको सही प्रकारको भण्डारण चयन गरिएको छ भन्ने कुरा पुष्टि गर्नुहोस्।"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"कुनै पनि प्रकारको AppSearch योजना फेला परेन। डेटाबेसको नाम वैध छ र डिभाइसको सही प्रकारको भण्डारण चयन गरिएको छ भन्ने कुरा पुष्टि गर्नुहोस्।"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch डकुमेन्टहरू लोड गरिँदै छ..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"विभिन्न प्रकारका AppSearch योजना लोड गरिँदै छन्..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"योजनाको संस्करण: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-nl/strings.xml b/appsearch/debug-view/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000..2ae5bf7
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-nl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Geen AppSearch-documenten gevonden in database. Check of de databasenaam geldig is en of het juiste opslagtype is geselecteerd."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Geen AppSearch-schematypen gevonden. Check of de databasenaam geldig is en of het juiste opslagtype is geselecteerd."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch-documenten laden..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch-schematypen laden..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schemaversie: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-or/strings.xml b/appsearch/debug-view/src/main/res/values-or/strings.xml
new file mode 100644
index 0000000..a026025
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-or/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ଡାଟାବେସରେ କୌଣସି AppSearch ଡକ୍ୟୁମେଣ୍ଟ ମିଳିଲା ନାହିଁ। ଡାଟାବେସର ନାମ ବୈଧ ଥିବା ଏବଂ ସଠିକ୍ ଷ୍ଟୋରେଜ୍ ପ୍ରକାରକୁ ଚୟନ କରାଯାଇଥିବା ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"କୌଣସି AppSearch ସ୍କିମା ପ୍ରକାର ମିଳିଲା ନାହିଁ। ଡାଟାବେସର ନାମ ବୈଧ ଥିବା ଏବଂ ସଠିକ୍ ଷ୍ଟୋରେଜ୍ ପ୍ରକାରକୁ ଚୟନ କରାଯାଇଥିବା ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch ଡକ୍ୟୁମେଣ୍ଟଗୁଡ଼ିକ ଲୋଡ୍ ହେଉଛି..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch ସ୍କିମା ପ୍ରକାରଗୁଡ଼ିକ ଲୋଡ୍ ହେଉଛି..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"ସ୍କିମା ସଂସ୍କରଣ: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-pa/strings.xml b/appsearch/debug-view/src/main/res/values-pa/strings.xml
new file mode 100644
index 0000000..b7c0c95
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-pa/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ਡਾਟਾਬੇਸ ਵਿੱਚ ਕੋਈ AppSearch ਦਸਤਾਵੇਜ਼ ਨਹੀਂ ਮਿਲੇ। ਪੁਸ਼ਟੀ ਕਰੋ ਕਿ ਡਾਟਾਬੇਸ ਦਾ ਨਾਮ ਵੈਧ ਹੈ ਅਤੇ ਸਟੋਰੇਜ ਦੀ ਇੱਕ ਸਹੀ ਕਿਸਮ ਚੁਣੀ ਗਈ ਸੀ।"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch ਸਕੀਮਾ ਦੀ ਕੋਈ ਕਿਸਮ ਨਹੀਂ ਮਿਲੀ। ਪੁਸ਼ਟੀ ਕਰੋ ਕਿ ਡਾਟਾਬੇਸ ਦਾ ਨਾਮ ਵੈਧ ਹੈ ਅਤੇ ਸਟੋਰੇਜ ਦੀ ਇੱਕ ਸਹੀ ਕਿਸਮ ਚੁਣੀ ਗਈ ਸੀ।"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch ਦਸਤਾਵੇਜ਼ਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch ਸਕੀਮਾ ਦੀਆਂ ਕਿਸਮਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"ਸਕੀਮਾ ਵਰਜਨ: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-pl/strings.xml b/appsearch/debug-view/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..0cab68f
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-pl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"W bazie danych nie znaleziono dokumentów AppSearch. Sprawdź, czy nazwa bazy danych jest prawidłowa i czy wybrano odpowiedni typ pamięci."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nie znaleziono typów schematów AppSearch. Sprawdź, czy nazwa bazy danych jest prawidłowa i czy wybrano odpowiedni typ pamięci."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Wczytuję dokumenty AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Wczytuję typy schematów AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Wersja schematu: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-pt-rBR/strings.xml b/appsearch/debug-view/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..35bc29b
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Não foram encontrados documentos do AppSearch no banco de dados. Verifique se o nome do banco de dados é válido e se você selecionou o tipo de armazenamento correto."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Não foram encontrados tipos de esquema do AppSearch. Verifique se o nome do banco de dados é válido e se você selecionou o tipo de armazenamento correto."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Carregando documentos do AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Carregando tipos de esquema do AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versão do esquema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-pt-rPT/strings.xml b/appsearch/debug-view/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..a4fb83f
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Não foram encontrados documentos da AppSearch na base de dados. Valide o nome da base de dados e confirme se foi selecionado o tipo de armazenamento correto."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Não foram encontrados tipos de esquemas da AppSearch. Valide o nome da base de dados e confirme se foi selecionado o tipo de armazenamento correto."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"A carregar os documentos da AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"A carregar os tipos de esquemas da AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versão do esquema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-pt/strings.xml b/appsearch/debug-view/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..35bc29b
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-pt/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Não foram encontrados documentos do AppSearch no banco de dados. Verifique se o nome do banco de dados é válido e se você selecionou o tipo de armazenamento correto."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Não foram encontrados tipos de esquema do AppSearch. Verifique se o nome do banco de dados é válido e se você selecionou o tipo de armazenamento correto."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Carregando documentos do AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Carregando tipos de esquema do AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versão do esquema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ro/strings.xml b/appsearch/debug-view/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000..f5c4056
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ro/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Nu s-au găsit documente AppSearch în baza de date. Verificați dacă numele bazei de date este valid și s-a selectat tipul corect de stocare."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nu s-au găsit tipuri de scheme AppSearch. Verificați dacă numele bazei de date este valid și s-a selectat tipul corect de stocare."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Se încarcă documentele AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Se încarcă tipurile de scheme AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versiunea schemei: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ru/strings.xml b/appsearch/debug-view/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..0fef687
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ru/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"В базе данных нет документов AppSearch. Убедитесь, что вы правильно указали название базы данных и тип хранилища."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Типы схемы AppSearch не найдены. Убедитесь, что вы правильно указали название базы данных и тип хранилища."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Загрузка документов AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Загрузка типов схемы AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Версия схемы: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-si/strings.xml b/appsearch/debug-view/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000..37564f3
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-si/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"දත්ත සමුදායේ AppSearch ලේඛන හමු නොවීය. දත්ත සමුදායේ නම වලංගු බව සහ නිවැරදි ගබඩා වර්ගය තෝරා ගත් බව සත්යාපනය කරන්න."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch නිරූපණ වර්ග හමු විය. දත්ත සමුදායේ නම වලංගු බව සහ නිවැරදි ගබඩා වර්ගය තෝරා ගත් බව සත්යාපනය කරන්න."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch ලේඛන පූරණය කරමින්..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch නිරූපණ වර්ග පූරණය කරමින්..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"නිරූපණ අනුවාදය: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-sk/strings.xml b/appsearch/debug-view/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000..acae3cb
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-sk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"V databáze sa nenašli žiadne dokumenty služby AppSearch. Overte, či je názov databázy platný a či bol vybraný správny typ priestoru."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nenašli sa žiadne typy schém služby AppSearch. Overte, či je názov databázy platný a či bol vybraný správny typ priestoru."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Načítavajú sa dokumenty služby AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Načítavajú sa typy schém služby AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Verzia schémy: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-sl/strings.xml b/appsearch/debug-view/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000..bf2015e
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-sl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"V zbirki podatkov ni bil najden noben dokument AppSearch. Preverite, ali je ime zbirke podatkov veljavno in ali je bila izbrana prava vrsta shrambe."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Najdena ni bila nobena vrsta sheme AppSearch. Preverite, ali je ime zbirke podatkov veljavno in ali je bila izbrana prava vrsta shrambe."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Nalaganje dokumentov AppSearch …"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Nalaganje vrst shem AppSearch …"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Različica sheme: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-sq/strings.xml b/appsearch/debug-view/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000..f7e82bf
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-sq/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Nuk u gjet asnjë dokument i AppSearch në bazën e të dhënave. Verifiko që emri i bazës së të dhënave është i vlefshëm dhe që është zgjedhur lloji i duhur i hapësirës ruajtëse."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Nuk u gjet asnjë lloj i skemave së AppSearch. Verifiko që emri i bazës së të dhënave është i vlefshëm dhe që është zgjedhur lloji i duhur i hapësirës ruajtëse."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Dokumentet e AppSearch po ngarkohen..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Llojet e skemave të AppSearch po ngarkohen..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Versioni i skemës: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-sr/strings.xml b/appsearch/debug-view/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000..660dda9
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-sr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Није пронађет ниједан AppSearch документ у бази података. Верификујте да је база података важећа и да је изабран исправан тип меморијског простора."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Није пронађен ниједан тип AppSearch шеме. Верификујте да је база података важећа и да је изабран исправан тип меморијског простора."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Учитавају се AppSearch документи..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Типови AppSearch шеме се учитавају..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Верзија шеме: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-sv/strings.xml b/appsearch/debug-view/src/main/res/values-sv/strings.xml
new file mode 100644
index 0000000..df6a335
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-sv/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Inget AppSearch-dokument hittades i databasen. Kontrollera att databasnamnet är giltigt och att rätt lagringstyp har angetts."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Ingen AppSearch-schematyp hittades. Kontrollera att databasnamnet är giltigt och att rätt lagringstyp har angetts."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Läser in AppSearch-dokument …"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Läser in AppSearch-schematyper …"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Schemaversion: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-sw/strings.xml b/appsearch/debug-view/src/main/res/values-sw/strings.xml
new file mode 100644
index 0000000..9750eb9
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-sw/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Hakuna hati za Utafutaji wa Programu zilizopatikana katika hifadhidata. Thibitisha kuwa jina la hifadhidata ni sahihi na aina sahihi ya hifadhi imechaguliwa."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Hakuna aina za taratibu za Utafutaji wa Programu zilizopatikana. Thibitisha kuwa jina la hifadhidata ni sahihi na aina sahihi ya hifadhi imechaguliwa."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Inapakia hati za Utafutaji wa Programu..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Inapakia aina za taratibu za Utafutaji wa Programu..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Toleo la Taratibu: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ta/strings.xml b/appsearch/debug-view/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000..3d44fe9
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ta/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"தரவுத்தளத்தில் AppSearch ஆவணங்கள் எதுவுமில்லை. தரவுத்தளத்தின் பெயர் சரியானதுதான் என்பதையும் சரியான சேமிப்பக வகை தேர்ந்தெடுக்கப்பட்டுள்ளதையும் உறுதிசெய்யவும்."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch திட்டப்பணித் தரவு வகைகள் எதுவுமில்லை. தரவுத்தளத்தின் பெயர் சரியானதுதான் என்பதையும் சரியான சேமிப்பக வகை தேர்ந்தெடுக்கப்பட்டுள்ளதையும் உறுதிசெய்யவும்."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch ஆவணங்களை ஏற்றுகிறது..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch திட்டப்பணித் தரவு வகைகளை ஏற்றுகிறது..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"திட்டப்பணித் தரவுப் பதிப்பு: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-te/strings.xml b/appsearch/debug-view/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000..44a1570
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-te/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"డేటాబేస్లో AppSearch డాక్యుమెంట్లు కనుగొనబడలేదు. డేటాబేస్ పేరు చెల్లుబాటులో ఉందని వెరిఫై చేయండి, సరైన స్టోరేజ్ రకం ఎంచుకోబడింది."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch స్కీమా రకాలు కనుగొనబడలేదు. డేటాబేస్ పేరు చెల్లుబాటులో ఉందని వెరిఫై చేయండి, సరైన స్టోరేజ్ రకం ఎంచుకోబడింది."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch డాక్యుమెంట్లను లోడ్ చేస్తోంది..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch స్కీమా రకాలు లోడ్ అవుతున్నయి..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"స్కీమా వెర్షన్: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-th/strings.xml b/appsearch/debug-view/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000..af1bd8d
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-th/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ไม่พบเอกสาร AppSearch ในฐานข้อมูล ตรวจสอบความถูกต้องของชื่อฐานข้อมูลและประเภทพื้นที่เก็บข้อมูลที่เลือก"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"ไม่พบประเภทสคีมาของ AppSearch ตรวจสอบความถูกต้องของชื่อฐานข้อมูลและประเภทพื้นที่เก็บข้อมูลที่เลือก"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"กำลังโหลดเอกสาร AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"กำลังโหลดประเภทสคีมาของ AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"เวอร์ชันของสคีมา: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-tl/strings.xml b/appsearch/debug-view/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000..febd912
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-tl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Walang nakitang dokumento ng AppSearch sa database. I-verify na valid ang pangalan ng database at tamang uri ng storage ang napili."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Walang nakitang uri ng schema ng AppSearch. I-verify na valid ang pangalan ng database at tamang uri ng storage ang napili."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Nilo-load ang mga dokumento ng AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Naglo-load ng mga uri ng schema ng AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Bersyon ng Schema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-tr/strings.xml b/appsearch/debug-view/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..cb5e867
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-tr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Veritabanında AppSearch belgesi bulunamadı. Veritabanı adının geçerli olduğunu ve doğru depolama türünün seçildiğini doğrulayın."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch şema türü bulunamadı. Veritabanı adının geçerli olduğunu ve doğru depolama türünün seçildiğini doğrulayın."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch belgeleri yükleniyor..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch şema türleri yükleniyor..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Şema Sürümü: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-uk/strings.xml b/appsearch/debug-view/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000..ce896d3
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-uk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"У базі даних немає документів AppSearch. Підтвердьте, що назва бази даних дійсна й вибрано правильний тип сховища."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Типів схеми AppSearch не знайдено. Підтвердьте, що назва бази даних дійсна й вибрано правильний тип сховища."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Завантаження документів AppSearch…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Завантаження типів схеми AppSearch…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Версія схеми: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-ur/strings.xml b/appsearch/debug-view/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..c88f789
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-ur/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"ڈیٹا بیس میں کوئی AppSearch دستاویز نہیں ملا۔ توثیق کریں کہ ڈیٹا بیس کا نام درست ہے اور اسٹوریج کی صحیح قسم منتخب کی گئی تھی۔"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"AppSearch سکیما کی کوئی قسم نہیں ملی۔ توثیق کریں کہ ڈیٹا بیس کا نام درست ہے اور اسٹوریج کی صحیح قسم منتخب کی گئی تھی۔"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch دستاویزات لوڈ ہو رہے ہیں..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch سکیما کی اقسام لوڈ ہو رہی ہیں..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"سکیما ورژن: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-uz/strings.xml b/appsearch/debug-view/src/main/res/values-uz/strings.xml
new file mode 100644
index 0000000..46fa912
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-uz/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Ma’lumotlar bazasidan hech qanday AppSearch hujjatlari topilmadi. Ma’lumotlar bazasi yaroqli va xatosiz xotira tanlanganini tasdiqlang."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Hech qanday AppSearch sxemasi topilmadi. Ma’lumotlar bazasi yaroqli va xatosiz xotira tanlanganini tasdiqlang."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"AppSearch hujjatlari yuklanmoqda..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"AppSearch sxemasi turlari yuklanmoqda..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Sxema versiyasi: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-vi/strings.xml b/appsearch/debug-view/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000..7024d29
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-vi/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Không tìm thấy tài liệu AppSearch trong cơ sở dữ liệu. Hãy xác minh rằng tên cơ sở dữ liệu là hợp lệ và bạn đã chọn đúng loại bộ nhớ."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Không tìm thấy loại giản đồ AppSearch. Hãy xác minh rằng tên cơ sở dữ liệu là hợp lệ và bạn đã chọn đúng loại bộ nhớ."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Đang tải các tài liệu AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Đang tải các loại giản đồ AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Phiên bản giản đồ: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-zh-rCN/strings.xml b/appsearch/debug-view/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..ec6d36e
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"未在数据库中找到任何 AppSearch 文档。请确认数据库名称有效且选择的存储类型正确。"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"未找到任何 AppSearch 架构类型。请确认数据库名称有效且选择的存储类型正确。"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"正在加载 AppSearch 文档…"</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"正在加载 AppSearch 架构类型…"</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"架构版本:%d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-zh-rHK/strings.xml b/appsearch/debug-view/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..a2e6f05
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-zh-rHK/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"資料庫中找不到 AppSearch 文件。請確認資料庫名稱有效,並選取正確的儲存空間類型。"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"找不到 AppSearch 結構定義類型。請確認資料庫名稱有效,並選取正確的儲存空間類型。"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"正在載入 AppSearch 文件..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"正在載入 AppSearch 結構定義類型..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"結構定義版本:%d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-zh-rTW/strings.xml b/appsearch/debug-view/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..a2e6f05
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"資料庫中找不到 AppSearch 文件。請確認資料庫名稱有效,並選取正確的儲存空間類型。"</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"找不到 AppSearch 結構定義類型。請確認資料庫名稱有效,並選取正確的儲存空間類型。"</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"正在載入 AppSearch 文件..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"正在載入 AppSearch 結構定義類型..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"結構定義版本:%d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values-zu/strings.xml b/appsearch/debug-view/src/main/res/values-zu/strings.xml
new file mode 100644
index 0000000..ea093a0
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values-zu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="appsearch_no_documents_error" msgid="2371906054857961621">"Awekho amadokhumenti we-AppSearch atholakele kusizindalwazi. Qinisekisa ukuthi igama lesizindalwazi livumelekile nokuthi kukhethwe uhlobo lwesitoreji esifanele."</string>
+ <string name="appsearch_no_schema_types_error" msgid="6040453370924007774">"Azikho izinhlobo ze-schema se-AppSearch ezitholakele. Qinisekisa ukuthi igama lesizindalwazi livumelekile nokuthi kukhethwe uhlobo lwesitoreji esifanele."</string>
+ <string name="appsearch_documents_loading" msgid="3079225167662255666">"Ilayisha amadokhumenti we-AppSearch..."</string>
+ <string name="appsearch_schema_types_loading" msgid="5223743742396711620">"Ilayisha izinhlobo ze-schema se-AppSearch..."</string>
+ <string name="appsearch_schema_version" msgid="5289450345246068014">"Uhlobo lwe-Schema: %d"</string>
+</resources>
diff --git a/appsearch/debug-view/src/main/res/values/strings.xml b/appsearch/debug-view/src/main/res/values/strings.xml
new file mode 100644
index 0000000..e6effe7
--- /dev/null
+++ b/appsearch/debug-view/src/main/res/values/strings.xml
@@ -0,0 +1,31 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="appsearch_no_documents_error">No AppSearch documents found in database. Verify
+ that the database name is valid and the correct storage type was selected.
+ </string>
+ <string name="appsearch_no_schema_types_error">No AppSearch schema types found. Verify that the
+ database name is valid and the correct storage type was selected.
+ </string>
+
+ <string name="appsearch_documents_loading">Loading AppSearch documents...
+ </string>
+ <string name="appsearch_schema_types_loading">Loading AppSearch schema types...
+ </string>
+
+ <string name="appsearch_schema_version">Schema Version: %d </string>
+</resources>
diff --git a/appsearch/exportToFramework.py b/appsearch/exportToFramework.py
index c7b91f5..7bfc923 100755
--- a/appsearch/exportToFramework.py
+++ b/appsearch/exportToFramework.py
@@ -20,6 +20,32 @@
#
# Example usage (from root dir of androidx workspace):
# $ ./frameworks/support/appsearch/exportToFramework.py "$HOME/android/master" "<jetpack changeid>"
+
+# Special directives supported by this script:
+#
+# Causes the file where it appears to not be copied at all:
+# @exportToFramework:skipFile()
+#
+# Causes the text appearing between startStrip() and endStrip() to be removed during export:
+# // @exportToFramework:startStrip() ... // @exportToFramework:endStrip()
+#
+# Replaced with @hide:
+# <!--@exportToFramework:hide-->
+#
+# Replaced with @CurrentTimeMillisLong:
+# /*@exportToFramework:CurrentTimeMillisLong*/
+#
+# Removes the text appearing between ifJetpack() and else(), and causes the text appearing between
+# else() and --> to become uncommented, to support framework-only Javadocs:
+# <!--@exportToFramework:ifJetpack()-->
+# Jetpack-only Javadoc
+# <!--@exportToFramework:else()
+# Framework-only Javadoc
+# -->
+# Note: Using the above pattern, you can hide a method in Jetpack but unhide it in Framework like
+# this:
+# <!--@exportToFramework:ifJetpack()-->@hide<!--@exportToFramework:else()-->
+
import os
import re
import subprocess
@@ -50,6 +76,7 @@
def __init__(self, jetpack_appsearch_root, framework_appsearch_root):
self._jetpack_appsearch_root = jetpack_appsearch_root
self._framework_appsearch_root = framework_appsearch_root
+ self._written_files = []
def _PruneDir(self, dir_to_prune):
for walk_path, walk_folders, walk_files in os.walk(dir_to_prune):
@@ -74,18 +101,36 @@
with open(dest_path, 'w') as fh:
fh.write(contents)
- # Run formatter
- google_java_format_cmd = [GOOGLE_JAVA_FORMAT, '--aosp', '-i', dest_path]
- print('$ ' + ' '.join(google_java_format_cmd))
- subprocess.check_call(google_java_format_cmd, cwd=self._framework_appsearch_root)
+ # Save file for future formatting
+ self._written_files.append(dest_path)
def _TransformCommonCode(self, contents):
- # Apply strips
+ # Apply stripping
contents = re.sub(
- r'\/\/ @exportToFramework:startStrip\(\).*?\/\/ @exportToFramework:endStrip\(\)',
- '',
- contents,
- flags=re.DOTALL)
+ r'\/\/ @exportToFramework:startStrip\(\).*?\/\/ @exportToFramework:endStrip\(\)',
+ '',
+ contents,
+ flags=re.DOTALL)
+
+ # Apply if/elses in javadocs
+ contents = re.sub(
+ r'<!--@exportToFramework:ifJetpack\(\)-->.*?<!--@exportToFramework:else\(\)(.*?)-->',
+ r'\1',
+ contents,
+ flags=re.DOTALL)
+
+ # Add additional imports if required
+ imports_to_add = []
+ if '@exportToFramework:CurrentTimeMillisLong' in contents:
+ imports_to_add.append('android.annotation.CurrentTimeMillisLong')
+ if '@exportToFramework:UnsupportedAppUsage' in contents:
+ imports_to_add.append('android.compat.annotation.UnsupportedAppUsage')
+ for import_to_add in imports_to_add:
+ contents = re.sub(
+ r'^(\s*package [^;]+;\s*)$', r'\1\nimport %s;\n' % import_to_add, contents,
+ flags=re.MULTILINE)
+
+ # Apply in-place replacements
return (contents
.replace('androidx.appsearch.app', 'android.app.appsearch')
.replace(
@@ -104,20 +149,24 @@
.replace(
'androidx.core.util.ObjectsCompat',
'java.util.Objects')
+ # Preconditions.checkNotNull is replaced with Objects.requireNonNull. We add both
+ # imports and let google-java-format sort out which one is unused.
.replace(
- 'androidx.core.util.Preconditions',
- 'com.android.internal.util.Preconditions')
+ 'import androidx.core.util.Preconditions;',
+ 'import java.util.Objects; import com.android.internal.util.Preconditions;')
.replace('import androidx.annotation.RestrictTo;', '')
.replace('@RestrictTo(RestrictTo.Scope.LIBRARY)', '')
.replace('@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)', '')
+ .replace('Preconditions.checkNotNull(', 'Objects.requireNonNull(')
.replace('ObjectsCompat.', 'Objects.')
+ .replace('/*@exportToFramework:CurrentTimeMillisLong*/', '@CurrentTimeMillisLong')
+ .replace('/*@exportToFramework:UnsupportedAppUsage*/', '@UnsupportedAppUsage')
+ .replace('<!--@exportToFramework:hide-->', '@hide')
.replace('// @exportToFramework:skipFile()', '')
)
def _TransformTestCode(self, contents):
contents = (contents
- .replace('org.junit.Assert.assertThrows', 'org.testng.Assert.expectThrows')
- .replace('assertThrows(', 'expectThrows(')
.replace('androidx.appsearch.app.util.', 'com.android.server.appsearch.testing.')
.replace(
'package androidx.appsearch.app.util;',
@@ -155,7 +204,7 @@
api_test_dest_dir = os.path.join(self._framework_appsearch_root, FRAMEWORK_API_TEST_ROOT)
# CTS tests
- cts_test_source_dir = os.path.join(api_test_source_dir, 'app/cts')
+ cts_test_source_dir = os.path.join(api_test_source_dir, 'cts')
cts_test_dest_dir = os.path.join(self._framework_appsearch_root, FRAMEWORK_CTS_TEST_ROOT)
# Test utils
@@ -246,7 +295,7 @@
.replace('package androidx.appsearch',
'package com.android.server.appsearch.external')
.replace('com.google.android.icing.proto.',
- 'com.android.server.appsearch.proto.')
+ 'com.android.server.appsearch.icing.proto.')
.replace('com.google.android.icing.protobuf.',
'com.android.server.appsearch.protobuf.')
)
@@ -254,9 +303,15 @@
self._TransformAndCopyFolder(
impl_test_source_dir, impl_test_dest_dir, transform_func=_TransformImplTestCode)
+ def _FormatWrittenFiles(self):
+ google_java_format_cmd = [GOOGLE_JAVA_FORMAT, '--aosp', '-i'] + self._written_files
+ print('$ ' + ' '.join(google_java_format_cmd))
+ subprocess.check_call(google_java_format_cmd, cwd=self._framework_appsearch_root)
+
def ExportCode(self):
self._ExportApiCode()
self._ExportImplCode()
+ self._FormatWrittenFiles()
def WriteChangeIdFile(self, changeid):
"""Copies the changeid of the most recent public CL into a file on the framework side.
diff --git a/appsearch/local-storage/api/current.txt b/appsearch/local-storage/api/current.txt
index e0d39ea..5eb0af5 100644
--- a/appsearch/local-storage/api/current.txt
+++ b/appsearch/local-storage/api/current.txt
@@ -5,22 +5,15 @@
method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchSession!> createSearchSession(androidx.appsearch.localstorage.LocalStorage.SearchContext);
}
- public static final class LocalStorage.GlobalSearchContext {
- }
-
- public static final class LocalStorage.GlobalSearchContext.Builder {
- ctor public LocalStorage.GlobalSearchContext.Builder(android.content.Context);
- method public androidx.appsearch.localstorage.LocalStorage.GlobalSearchContext build();
- }
-
public static final class LocalStorage.SearchContext {
method public String getDatabaseName();
+ method public java.util.concurrent.Executor getWorkerExecutor();
}
public static final class LocalStorage.SearchContext.Builder {
- ctor public LocalStorage.SearchContext.Builder(android.content.Context);
+ ctor public LocalStorage.SearchContext.Builder(android.content.Context, String);
method public androidx.appsearch.localstorage.LocalStorage.SearchContext build();
- method public androidx.appsearch.localstorage.LocalStorage.SearchContext.Builder setDatabaseName(String);
+ method public androidx.appsearch.localstorage.LocalStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
}
}
diff --git a/appsearch/local-storage/api/public_plus_experimental_current.txt b/appsearch/local-storage/api/public_plus_experimental_current.txt
index e0d39ea..5eb0af5 100644
--- a/appsearch/local-storage/api/public_plus_experimental_current.txt
+++ b/appsearch/local-storage/api/public_plus_experimental_current.txt
@@ -5,22 +5,15 @@
method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchSession!> createSearchSession(androidx.appsearch.localstorage.LocalStorage.SearchContext);
}
- public static final class LocalStorage.GlobalSearchContext {
- }
-
- public static final class LocalStorage.GlobalSearchContext.Builder {
- ctor public LocalStorage.GlobalSearchContext.Builder(android.content.Context);
- method public androidx.appsearch.localstorage.LocalStorage.GlobalSearchContext build();
- }
-
public static final class LocalStorage.SearchContext {
method public String getDatabaseName();
+ method public java.util.concurrent.Executor getWorkerExecutor();
}
public static final class LocalStorage.SearchContext.Builder {
- ctor public LocalStorage.SearchContext.Builder(android.content.Context);
+ ctor public LocalStorage.SearchContext.Builder(android.content.Context, String);
method public androidx.appsearch.localstorage.LocalStorage.SearchContext build();
- method public androidx.appsearch.localstorage.LocalStorage.SearchContext.Builder setDatabaseName(String);
+ method public androidx.appsearch.localstorage.LocalStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
}
}
diff --git a/appsearch/local-storage/api/restricted_current.txt b/appsearch/local-storage/api/restricted_current.txt
index e0d39ea..5eb0af5 100644
--- a/appsearch/local-storage/api/restricted_current.txt
+++ b/appsearch/local-storage/api/restricted_current.txt
@@ -5,22 +5,15 @@
method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchSession!> createSearchSession(androidx.appsearch.localstorage.LocalStorage.SearchContext);
}
- public static final class LocalStorage.GlobalSearchContext {
- }
-
- public static final class LocalStorage.GlobalSearchContext.Builder {
- ctor public LocalStorage.GlobalSearchContext.Builder(android.content.Context);
- method public androidx.appsearch.localstorage.LocalStorage.GlobalSearchContext build();
- }
-
public static final class LocalStorage.SearchContext {
method public String getDatabaseName();
+ method public java.util.concurrent.Executor getWorkerExecutor();
}
public static final class LocalStorage.SearchContext.Builder {
- ctor public LocalStorage.SearchContext.Builder(android.content.Context);
+ ctor public LocalStorage.SearchContext.Builder(android.content.Context, String);
method public androidx.appsearch.localstorage.LocalStorage.SearchContext build();
- method public androidx.appsearch.localstorage.LocalStorage.SearchContext.Builder setDatabaseName(String);
+ method public androidx.appsearch.localstorage.LocalStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
}
}
diff --git a/appsearch/local-storage/build.gradle b/appsearch/local-storage/build.gradle
index cb37d65..046289f 100644
--- a/appsearch/local-storage/build.gradle
+++ b/appsearch/local-storage/build.gradle
@@ -51,6 +51,7 @@
targets "icing"
}
}
+ multiDexEnabled true
}
externalNativeBuild {
cmake {
@@ -75,9 +76,11 @@
implementation("androidx.concurrent:concurrent-futures:1.0.0")
implementation("androidx.core:core:1.2.0")
+ androidTestImplementation(libs.multidex)
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRules)
androidTestImplementation(libs.truth)
+ androidTestImplementation(libs.mockitoAndroid)
//TODO(b/149787478) upgrade and link to Dependencies.kt
androidTestImplementation("junit:junit:4.13")
}
diff --git a/appsearch/local-storage/proguard-rules.pro b/appsearch/local-storage/proguard-rules.pro
index b18f891..82c4b719 100644
--- a/appsearch/local-storage/proguard-rules.pro
+++ b/appsearch/local-storage/proguard-rules.pro
@@ -18,3 +18,13 @@
-keepclassmembers class * extends com.google.android.icing.protobuf.GeneratedMessageLite {
<fields>;
}
+-keep class com.google.android.icing.BreakIteratorBatcher { *; }
+-keepclassmembers public class com.google.android.icing.IcingSearchEngine {
+ private long nativePointer;
+}
+
+# This prevents the names of native methods from being obfuscated and prevents
+# UnsatisfiedLinkErrors.
+-keepclasseswithmembernames,includedescriptorclasses class * {
+ native <methods>;
+}
diff --git a/appsearch/local-storage/src/androidTest/AndroidManifest.xml b/appsearch/local-storage/src/androidTest/AndroidManifest.xml
index 7638c0f..014f4a2 100644
--- a/appsearch/local-storage/src/androidTest/AndroidManifest.xml
+++ b/appsearch/local-storage/src/androidTest/AndroidManifest.xml
@@ -16,4 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.appsearch.localstorage.test">
+ <!-- Required for junit TemporaryFolder rule on older API levels -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java
index 4ce9593..1662d16 100644
--- a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java
@@ -16,30 +16,50 @@
package androidx.appsearch.localstorage;
+import static androidx.appsearch.localstorage.util.PrefixUtil.addPrefixToDocument;
+import static androidx.appsearch.localstorage.util.PrefixUtil.createPrefix;
+import static androidx.appsearch.localstorage.util.PrefixUtil.removePrefixesFromDocument;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import android.content.Context;
+import android.os.Process;
+
+import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.GenericDocument;
import androidx.appsearch.app.SearchResult;
import androidx.appsearch.app.SearchResultPage;
import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.appsearch.app.StorageInfo;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.localstorage.converter.GenericDocumentToProtoConverter;
-import androidx.appsearch.localstorage.converter.SchemaToProtoConverter;
+import androidx.appsearch.localstorage.stats.InitializeStats;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
+import androidx.appsearch.localstorage.util.PrefixUtil;
+import androidx.collection.ArrayMap;
+import androidx.collection.ArraySet;
+import androidx.test.core.app.ApplicationProvider;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.GetOptimizeInfoResultProto;
+import com.google.android.icing.proto.PersistType;
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.PutResultProto;
import com.google.android.icing.proto.SchemaProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchSpecProto;
+import com.google.android.icing.proto.StatusProto;
+import com.google.android.icing.proto.StorageInfoProto;
import com.google.android.icing.proto.StringIndexingConfig;
import com.google.android.icing.proto.TermMatchType;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
@@ -47,37 +67,30 @@
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class AppSearchImplTest {
+ /**
+ * Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
+ */
+ private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
@Rule
public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
private AppSearchImpl mAppSearchImpl;
- private SchemaTypeConfigProto mVisibilitySchemaProto;
@Before
public void setUp() throws Exception {
- mAppSearchImpl = AppSearchImpl.create(mTemporaryFolder.newFolder());
-
- AppSearchSchema visibilitySchema = VisibilityStore.SCHEMA;
-
- // We need to rewrite the schema type to follow AppSearchImpl's prefixing scheme.
- AppSearchSchema.Builder rewrittenVisibilitySchema =
- new AppSearchSchema.Builder(AppSearchImpl.createPrefix(VisibilityStore.PACKAGE_NAME,
- VisibilityStore.DATABASE_NAME) + VisibilityStore.SCHEMA_TYPE);
- List<AppSearchSchema.PropertyConfig> visibilityProperties =
- visibilitySchema.getProperties();
- for (AppSearchSchema.PropertyConfig property : visibilityProperties) {
- rewrittenVisibilitySchema.addProperty(property);
- }
- mVisibilitySchemaProto =
- SchemaToProtoConverter.toSchemaTypeConfigProto(rewrittenVisibilitySchema.build());
+ mAppSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
}
- //TODO(b/175430168) add test to verify reset is working properly.
-
/**
* Ensure that we can rewrite an incoming schema type by adding the database as a prefix. While
* also keeping any other existing schema types that may already be part of Icing's persisted
@@ -92,38 +105,52 @@
// Create a copy so we can modify it.
List<SchemaTypeConfigProto> existingTypes =
new ArrayList<>(existingSchemaBuilder.getTypesList());
-
- SchemaProto newSchema = SchemaProto.newBuilder()
- .addTypes(SchemaTypeConfigProto.newBuilder()
- .setSchemaType("Foo").build())
- .addTypes(SchemaTypeConfigProto.newBuilder()
- .setSchemaType("TestType")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setStringIndexingConfig(StringIndexingConfig.newBuilder()
- .setTokenizerType(
- StringIndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- .build()
- ).build()
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("link")
- .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setSchemaType("RefType")
+ SchemaTypeConfigProto schemaTypeConfigProto1 = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("Foo").build();
+ SchemaTypeConfigProto schemaTypeConfigProto2 = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("TestType")
+ .addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setStringIndexingConfig(StringIndexingConfig.newBuilder()
+ .setTokenizerType(
+ StringIndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
.build()
).build()
+ ).addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("link")
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setSchemaType("RefType")
+ .build()
).build();
+ SchemaTypeConfigProto schemaTypeConfigProto3 = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("RefType").build();
+ SchemaProto newSchema = SchemaProto.newBuilder()
+ .addTypes(schemaTypeConfigProto1)
+ .addTypes(schemaTypeConfigProto2)
+ .addTypes(schemaTypeConfigProto3)
+ .build();
- AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults = mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "newDatabase"), existingSchemaBuilder,
+ AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults = AppSearchImpl.rewriteSchema(
+ createPrefix("package", "newDatabase"), existingSchemaBuilder,
newSchema);
// We rewrote all the new types that were added. And nothing was removed.
- assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
- .containsExactly("package$newDatabase/Foo", "package$newDatabase/TestType");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet()).containsExactly(
+ "package$newDatabase/Foo", "package$newDatabase/TestType",
+ "package$newDatabase/RefType");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.get(
+ "package$newDatabase/Foo").getSchemaType()).isEqualTo(
+ "package$newDatabase/Foo");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.get(
+ "package$newDatabase/TestType").getSchemaType()).isEqualTo(
+ "package$newDatabase/TestType");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.get(
+ "package$newDatabase/RefType").getSchemaType()).isEqualTo(
+ "package$newDatabase/RefType");
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
SchemaProto expectedSchema = SchemaProto.newBuilder()
@@ -148,6 +175,8 @@
.setSchemaType("package$newDatabase/RefType")
.build()
).build())
+ .addTypes(SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$newDatabase/RefType").build())
.build();
existingTypes.addAll(expectedSchema.getTypesList());
@@ -169,13 +198,13 @@
.setSchemaType("Foo").build())
.build();
- AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults = mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "existingDatabase"), existingSchemaBuilder,
+ AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults = AppSearchImpl.rewriteSchema(
+ createPrefix("package", "existingDatabase"), existingSchemaBuilder,
newSchema);
// Nothing was removed, but the method did rewrite the type name.
- assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
- .containsExactly("package$existingDatabase/Foo");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet()).containsExactly(
+ "package$existingDatabase/Foo");
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
// Same schema since nothing was added.
@@ -199,14 +228,15 @@
.setSchemaType("Bar").build())
.build();
- AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults = mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "existingDatabase"), existingSchemaBuilder,
+ AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults = AppSearchImpl.rewriteSchema(
+ createPrefix("package", "existingDatabase"), existingSchemaBuilder,
newSchema);
// Bar type was rewritten, but Foo ended up being deleted since it wasn't included in the
// new schema.
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
- .containsExactly("package$existingDatabase/Bar");
+ .containsKey("package$existingDatabase/Bar");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet().size()).isEqualTo(1);
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes)
.containsExactly("package$existingDatabase/Foo");
@@ -223,31 +253,31 @@
@Test
public void testAddDocumentTypePrefix() {
DocumentProto insideDocument = DocumentProto.newBuilder()
- .setUri("inside-uri")
+ .setUri("inside-id")
.setSchema("type")
.setNamespace("namespace")
.build();
DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri("uri")
+ .setUri("id")
.setSchema("type")
.setNamespace("namespace")
.addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
.build();
DocumentProto expectedInsideDocument = DocumentProto.newBuilder()
- .setUri("inside-uri")
+ .setUri("inside-id")
.setSchema("package$databaseName/type")
.setNamespace("package$databaseName/namespace")
.build();
DocumentProto expectedDocumentProto = DocumentProto.newBuilder()
- .setUri("uri")
+ .setUri("id")
.setSchema("package$databaseName/type")
.setNamespace("package$databaseName/namespace")
.addProperties(PropertyProto.newBuilder().addDocumentValues(expectedInsideDocument))
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
- mAppSearchImpl.addPrefixToDocument(actualDocument, AppSearchImpl.createPrefix("package",
+ addPrefixToDocument(actualDocument, createPrefix("package",
"databaseName"));
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
}
@@ -255,62 +285,62 @@
@Test
public void testRemoveDocumentTypePrefixes() throws Exception {
DocumentProto insideDocument = DocumentProto.newBuilder()
- .setUri("inside-uri")
+ .setUri("inside-id")
.setSchema("package$databaseName/type")
.setNamespace("package$databaseName/namespace")
.build();
DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri("uri")
+ .setUri("id")
.setSchema("package$databaseName/type")
.setNamespace("package$databaseName/namespace")
.addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
.build();
DocumentProto expectedInsideDocument = DocumentProto.newBuilder()
- .setUri("inside-uri")
+ .setUri("inside-id")
.setSchema("type")
.setNamespace("namespace")
.build();
DocumentProto expectedDocumentProto = DocumentProto.newBuilder()
- .setUri("uri")
+ .setUri("id")
.setSchema("type")
.setNamespace("namespace")
.addProperties(PropertyProto.newBuilder().addDocumentValues(expectedInsideDocument))
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
- assertThat(mAppSearchImpl.removePrefixesFromDocument(actualDocument)).isEqualTo(
+ assertThat(removePrefixesFromDocument(actualDocument)).isEqualTo(
"package$databaseName/");
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
}
@Test
- public void testRemoveDatabasesFromDocumentThrowsException() throws Exception {
+ public void testRemoveDatabasesFromDocumentThrowsException() {
// Set two different database names in the document, which should never happen
DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri("uri")
+ .setUri("id")
.setSchema("prefix1/type")
.setNamespace("prefix2/namespace")
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e = assertThrows(AppSearchException.class, () ->
- mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@Test
- public void testNestedRemoveDatabasesFromDocumentThrowsException() throws Exception {
+ public void testNestedRemoveDatabasesFromDocumentThrowsException() {
// Set two different database names in the outer and inner document, which should never
// happen.
DocumentProto insideDocument = DocumentProto.newBuilder()
- .setUri("inside-uri")
+ .setUri("inside-id")
.setSchema("prefix1/type")
.setNamespace("prefix1/namespace")
.build();
DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri("uri")
+ .setUri("id")
.setSchema("prefix2/type")
.setNamespace("prefix2/namespace")
.addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
@@ -318,53 +348,188 @@
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e = assertThrows(AppSearchException.class, () ->
- mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@Test
- public void testOptimize() throws Exception {
+ public void testTriggerCheckOptimizeByMutationSize() throws Exception {
// Insert schema
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
- mAppSearchImpl.setSchema("package", "database", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
- // Insert enough documents.
- for (int i = 0; i < AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT
- + AppSearchImpl.CHECK_OPTIMIZE_INTERVAL; i++) {
- GenericDocument document =
- new GenericDocument.Builder<>("uri" + i, "type").setNamespace(
- "namespace").build();
- mAppSearchImpl.putDocument("package", "database", document);
- }
+ // Insert a document and then remove it to generate garbage.
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
+ mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
+ mAppSearchImpl.remove("package", "database", "namespace", "id",
+ /*removeStatsBuilder=*/ null);
- // Check optimize() will release 0 docs since there is no deletion.
+ // Verify there is garbage documents.
GetOptimizeInfoResultProto optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
+ assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1);
+
+ // Increase mutation counter and stop before reach the threshold
+ mAppSearchImpl.checkForOptimize(AppSearchImpl.CHECK_OPTIMIZE_INTERVAL - 1,
+ /*builder=*/null);
+
+ // Verify the optimize() isn't triggered.
+ optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
+ assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1);
+
+ // Increase the counter and reach the threshold, optimize() should be triggered.
+ OptimizeStats.Builder builder = new OptimizeStats.Builder();
+ mAppSearchImpl.checkForOptimize(/*mutateBatchSize=*/ 1, builder);
+
+ // Verify optimize() is triggered.
+ optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(0);
+ assertThat(optimizeInfo.getEstimatedOptimizableBytes()).isEqualTo(0);
- // delete 999 documents , we will reach the threshold to trigger optimize() in next
- // deletion.
- for (int i = 0; i < AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT - 1; i++) {
- mAppSearchImpl.remove("package", "database", "namespace", "uri" + i);
- }
+ // Verify the stats have been set.
+ OptimizeStats oStats = builder.build();
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(1);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(1);
+ }
- // optimize() still not be triggered since we are in the interval to call getOptimizeInfo()
- optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
- assertThat(optimizeInfo.getOptimizableDocs())
- .isEqualTo(AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT - 1);
+ @Test
+ public void testReset() throws Exception {
+ // Setup the index
+ Context context = ApplicationProvider.getApplicationContext();
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
- // Keep delete docs, will reach the interval this time and trigger optimize().
- for (int i = AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT;
- i < AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT
- + AppSearchImpl.CHECK_OPTIMIZE_INTERVAL; i++) {
- mAppSearchImpl.remove("package", "database", "namespace", "uri" + i);
- }
+ // Insert schema
+ List<AppSearchSchema> schemas = ImmutableList.of(
+ new AppSearchSchema.Builder("Type1").build(),
+ new AppSearchSchema.Builder("Type2").build());
+ appSearchImpl.setSchema(
+ context.getPackageName(),
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
- // Verify optimize() is triggered
- optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
- assertThat(optimizeInfo.getOptimizableDocs())
- .isLessThan(AppSearchImpl.CHECK_OPTIMIZE_INTERVAL);
+ // Insert a valid doc
+ GenericDocument validDoc =
+ new GenericDocument.Builder<>("namespace1", "id1", "Type1").build();
+ appSearchImpl.putDocument(
+ context.getPackageName(),
+ "database1",
+ validDoc,
+ /*logger=*/null);
+
+ // Query it via global query. We use the same code again later so this is to make sure we
+ // have our global query configured right.
+ SearchResultPage results = appSearchImpl.globalQuery(
+ /*queryExpression=*/ "",
+ new SearchSpec.Builder().addFilterSchemas("Type1").build(),
+ context.getPackageName(),
+ /*visibilityStore=*/ null,
+ Process.INVALID_UID,
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
+ assertThat(results.getResults()).hasSize(1);
+ assertThat(results.getResults().get(0).getGenericDocument()).isEqualTo(validDoc);
+
+ // Create a doc with a malformed namespace
+ DocumentProto invalidDoc = DocumentProto.newBuilder()
+ .setNamespace("invalidNamespace")
+ .setUri("id2")
+ .setSchema(context.getPackageName() + "$database1/Type1")
+ .build();
+ AppSearchException e = assertThrows(
+ AppSearchException.class,
+ () -> PrefixUtil.getPrefix(invalidDoc.getNamespace()));
+ assertThat(e).hasMessageThat().isEqualTo(
+ "The prefixed value \"invalidNamespace\" doesn't contain a valid database name");
+
+ // Insert the invalid doc with an invalid namespace right into icing
+ PutResultProto putResultProto = appSearchImpl.mIcingSearchEngineLocked.put(invalidDoc);
+ assertThat(putResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+
+ // Initialize AppSearchImpl. This should cause a reset.
+ InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
+ appSearchImpl.close();
+ appSearchImpl = AppSearchImpl.create(
+ appsearchDir, new UnlimitedLimitConfig(), initStatsBuilder, ALWAYS_OPTIMIZE);
+
+ // Check recovery state
+ InitializeStats initStats = initStatsBuilder.build();
+ assertThat(initStats).isNotNull();
+ assertThat(initStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
+ assertThat(initStats.hasDeSync()).isFalse();
+ assertThat(initStats.getDocumentStoreRecoveryCause())
+ .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE);
+ assertThat(initStats.getIndexRestorationCause())
+ .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE);
+ assertThat(initStats.getSchemaStoreRecoveryCause())
+ .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE);
+ assertThat(initStats.getDocumentStoreDataStatus())
+ .isEqualTo(InitializeStats.DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS);
+ assertThat(initStats.hasReset()).isTrue();
+ assertThat(initStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+
+ // Make sure all our data is gone
+ assertThat(appSearchImpl.getSchema(context.getPackageName(), "database1").getSchemas())
+ .isEmpty();
+ results = appSearchImpl.globalQuery(
+ /*queryExpression=*/ "",
+ new SearchSpec.Builder().addFilterSchemas("Type1").build(),
+ context.getPackageName(),
+ /*visibilityStore=*/ null,
+ Process.INVALID_UID,
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
+ assertThat(results.getResults()).isEmpty();
+
+ // Make sure the index can now be used successfully
+ appSearchImpl.setSchema(
+ context.getPackageName(),
+ "database1",
+ Collections.singletonList(new AppSearchSchema.Builder("Type1").build()),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert a valid doc
+ appSearchImpl.putDocument(
+ context.getPackageName(),
+ "database1",
+ validDoc,
+ /*logger=*/null);
+
+ // Query it via global query.
+ results = appSearchImpl.globalQuery(
+ /*queryExpression=*/ "",
+ new SearchSpec.Builder().addFilterSchemas("Type1").build(),
+ context.getPackageName(),
+ /*visibilityStore=*/ null,
+ Process.INVALID_UID,
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
+ assertThat(results.getResults()).hasSize(1);
+ assertThat(results.getResults().get(0).getGenericDocument()).isEqualTo(validDoc);
}
@Test
@@ -375,17 +540,26 @@
// Insert schema
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
- mAppSearchImpl.setSchema("package", "database", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert document
- GenericDocument document = new GenericDocument.Builder<>("uri", "type").setNamespace(
- "namespace").build();
- mAppSearchImpl.putDocument("package", "database", document);
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id",
+ "type").build();
+ mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
// Rewrite SearchSpec
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(searchSpecProto,
- Collections.singleton(AppSearchImpl.createPrefix("package", "database")));
+ Collections.singleton(createPrefix("package", "database")),
+ ImmutableSet.of("package$database/type"));
assertThat(searchSpecProto.getSchemaTypeFiltersList()).containsExactly(
"package$database/type");
assertThat(searchSpecProto.getNamespaceFiltersList()).containsExactly(
@@ -401,24 +575,42 @@
List<AppSearchSchema> schemas = ImmutableList.of(
new AppSearchSchema.Builder("typeA").build(),
new AppSearchSchema.Builder("typeB").build());
- mAppSearchImpl.setSchema("package", "database1", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
- mAppSearchImpl.setSchema("package", "database2", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database2",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert documents
- GenericDocument document1 = new GenericDocument.Builder<>("uri", "typeA").setNamespace(
- "namespace").build();
- mAppSearchImpl.putDocument("package", "database1", document1);
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id",
+ "typeA").build();
+ mAppSearchImpl.putDocument("package", "database1", document1, /*logger=*/ null);
- GenericDocument document2 = new GenericDocument.Builder<>("uri", "typeB").setNamespace(
- "namespace").build();
- mAppSearchImpl.putDocument("package", "database2", document2);
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id",
+ "typeB").build();
+ mAppSearchImpl.putDocument("package", "database2", document2, /*logger=*/ null);
// Rewrite SearchSpec
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(searchSpecProto,
- ImmutableSet.of(AppSearchImpl.createPrefix("package", "database1"),
- AppSearchImpl.createPrefix("package", "database2")));
+ ImmutableSet.of(createPrefix("package", "database1"),
+ createPrefix("package", "database2")), ImmutableSet.of(
+ "package$database1/typeA", "package$database1/typeB",
+ "package$database2/typeA", "package$database2/typeB"));
assertThat(searchSpecProto.getSchemaTypeFiltersList()).containsExactly(
"package$database1/typeA", "package$database1/typeB", "package$database2/typeA",
"package$database2/typeB");
@@ -427,138 +619,759 @@
}
@Test
+ public void testRewriteSearchSpec_ignoresSearchSpecSchemaFilters() throws Exception {
+ SearchSpecProto.Builder searchSpecProto =
+ SearchSpecProto.newBuilder().setQuery("").addSchemaTypeFilters("type");
+
+ // Insert schema
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert document
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id",
+ "type").build();
+ mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
+
+ // If 'allowedPrefixedSchemas' is empty, this returns false since there's nothing to
+ // search over. Despite the searchSpecProto having schema type filters.
+ assertThat(mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(searchSpecProto,
+ Collections.singleton(createPrefix("package", "database")),
+ /*allowedPrefixedSchemas=*/ Collections.emptySet())).isFalse();
+ }
+
+ @Test
public void testQueryEmptyDatabase() throws Exception {
SearchSpec searchSpec =
new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
SearchResultPage searchResultPage = mAppSearchImpl.query("package", "EmptyDatabase", "",
- searchSpec);
+ searchSpec, /*logger=*/ null);
assertThat(searchResultPage.getResults()).isEmpty();
}
+ /**
+ * TODO(b/169883602): This should be an integration test at the cts-level. This is a
+ * short-term test until we have official support for multiple-apps indexing at once.
+ */
+ @Test
+ public void testQueryWithMultiplePackages_noPackageFilters() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert package2 schema
+ List<AppSearchSchema> schema2 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database2",
+ schema2,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert package1 document
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "schema1")
+ .build();
+ mAppSearchImpl.putDocument("package1", "database1", document, /*logger=*/ null);
+
+ // No query filters specified, package2 shouldn't be able to query for package1's documents.
+ SearchSpec searchSpec =
+ new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
+ SearchResultPage searchResultPage = mAppSearchImpl.query("package2", "database2", "",
+ searchSpec, /*logger=*/ null);
+ assertThat(searchResultPage.getResults()).isEmpty();
+
+ // Insert package2 document
+ document = new GenericDocument.Builder<>("namespace", "id", "schema2").build();
+ mAppSearchImpl.putDocument("package2", "database2", document, /*logger=*/ null);
+
+ // No query filters specified. package2 should only get its own documents back.
+ searchResultPage = mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger=
+ */ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document);
+ }
+
+ /**
+ * TODO(b/169883602): This should be an integration test at the cts-level. This is a
+ * short-term test until we have official support for multiple-apps indexing at once.
+ */
+ @Test
+ public void testQueryWithMultiplePackages_withPackageFilters() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert package2 schema
+ List<AppSearchSchema> schema2 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database2",
+ schema2,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert package1 document
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document, /*logger=*/ null);
+
+ // "package1" filter specified, but package2 shouldn't be able to query for package1's
+ // documents.
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .addFilterPackageNames("package1")
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.query("package2", "database2", "",
+ searchSpec, /*logger=*/ null);
+ assertThat(searchResultPage.getResults()).isEmpty();
+
+ // Insert package2 document
+ document = new GenericDocument.Builder<>("namespace", "id", "schema2").build();
+ mAppSearchImpl.putDocument("package2", "database2", document, /*logger=*/ null);
+
+ // "package2" filter specified, package2 should only get its own documents back.
+ searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .addFilterPackageNames("package2")
+ .build();
+ searchResultPage = mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger=
+ */ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document);
+ }
+
@Test
public void testGlobalQueryEmptyDatabase() throws Exception {
SearchSpec searchSpec =
new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
- SearchResultPage searchResultPage = mAppSearchImpl.globalQuery("", searchSpec);
+ SearchResultPage searchResultPage = mAppSearchImpl.globalQuery(
+ "",
+ searchSpec,
+ /*callerPackageName=*/ "",
+ /*visibilityStore=*/ null,
+ Process.INVALID_UID,
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
assertThat(searchResultPage.getResults()).isEmpty();
}
@Test
+ public void testGetNextPageToken_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.query("package1", "database1", "",
+ searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testGetNextPageWithDifferentPackage_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.query("package1", "database1", "",
+ searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e = assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package2",
+ nextPageToken, /*statsBuilder=*/ null));
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testGetNextPageToken_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.globalQuery(/*queryExpression=*/ "",
+ searchSpec, "package1", /*visibilityStore=*/ null, Process.myUid(),
+ /*callerHasSystemAccess=*/ false, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testGetNextPageWithDifferentPackage_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.globalQuery(/*queryExpression=*/ "",
+ searchSpec, "package1", /*visibilityStore=*/ null, Process.myUid(),
+ /*callerHasSystemAccess=*/ false, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e = assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package2", nextPageToken,
+ /*statsBuilder=*/ null));
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testInvalidateNextPageToken_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.query("package1", "database1", "",
+ searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Invalidate the token
+ mAppSearchImpl.invalidateNextPageToken("package1", nextPageToken);
+
+ // Can't get next page because we invalidated the token.
+ AppSearchException e = assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null));
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package1\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+ }
+
+ @Test
+ public void testInvalidateNextPageTokenWithDifferentPackage_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.query("package1", "database1", "",
+ searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e = assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.invalidateNextPageToken("package2",
+ nextPageToken));
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testInvalidateNextPageToken_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.globalQuery(/*queryExpression=*/ "",
+ searchSpec, "package1", /*visibilityStore=*/ null, Process.myUid(),
+ /*callerHasSystemAccess=*/ false, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Invalidate the token
+ mAppSearchImpl.invalidateNextPageToken("package1", nextPageToken);
+
+ // Can't get next page because we invalidated the token.
+ AppSearchException e = assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null));
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package1\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+ }
+
+ @Test
+ public void testInvalidateNextPageTokenWithDifferentPackage_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage = mAppSearchImpl.globalQuery(/*queryExpression=*/ "",
+ searchSpec, "package1", /*visibilityStore=*/ null, Process.myUid(),
+ /*callerHasSystemAccess=*/ false, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e = assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.invalidateNextPageToken("package2",
+ nextPageToken));
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken,
+ /*statsBuilder=*/ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
public void testRemoveEmptyDatabase_noExceptionThrown() throws Exception {
SearchSpec searchSpec =
- new SearchSpec.Builder().addSchemaType("FakeType").setTermMatch(
+ new SearchSpec.Builder().addFilterSchemas("FakeType").setTermMatch(
TermMatchType.Code.PREFIX_VALUE).build();
mAppSearchImpl.removeByQuery("package", "EmptyDatabase",
- "", searchSpec);
+ "", searchSpec, /*statsBuilder=*/ null);
searchSpec =
- new SearchSpec.Builder().addNamespace("FakeNamespace").setTermMatch(
+ new SearchSpec.Builder().addFilterNamespaces("FakeNamespace").setTermMatch(
TermMatchType.Code.PREFIX_VALUE).build();
mAppSearchImpl.removeByQuery("package", "EmptyDatabase",
- "", searchSpec);
+ "", searchSpec, /*statsBuilder=*/ null);
searchSpec = new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
- mAppSearchImpl.removeByQuery("package", "EmptyDatabase", "", searchSpec);
+ mAppSearchImpl.removeByQuery("package", "EmptyDatabase", "", searchSpec,
+ /*statsBuilder=*/ null);
}
@Test
public void testSetSchema() throws Exception {
+ List<SchemaTypeConfigProto> existingSchemas =
+ mAppSearchImpl.getSchemaProtoLocked().getTypesList();
+
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("Email").build());
// Set schema Email to AppSearch database1
- mAppSearchImpl.setSchema("package", "database1", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType proto.
SchemaProto expectedProto = SchemaProto.newBuilder()
.addTypes(
- SchemaTypeConfigProto.newBuilder().setSchemaType("package$database1/Email"))
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$database1/Email").setVersion(0))
.build();
List<SchemaTypeConfigProto> expectedTypes = new ArrayList<>();
- expectedTypes.add(mVisibilitySchemaProto);
+ expectedTypes.addAll(existingSchemas);
expectedTypes.addAll(expectedProto.getTypesList());
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(expectedTypes);
}
@Test
- public void testSetSchema_existingSchemaRetainsVisibilitySetting() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema("package", "database",
- Collections.singletonList(new AppSearchSchema.Builder(
- "schema1").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.singletonList("schema1"), /*forceOverride=*/ false);
-
- // "schema1" is platform hidden now
- assertThat(mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "schema1")).isFalse();
-
- // Add a new schema, and include the already-existing "schema1"
+ public void testSetSchema_incompatible() throws Exception {
+ List<AppSearchSchema> oldSchemas = new ArrayList<>();
+ oldSchemas.add(new AppSearchSchema.Builder("Email")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("foo")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build())
+ .build());
+ oldSchemas.add(new AppSearchSchema.Builder("Text").build());
+ // Set schema Email to AppSearch database1
mAppSearchImpl.setSchema(
- "package", "database",
- ImmutableList.of(
- new AppSearchSchema.Builder("schema1").build(),
- new AppSearchSchema.Builder("schema2").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
- /*forceOverride=*/ false);
+ "package",
+ "database1",
+ oldSchemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
- // Check that "schema1" is still platform hidden, but "schema2" is the default platform
- // visible.
- assertThat(mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "schema1")).isFalse();
- assertThat(mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "schema2")).isTrue();
+ // Create incompatible schema
+ List<AppSearchSchema> newSchemas =
+ Collections.singletonList(new AppSearchSchema.Builder("Email").build());
+
+ // set email incompatible and delete text
+ SetSchemaResponse setSchemaResponse = mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ newSchemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ true,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Text");
+ assertThat(setSchemaResponse.getIncompatibleTypes()).containsExactly("Email");
}
@Test
public void testRemoveSchema() throws Exception {
+ List<SchemaTypeConfigProto> existingSchemas =
+ mAppSearchImpl.getSchemaProtoLocked().getTypesList();
+
List<AppSearchSchema> schemas = ImmutableList.of(
new AppSearchSchema.Builder("Email").build(),
new AppSearchSchema.Builder("Document").build());
// Set schema Email and Document to AppSearch database1
- mAppSearchImpl.setSchema("package", "database1", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType proto.
SchemaProto expectedProto = SchemaProto.newBuilder()
.addTypes(
- SchemaTypeConfigProto.newBuilder().setSchemaType("package$database1/Email"))
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$database1/Email").setVersion(0))
.addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType(
- "package$database1/Document"))
+ "package$database1/Document").setVersion(0))
.build();
// Check both schema Email and Document saved correctly.
List<SchemaTypeConfigProto> expectedTypes = new ArrayList<>();
- expectedTypes.add(mVisibilitySchemaProto);
+ expectedTypes.addAll(existingSchemas);
expectedTypes.addAll(expectedProto.getTypesList());
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(expectedTypes);
final List<AppSearchSchema> finalSchemas = Collections.singletonList(
- new AppSearchSchema.Builder(
- "Email").build());
- // Check the incompatible error has been thrown.
- AppSearchException e = assertThrows(AppSearchException.class, () ->
- mAppSearchImpl.setSchema("package", "database1",
- finalSchemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false));
- assertThat(e).hasMessageThat().contains("Schema is incompatible");
- assertThat(e).hasMessageThat().contains("Deleted types: [package$database1/Document]");
+ new AppSearchSchema.Builder("Email").build());
+ SetSchemaResponse setSchemaResponse =
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ finalSchemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ // Check the Document type has been deleted.
+ assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Document");
// ForceOverride to delete.
- mAppSearchImpl.setSchema("package", "database1",
- finalSchemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ true);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ finalSchemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ true,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Check Document schema is removed.
expectedProto = SchemaProto.newBuilder()
.addTypes(
- SchemaTypeConfigProto.newBuilder().setSchemaType("package$database1/Email"))
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$database1/Email").setVersion(0))
.build();
expectedTypes = new ArrayList<>();
- expectedTypes.add(mVisibilitySchemaProto);
+ expectedTypes.addAll(existingSchemas);
expectedTypes.addAll(expectedProto.getTypesList());
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(expectedTypes);
@@ -566,173 +1379,261 @@
@Test
public void testRemoveSchema_differentDataBase() throws Exception {
+ List<SchemaTypeConfigProto> existingSchemas =
+ mAppSearchImpl.getSchemaProtoLocked().getTypesList();
+
// Create schemas
List<AppSearchSchema> schemas = ImmutableList.of(
new AppSearchSchema.Builder("Email").build(),
new AppSearchSchema.Builder("Document").build());
// Set schema Email and Document to AppSearch database1 and 2
- mAppSearchImpl.setSchema("package", "database1", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
- mAppSearchImpl.setSchema("package", "database2", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database2",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType proto.
SchemaProto expectedProto = SchemaProto.newBuilder()
.addTypes(
- SchemaTypeConfigProto.newBuilder().setSchemaType("package$database1/Email"))
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$database1/Email").setVersion(0))
.addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType(
- "package$database1/Document"))
+ "package$database1/Document").setVersion(0))
.addTypes(
- SchemaTypeConfigProto.newBuilder().setSchemaType("package$database2/Email"))
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$database2/Email").setVersion(0))
.addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType(
- "package$database2/Document"))
+ "package$database2/Document").setVersion(0))
.build();
// Check Email and Document is saved in database 1 and 2 correctly.
List<SchemaTypeConfigProto> expectedTypes = new ArrayList<>();
- expectedTypes.add(mVisibilitySchemaProto);
+ expectedTypes.addAll(existingSchemas);
expectedTypes.addAll(expectedProto.getTypesList());
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(expectedTypes);
// Save only Email to database1 this time.
schemas = Collections.singletonList(new AppSearchSchema.Builder("Email").build());
- mAppSearchImpl.setSchema("package", "database1", schemas, /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ true);
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ true,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType list, database 1 should only contain Email but database 2
// remains in same.
expectedProto = SchemaProto.newBuilder()
.addTypes(
- SchemaTypeConfigProto.newBuilder().setSchemaType("package$database1/Email"))
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$database1/Email").setVersion(0))
.addTypes(
- SchemaTypeConfigProto.newBuilder().setSchemaType("package$database2/Email"))
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$database2/Email").setVersion(0))
.addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType(
- "package$database2/Document"))
+ "package$database2/Document").setVersion(0))
.build();
// Check nothing changed in database2.
expectedTypes = new ArrayList<>();
- expectedTypes.add(mVisibilitySchemaProto);
+ expectedTypes.addAll(existingSchemas);
expectedTypes.addAll(expectedProto.getTypesList());
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(expectedTypes);
}
-
@Test
- public void testRemoveSchema_removedFromVisibilityStore() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema("package", "database",
- Collections.singletonList(new AppSearchSchema.Builder(
- "schema1").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.singletonList("schema1"), /*forceOverride=*/ false);
+ public void testClearPackageData() throws AppSearchException {
+ List<SchemaTypeConfigProto> existingSchemas =
+ mAppSearchImpl.getSchemaProtoLocked().getTypesList();
+ Map<String, Set<String>> existingDatabases = mAppSearchImpl.getPackageToDatabases();
- // "schema1" is platform hidden now
- assertThat(mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "schema1")).isFalse();
+ // Insert package schema
+ List<AppSearchSchema> schema =
+ ImmutableList.of(new AppSearchSchema.Builder("schema").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schema,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
- // Remove "schema1" by force overriding
- mAppSearchImpl.setSchema("package", "database",
- Collections.emptyList(), /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ true);
+ // Insert package document
+ GenericDocument document = new GenericDocument.Builder<>("namespace", "id",
+ "schema").build();
+ mAppSearchImpl.putDocument("package", "database", document,
+ /*logger=*/ null);
- // Check that "schema1" is no longer considered platform hidden
- assertThat(
- mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "schema1")).isTrue();
+ // Verify the document is indexed.
+ SearchSpec searchSpec =
+ new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
+ SearchResultPage searchResultPage = mAppSearchImpl.query("package",
+ "database", /*queryExpression=*/ "", searchSpec, /*logger=*/ null);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document);
- // Add "schema1" back, it gets default visibility settings which means it's not platform
- // hidden.
- mAppSearchImpl.setSchema("package", "database",
- Collections.singletonList(new AppSearchSchema.Builder(
- "schema1").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
- assertThat(
- mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "schema1")).isTrue();
+ // Remove the package
+ mAppSearchImpl.clearPackageData("package");
+
+ // Verify the document is cleared.
+ searchResultPage = mAppSearchImpl.query("package2", "database2",
+ /*queryExpression=*/ "", searchSpec, /*logger=*/ null);
+ assertThat(searchResultPage.getResults()).isEmpty();
+
+ // Verify the schema is cleared.
+ assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
+ .containsExactlyElementsIn(existingSchemas);
+ assertThat(mAppSearchImpl.getPackageToDatabases())
+ .containsExactlyEntriesIn(existingDatabases);
}
@Test
- public void testSetSchema_defaultPlatformVisible() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema("package", "database",
- Collections.singletonList(new AppSearchSchema.Builder(
- "Schema").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
- assertThat(
- mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "Schema")).isTrue();
+ public void testPrunePackageData() throws AppSearchException {
+ List<SchemaTypeConfigProto> existingSchemas =
+ mAppSearchImpl.getSchemaProtoLocked().getTypesList();
+ Map<String, Set<String>> existingDatabases = mAppSearchImpl.getPackageToDatabases();
+
+ Set<String> existingPackages = new ArraySet<>(existingSchemas.size());
+ for (int i = 0; i < existingSchemas.size(); i++) {
+ existingPackages.add(PrefixUtil.getPackageName(existingSchemas.get(i).getSchemaType()));
+ }
+
+ // Insert schema for package A and B.
+ List<AppSearchSchema> schema =
+ ImmutableList.of(new AppSearchSchema.Builder("schema").build());
+ mAppSearchImpl.setSchema(
+ "packageA",
+ "database",
+ schema,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ mAppSearchImpl.setSchema(
+ "packageB",
+ "database",
+ schema,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Verify these two packages is stored in AppSearch
+ SchemaProto expectedProto = SchemaProto.newBuilder()
+ .addTypes(
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("packageA$database/schema").setVersion(0))
+ .addTypes(
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("packageB$database/schema").setVersion(0))
+ .build();
+ List<SchemaTypeConfigProto> expectedTypes = new ArrayList<>();
+ expectedTypes.addAll(existingSchemas);
+ expectedTypes.addAll(expectedProto.getTypesList());
+ assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
+ .containsExactlyElementsIn(expectedTypes);
+
+ // Prune packages
+ mAppSearchImpl.prunePackageData(existingPackages);
+
+ // Verify the schema is same as beginning.
+ assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
+ .containsExactlyElementsIn(existingSchemas);
+ assertThat(mAppSearchImpl.getPackageToDatabases())
+ .containsExactlyEntriesIn(existingDatabases);
}
@Test
- public void testSetSchema_platformHidden() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema("package", "database",
- Collections.singletonList(new AppSearchSchema.Builder(
- "Schema").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.singletonList("Schema"), /*forceOverride=*/ false);
- assertThat(mAppSearchImpl.getVisibilityStoreLocked().isSchemaPlatformSurfaceable(
- prefix, prefix + "Schema")).isFalse();
- }
-
- @Test
- public void testHasSchemaType() throws Exception {
- // Nothing exists yet
- assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "Schema")).isFalse();
-
- mAppSearchImpl.setSchema("package", "database",
- Collections.singletonList(new AppSearchSchema.Builder(
- "Schema").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
- assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "Schema")).isTrue();
-
- assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database",
- "UnknownSchema")).isFalse();
- }
-
- @Test
- public void testGetDatabases() throws Exception {
- // No client databases exist yet, but the VisibilityStore's does
- assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactly(
- AppSearchImpl.createPrefix(VisibilityStore.PACKAGE_NAME,
- VisibilityStore.DATABASE_NAME));
+ public void testGetPackageToDatabases() throws Exception {
+ Map<String, Set<String>> existingMapping = mAppSearchImpl.getPackageToDatabases();
+ Map<String, Set<String>> expectedMapping = new ArrayMap<>();
+ expectedMapping.putAll(existingMapping);
// Has database1
- mAppSearchImpl.setSchema("package", "database1",
- Collections.singletonList(new AppSearchSchema.Builder(
- "schema").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
- assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactly(
- AppSearchImpl.createPrefix(VisibilityStore.PACKAGE_NAME,
- VisibilityStore.DATABASE_NAME),
- AppSearchImpl.createPrefix("package", "database1"));
+ expectedMapping.put("package1", ImmutableSet.of("database1"));
+ mAppSearchImpl.setSchema(
+ "package1", "database1",
+ Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ assertThat(mAppSearchImpl.getPackageToDatabases()).containsExactlyEntriesIn(
+ expectedMapping);
// Has both databases
- mAppSearchImpl.setSchema("package", "database2",
- Collections.singletonList(new AppSearchSchema.Builder(
- "schema").build()), /*schemasNotPlatformSurfaceable=*/
- Collections.emptyList(), /*forceOverride=*/ false);
- assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactly(
- AppSearchImpl.createPrefix(VisibilityStore.PACKAGE_NAME,
- VisibilityStore.DATABASE_NAME),
- AppSearchImpl.createPrefix("package", "database1"), AppSearchImpl.createPrefix(
- "package", "database2"));
+ expectedMapping.put("package1", ImmutableSet.of("database1", "database2"));
+ mAppSearchImpl.setSchema(
+ "package1", "database2",
+ Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ assertThat(mAppSearchImpl.getPackageToDatabases()).containsExactlyEntriesIn(
+ expectedMapping);
+
+ // Has both packages
+ expectedMapping.put("package2", ImmutableSet.of("database1"));
+ mAppSearchImpl.setSchema(
+ "package2", "database1",
+ Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ assertThat(mAppSearchImpl.getPackageToDatabases()).containsExactlyEntriesIn(
+ expectedMapping);
}
@Test
public void testRewriteSearchResultProto() throws Exception {
- final String database =
- "com.package.foo" + AppSearchImpl.PACKAGE_DELIMITER + "databaseName"
- + AppSearchImpl.DATABASE_DELIMITER;
- final String uri = "uri";
- final String namespace = database + "namespace";
- final String schemaType = database + "schema";
+ final String prefix =
+ "com.package.foo" + PrefixUtil.PACKAGE_DELIMITER + "databaseName"
+ + PrefixUtil.DATABASE_DELIMITER;
+ final String id = "id";
+ final String namespace = prefix + "namespace";
+ final String schemaType = prefix + "schema";
// Building the SearchResult received from query.
DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri(uri)
+ .setUri(id)
.setNamespace(namespace)
.setSchema(schemaType)
.build();
@@ -742,16 +1643,1270 @@
SearchResultProto searchResultProto = SearchResultProto.newBuilder()
.addResults(resultProto)
.build();
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(schemaType)
+ .build();
+ Map<String, Map<String, SchemaTypeConfigProto>> schemaMap = ImmutableMap.of(prefix,
+ ImmutableMap.of(schemaType, schemaTypeConfigProto));
DocumentProto.Builder strippedDocumentProto = documentProto.toBuilder();
- AppSearchImpl.removePrefixesFromDocument(strippedDocumentProto);
+ removePrefixesFromDocument(strippedDocumentProto);
SearchResultPage searchResultPage =
- AppSearchImpl.rewriteSearchResultProto(searchResultProto);
+ AppSearchImpl.rewriteSearchResultProto(searchResultProto, schemaMap);
for (SearchResult result : searchResultPage.getResults()) {
assertThat(result.getPackageName()).isEqualTo("com.package.foo");
- assertThat(result.getDocument()).isEqualTo(
+ assertThat(result.getDatabaseName()).isEqualTo("databaseName");
+ assertThat(result.getGenericDocument()).isEqualTo(
GenericDocumentToProtoConverter.toGenericDocument(
- strippedDocumentProto.build()));
+ strippedDocumentProto.build(), prefix, schemaMap.get(prefix)));
}
}
+
+ @Test
+ public void testReportUsage() throws Exception {
+ // Insert schema
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two docs
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "type").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "type").build();
+ mAppSearchImpl.putDocument("package", "database", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
+
+ // Report some usages. id1 has 2 app and 1 system usage, id2 has 1 app and 2 system usage.
+ mAppSearchImpl.reportUsage("package", "database", "namespace",
+ "id1", /*usageTimestampMillis=*/ 10, /*systemUsage=*/ false);
+ mAppSearchImpl.reportUsage("package", "database", "namespace",
+ "id1", /*usageTimestampMillis=*/ 20, /*systemUsage=*/ false);
+ mAppSearchImpl.reportUsage("package", "database", "namespace",
+ "id1", /*usageTimestampMillis=*/ 1000, /*systemUsage=*/ true);
+
+ mAppSearchImpl.reportUsage("package", "database", "namespace",
+ "id2", /*usageTimestampMillis=*/ 100, /*systemUsage=*/ false);
+ mAppSearchImpl.reportUsage("package", "database", "namespace",
+ "id2", /*usageTimestampMillis=*/ 200, /*systemUsage=*/ true);
+ mAppSearchImpl.reportUsage("package", "database", "namespace",
+ "id2", /*usageTimestampMillis=*/ 150, /*systemUsage=*/ true);
+
+ // Sort by app usage count: id1 should win
+ List<SearchResult> page = mAppSearchImpl.query("package", "database", "",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_USAGE_COUNT)
+ .build(), /*logger=*/ null).getResults();
+ assertThat(page).hasSize(2);
+ assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id1");
+ assertThat(page.get(1).getGenericDocument().getId()).isEqualTo("id2");
+
+ // Sort by app usage timestamp: id2 should win
+ page = mAppSearchImpl.query("package", "database", "",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP)
+ .build(), /*logger=*/ null).getResults();
+ assertThat(page).hasSize(2);
+ assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id2");
+ assertThat(page.get(1).getGenericDocument().getId()).isEqualTo("id1");
+
+ // Sort by system usage count: id2 should win
+ page = mAppSearchImpl.query("package", "database", "",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_COUNT)
+ .build(), /*logger=*/ null).getResults();
+ assertThat(page).hasSize(2);
+ assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id2");
+ assertThat(page.get(1).getGenericDocument().getId()).isEqualTo("id1");
+
+ // Sort by system usage timestamp: id1 should win
+ page = mAppSearchImpl.query("package", "database", "",
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .setRankingStrategy(
+ SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP)
+ .build(), /*logger=*/ null).getResults();
+ assertThat(page).hasSize(2);
+ assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id1");
+ assertThat(page.get(1).getGenericDocument().getId()).isEqualTo("id2");
+ }
+
+ @Test
+ public void testGetStorageInfoForPackage_nonexistentPackage() throws Exception {
+ // "package2" doesn't exist yet, so it shouldn't have any storage size
+ StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForPackage("nonexistent.package");
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(0);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetStorageInfoForPackage_withoutDocument() throws Exception {
+ // Insert schema for "package1"
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Since "package1" doesn't have a document, it get any space attributed to it.
+ StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForPackage("package1");
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(0);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetStorageInfoForPackage_proportionalToDocuments() throws Exception {
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+
+ // Insert schema for "package1"
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert document for "package1"
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "id1", "type").build();
+ mAppSearchImpl.putDocument("package1", "database", document, /*logger=*/ null);
+
+ // Insert schema for "package2"
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert two documents for "package2"
+ document = new GenericDocument.Builder<>("namespace", "id1", "type").build();
+ mAppSearchImpl.putDocument("package2", "database", document, /*logger=*/ null);
+ document = new GenericDocument.Builder<>("namespace", "id2", "type").build();
+ mAppSearchImpl.putDocument("package2", "database", document, /*logger=*/ null);
+
+ StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForPackage("package1");
+ long size1 = storageInfo.getSizeBytes();
+ assertThat(size1).isGreaterThan(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(1);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(1);
+
+ storageInfo = mAppSearchImpl.getStorageInfoForPackage("package2");
+ long size2 = storageInfo.getSizeBytes();
+ assertThat(size2).isGreaterThan(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(2);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(1);
+
+ // Size is proportional to number of documents. Since "package2" has twice as many
+ // documents as "package1", its size is twice as much too.
+ assertThat(size2).isAtLeast(2 * size1);
+ }
+
+ @Test
+ public void testGetStorageInfoForDatabase_nonexistentPackage() throws Exception {
+ // "package2" doesn't exist yet, so it shouldn't have any storage size
+ StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForDatabase("nonexistent.package",
+ "nonexistentDatabase");
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(0);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetStorageInfoForDatabase_nonexistentDatabase() throws Exception {
+ // Insert schema for "package1"
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // "package2" doesn't exist yet, so it shouldn't have any storage size
+ StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForDatabase("package1",
+ "nonexistentDatabase");
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(0);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetStorageInfoForDatabase_withoutDocument() throws Exception {
+ // Insert schema for "package1"
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Since "package1", "database1" doesn't have a document, it get any space attributed to it.
+ StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForDatabase("package1", "database1");
+ assertThat(storageInfo.getSizeBytes()).isEqualTo(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(0);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetStorageInfoForDatabase_proportionalToDocuments() throws Exception {
+ // Insert schema for "package1", "database1" and "database2"
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database2",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Add a document for "package1", "database1"
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace1", "id1", "type").build();
+ mAppSearchImpl.putDocument("package1", "database1", document, /*logger=*/ null);
+
+ // Add two documents for "package1", "database2"
+ document = new GenericDocument.Builder<>("namespace1", "id1", "type").build();
+ mAppSearchImpl.putDocument("package1", "database2", document, /*logger=*/ null);
+ document = new GenericDocument.Builder<>("namespace1", "id2", "type").build();
+ mAppSearchImpl.putDocument("package1", "database2", document, /*logger=*/ null);
+
+
+ StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForDatabase("package1", "database1");
+ long size1 = storageInfo.getSizeBytes();
+ assertThat(size1).isGreaterThan(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(1);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(1);
+
+ storageInfo = mAppSearchImpl.getStorageInfoForDatabase("package1", "database2");
+ long size2 = storageInfo.getSizeBytes();
+ assertThat(size2).isGreaterThan(0);
+ assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(2);
+ assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(1);
+
+ // Size is proportional to number of documents. Since "database2" has twice as many
+ // documents as "database1", its size is twice as much too.
+ assertThat(size2).isAtLeast(2 * size1);
+ }
+
+ @Test
+ public void testThrowsExceptionIfClosed() throws Exception {
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+
+ // Initial check that we could do something at first.
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ appSearchImpl.close();
+
+ // Check all our public APIs
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.getSchema(
+ "package", "database"));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id", "type").build(),
+ /*logger=*/ null));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.getDocument(
+ "package", "database", "namespace", "id", Collections.emptyMap()));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.query(
+ "package",
+ "database",
+ "query",
+ new SearchSpec.Builder().build(),
+ /*logger=*/ null));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.globalQuery(
+ "query",
+ new SearchSpec.Builder().build(),
+ "package",
+ /*visibilityStore=*/ null,
+ Process.INVALID_UID,
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.getNextPage("package",
+ /*nextPageToken=*/ 1L, /*statsBuilder=*/ null));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.invalidateNextPageToken(
+ "package",
+ /*nextPageToken=*/ 1L));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.reportUsage(
+ "package", "database", "namespace", "id",
+ /*usageTimestampMillis=*/ 1000L, /*systemUsage=*/ false));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.remove(
+ "package", "database", "namespace", "id", /*removeStatsBuilder=*/ null));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.removeByQuery(
+ "package",
+ "database",
+ "query",
+ new SearchSpec.Builder().build(),
+ /*removeStatsBuilder=*/ null));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.getStorageInfoForPackage(
+ "package"));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.getStorageInfoForDatabase(
+ "package", "database"));
+
+ assertThrows(IllegalStateException.class, () -> appSearchImpl.persistToDisk(
+ PersistType.Code.FULL));
+ }
+
+ @Test
+ public void testPutPersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Add a document and persist it.
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace1", "id1", "type").build();
+ appSearchImpl.putDocument("package", "database", document, /*logger=*/null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult = appSearchImpl.getDocument("package", "database", "namespace1",
+ "id1",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document);
+
+ // That document should be visible even from another instance.
+ AppSearchImpl appSearchImpl2 = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+ getResult = appSearchImpl2.getDocument("package", "database", "namespace1",
+ "id1",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document);
+ }
+
+ @Test
+ public void testDeletePersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Add two documents and persist them.
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace1", "id1", "type").build();
+ appSearchImpl.putDocument("package", "database", document1, /*logger=*/null);
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace1", "id2", "type").build();
+ appSearchImpl.putDocument("package", "database", document2, /*logger=*/null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult = appSearchImpl.getDocument("package", "database", "namespace1",
+ "id1",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document1);
+ getResult = appSearchImpl.getDocument("package", "database", "namespace1",
+ "id2",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Delete the first document
+ appSearchImpl.remove("package", "database", "namespace1", "id1", /*statsBuilder=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+ assertThrows(AppSearchException.class, () -> appSearchImpl.getDocument("package",
+ "database",
+ "namespace1",
+ "id1",
+ Collections.emptyMap()));
+ getResult = appSearchImpl.getDocument("package", "database", "namespace1",
+ "id2",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Only the second document should be retrievable from another instance.
+ AppSearchImpl appSearchImpl2 = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+ assertThrows(AppSearchException.class, () -> appSearchImpl2.getDocument("package",
+ "database",
+ "namespace1",
+ "id1",
+ Collections.emptyMap()));
+ getResult = appSearchImpl2.getDocument("package", "database", "namespace1",
+ "id2",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+ }
+
+ @Test
+ public void testDeleteByQueryPersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Add two documents and persist them.
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace1", "id1", "type").build();
+ appSearchImpl.putDocument("package", "database", document1, /*logger=*/null);
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace2", "id2", "type").build();
+ appSearchImpl.putDocument("package", "database", document2, /*logger=*/null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult = appSearchImpl.getDocument("package", "database", "namespace1",
+ "id1",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document1);
+ getResult = appSearchImpl.getDocument("package", "database", "namespace2",
+ "id2",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Delete the first document
+ appSearchImpl.removeByQuery("package", "database", "",
+ new SearchSpec.Builder().addFilterNamespaces("namespace1").setTermMatch(
+ SearchSpec.TERM_MATCH_EXACT_ONLY).build(), /*statsBuilder=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+ assertThrows(AppSearchException.class, () -> appSearchImpl.getDocument("package",
+ "database",
+ "namespace1",
+ "id1",
+ Collections.emptyMap()));
+ getResult = appSearchImpl.getDocument("package", "database", "namespace2",
+ "id2",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Only the second document should be retrievable from another instance.
+ AppSearchImpl appSearchImpl2 = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+ assertThrows(AppSearchException.class, () -> appSearchImpl2.getDocument("package",
+ "database",
+ "namespace1",
+ "id1",
+ Collections.emptyMap()));
+ getResult = appSearchImpl2.getDocument("package", "database", "namespace2",
+ "id2",
+ Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+ }
+
+ @Test
+ public void testGetIcingSearchEngineStorageInfo() throws Exception {
+ // Setup the index
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ appsearchDir,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Add two documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace1", "id1", "type").build();
+ appSearchImpl.putDocument("package", "database", document1, /*logger=*/null);
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace1", "id2", "type").build();
+ appSearchImpl.putDocument("package", "database", document2, /*logger=*/null);
+
+ StorageInfoProto storageInfo = appSearchImpl.getRawStorageInfoProto();
+
+ // Simple checks to verify if we can get correct StorageInfoProto from IcingSearchEngine
+ // No need to cover all the fields
+ assertThat(storageInfo.getTotalStorageSize()).isGreaterThan(0);
+ assertThat(
+ storageInfo.getDocumentStorageInfo().getNumAliveDocuments())
+ .isEqualTo(2);
+ assertThat(
+ storageInfo.getSchemaStoreStorageInfo().getNumSchemaTypes())
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void testLimitConfig_DocumentSize() throws Exception {
+ // Create a new mAppSearchImpl with a lower limit
+ mAppSearchImpl.close();
+ mAppSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return 80;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 1;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Insert schema
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert a document which is too large
+ GenericDocument document = new GenericDocument.Builder<>(
+ "this_namespace_is_long_to_make_the_doc_big", "id", "type").build();
+ AppSearchException e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Document \"id\" for package \"package\" serialized to 99 bytes, which exceeds"
+ + " limit of 80 bytes");
+
+ // Make sure this failure didn't increase our document count. We should still be able to
+ // index 1 document.
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "type").build();
+ mAppSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
+
+ // Now we should get a failure
+ GenericDocument document3 =
+ new GenericDocument.Builder<>("namespace", "id3", "type").build();
+ e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document3, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 1 documents");
+ }
+
+ @Test
+ public void testLimitConfig_Init() throws Exception {
+ // Create a new mAppSearchImpl with a lower limit
+ mAppSearchImpl.close();
+ File tempFolder = mTemporaryFolder.newFolder();
+ mAppSearchImpl = AppSearchImpl.create(
+ tempFolder,
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return 80;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 1;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Insert schema
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Index a document
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id1", "type").build(),
+ /*logger=*/ null);
+
+ // Now we should get a failure
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "type").build();
+ AppSearchException e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document2, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 1 documents");
+
+ // Close and reinitialize AppSearchImpl
+ mAppSearchImpl.close();
+ mAppSearchImpl = AppSearchImpl.create(
+ tempFolder,
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return 80;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 1;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Make sure the limit is maintained
+ e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document2, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 1 documents");
+ }
+
+ @Test
+ public void testLimitConfig_Remove() throws Exception {
+ // Create a new mAppSearchImpl with a lower limit
+ mAppSearchImpl.close();
+ mAppSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 3;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Insert schema
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Index 3 documents
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id1", "type").build(),
+ /*logger=*/ null);
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id2", "type").build(),
+ /*logger=*/ null);
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id3", "type").build(),
+ /*logger=*/ null);
+
+ // Now we should get a failure
+ GenericDocument document4 =
+ new GenericDocument.Builder<>("namespace", "id4", "type").build();
+ AppSearchException e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document4, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 3 documents");
+
+ // Remove a document that doesn't exist
+ assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.remove(
+ "package", "database", "namespace", "id4", /*removeStatsBuilder=*/null));
+
+ // Should still fail
+ e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document4, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 3 documents");
+
+ // Remove a document that does exist
+ mAppSearchImpl.remove(
+ "package", "database", "namespace", "id2", /*removeStatsBuilder=*/null);
+
+ // Now doc4 should work
+ mAppSearchImpl.putDocument("package", "database", document4, /*logger=*/ null);
+
+ // The next one should fail again
+ e = assertThrows(AppSearchException.class, () -> mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id5", "type").build(),
+ /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 3 documents");
+ }
+
+ @Test
+ public void testLimitConfig_DifferentPackages() throws Exception {
+ // Create a new mAppSearchImpl with a lower limit
+ mAppSearchImpl.close();
+ File tempFolder = mTemporaryFolder.newFolder();
+ mAppSearchImpl = AppSearchImpl.create(
+ tempFolder,
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 2;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Insert schema
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database2",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database1",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database2",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Index documents in package1/database1
+ mAppSearchImpl.putDocument(
+ "package1",
+ "database1",
+ new GenericDocument.Builder<>("namespace", "id1", "type").build(),
+ /*logger=*/ null);
+ mAppSearchImpl.putDocument(
+ "package1",
+ "database2",
+ new GenericDocument.Builder<>("namespace", "id2", "type").build(),
+ /*logger=*/ null);
+
+ // Indexing a third doc into package1 should fail (here we use database3)
+ AppSearchException e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument(
+ "package1",
+ "database3",
+ new GenericDocument.Builder<>("namespace", "id3", "type").build(),
+ /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package1\" exceeded limit of 2 documents");
+
+ // Indexing a doc into package2 should succeed
+ mAppSearchImpl.putDocument(
+ "package2",
+ "database1",
+ new GenericDocument.Builder<>("namespace", "id1", "type").build(),
+ /*logger=*/ null);
+
+ // Reinitialize to make sure packages are parsed correctly on init
+ mAppSearchImpl.close();
+ mAppSearchImpl = AppSearchImpl.create(
+ tempFolder,
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 2;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // package1 should still be out of space
+ e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument(
+ "package1",
+ "database4",
+ new GenericDocument.Builder<>("namespace", "id4", "type").build(),
+ /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package1\" exceeded limit of 2 documents");
+
+ // package2 has room for one more
+ mAppSearchImpl.putDocument(
+ "package2",
+ "database2",
+ new GenericDocument.Builder<>("namespace", "id2", "type").build(),
+ /*logger=*/ null);
+
+ // now package2 really is out of space
+ e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument(
+ "package2",
+ "database3",
+ new GenericDocument.Builder<>("namespace", "id3", "type").build(),
+ /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package2\" exceeded limit of 2 documents");
+ }
+
+ @Test
+ public void testLimitConfig_RemoveByQyery() throws Exception {
+ // Create a new mAppSearchImpl with a lower limit
+ mAppSearchImpl.close();
+ mAppSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 3;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Insert schema
+ List<AppSearchSchema> schemas = Collections.singletonList(
+ new AppSearchSchema.Builder("type")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("body")
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Index 3 documents
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id1", "type")
+ .setPropertyString("body", "tablet")
+ .build(),
+ /*logger=*/ null);
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id2", "type")
+ .setPropertyString("body", "tabby")
+ .build(),
+ /*logger=*/ null);
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id3", "type")
+ .setPropertyString("body", "grabby")
+ .build(),
+ /*logger=*/ null);
+
+ // Now we should get a failure
+ GenericDocument document4 =
+ new GenericDocument.Builder<>("namespace", "id4", "type").build();
+ AppSearchException e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document4, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 3 documents");
+
+ // Run removebyquery, deleting nothing
+ mAppSearchImpl.removeByQuery(
+ "package",
+ "database",
+ "nothing",
+ new SearchSpec.Builder().build(),
+ /*removeStatsBuilder=*/null);
+
+ // Should still fail
+ e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document4, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 3 documents");
+
+ // Remove "tab*"
+ mAppSearchImpl.removeByQuery(
+ "package",
+ "database",
+ "tab",
+ new SearchSpec.Builder().build(),
+ /*removeStatsBuilder=*/null);
+
+ // Now doc4 and doc5 should work
+ mAppSearchImpl.putDocument("package", "database", document4, /*logger=*/ null);
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id5", "type").build(),
+ /*logger=*/ null);
+
+ // We only deleted 2 docs so the next one should fail again
+ e = assertThrows(AppSearchException.class, () -> mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id6", "type").build(),
+ /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 3 documents");
+ }
+
+ @Test
+ public void testLimitConfig_Replace() throws Exception {
+ // Create a new mAppSearchImpl with a lower limit
+ mAppSearchImpl.close();
+ mAppSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 2;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Insert schema
+ List<AppSearchSchema> schemas = Collections.singletonList(
+ new AppSearchSchema.Builder("type")
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder("body").build())
+ .build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Index a document
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id1", "type")
+ .setPropertyString("body", "id1.orig")
+ .build(),
+ /*logger=*/ null);
+ // Replace it with another doc
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id1", "type")
+ .setPropertyString("body", "id1.new")
+ .build(),
+ /*logger=*/ null);
+
+ // Index id2. This should pass but only because we check for replacements.
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id2", "type").build(),
+ /*logger=*/ null);
+
+ // Now we should get a failure on id3
+ GenericDocument document3 =
+ new GenericDocument.Builder<>("namespace", "id3", "type").build();
+ AppSearchException e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document3, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 2 documents");
+ }
+
+ @Test
+ public void testLimitConfig_ReplaceReinit() throws Exception {
+ // Create a new mAppSearchImpl with a lower limit
+ mAppSearchImpl.close();
+ File tempFolder = mTemporaryFolder.newFolder();
+ mAppSearchImpl = AppSearchImpl.create(
+ tempFolder,
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 2;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Insert schema
+ List<AppSearchSchema> schemas = Collections.singletonList(
+ new AppSearchSchema.Builder("type")
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder("body").build())
+ .build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Index a document
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id1", "type")
+ .setPropertyString("body", "id1.orig")
+ .build(),
+ /*logger=*/ null);
+ // Replace it with another doc
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id1", "type")
+ .setPropertyString("body", "id1.new")
+ .build(),
+ /*logger=*/ null);
+
+ // Reinitialize to make sure replacements are correctly accounted for by init
+ mAppSearchImpl.close();
+ mAppSearchImpl = AppSearchImpl.create(
+ tempFolder,
+ new LimitConfig() {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return 2;
+ }
+ },
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ // Index id2. This should pass but only because we check for replacements.
+ mAppSearchImpl.putDocument(
+ "package",
+ "database",
+ new GenericDocument.Builder<>("namespace", "id2", "type").build(),
+ /*logger=*/ null);
+
+ // Now we should get a failure on id3
+ GenericDocument document3 =
+ new GenericDocument.Builder<>("namespace", "id3", "type").build();
+ AppSearchException e = assertThrows(AppSearchException.class, () ->
+ mAppSearchImpl.putDocument("package", "database", document3, /*logger=*/ null));
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_OUT_OF_SPACE);
+ assertThat(e).hasMessageThat().contains(
+ "Package \"package\" exceeded limit of 2 documents");
+ }
}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchLoggerTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchLoggerTest.java
new file mode 100644
index 0000000..a0dbd6c
--- /dev/null
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchLoggerTest.java
@@ -0,0 +1,861 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.SearchResultPage;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.stats.CallStats;
+import androidx.appsearch.localstorage.stats.InitializeStats;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
+import androidx.appsearch.localstorage.stats.PutDocumentStats;
+import androidx.appsearch.localstorage.stats.RemoveStats;
+import androidx.appsearch.localstorage.stats.SearchStats;
+import androidx.appsearch.localstorage.stats.SetSchemaStats;
+
+import com.google.android.icing.proto.DeleteStatsProto;
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.InitializeStatsProto;
+import com.google.android.icing.proto.OptimizeStatsProto;
+import com.google.android.icing.proto.PutDocumentStatsProto;
+import com.google.android.icing.proto.PutResultProto;
+import com.google.android.icing.proto.QueryStatsProto;
+import com.google.android.icing.proto.ScoringSpecProto;
+import com.google.android.icing.proto.SetSchemaResultProto;
+import com.google.android.icing.proto.StatusProto;
+import com.google.android.icing.proto.TermMatchType;
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+public class AppSearchLoggerTest {
+ private static final String PACKAGE_NAME = "packageName";
+ private static final String DATABASE = "database";
+ /**
+ * Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
+ */
+ private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private AppSearchImpl mAppSearchImpl;
+ private TestLogger mLogger;
+
+ @Before
+ public void setUp() throws Exception {
+ mAppSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+ mLogger = new TestLogger();
+ }
+
+ // Test only not thread safe.
+ public static class TestLogger implements AppSearchLogger {
+ @Nullable
+ CallStats mCallStats;
+ @Nullable
+ PutDocumentStats mPutDocumentStats;
+ @Nullable
+ InitializeStats mInitializeStats;
+ @Nullable
+ SearchStats mSearchStats;
+ @Nullable
+ RemoveStats mRemoveStats;
+ @Nullable
+ OptimizeStats mOptimizeStats;
+ @Nullable
+ SetSchemaStats mSetSchemaStats;
+
+ @Override
+ public void logStats(@NonNull CallStats stats) {
+ mCallStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull PutDocumentStats stats) {
+ mPutDocumentStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull InitializeStats stats) {
+ mInitializeStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull SearchStats stats) {
+ mSearchStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull RemoveStats stats) {
+ mRemoveStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull OptimizeStats stats) {
+ mOptimizeStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull SetSchemaStats stats) {
+ mSetSchemaStats = stats;
+ }
+ }
+
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_initialize() {
+ int nativeLatencyMillis = 3;
+ int nativeDocumentStoreRecoveryCause = InitializeStatsProto.RecoveryCause.DATA_LOSS_VALUE;
+ int nativeIndexRestorationCause =
+ InitializeStatsProto.RecoveryCause.INCONSISTENT_WITH_GROUND_TRUTH_VALUE;
+ int nativeSchemaStoreRecoveryCause =
+ InitializeStatsProto.RecoveryCause.SCHEMA_CHANGES_OUT_OF_SYNC_VALUE;
+ int nativeDocumentStoreRecoveryLatencyMillis = 7;
+ int nativeIndexRestorationLatencyMillis = 8;
+ int nativeSchemaStoreRecoveryLatencyMillis = 9;
+ int nativeDocumentStoreDataStatus =
+ InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE;
+ int nativeNumDocuments = 11;
+ int nativeNumSchemaTypes = 12;
+ InitializeStatsProto.Builder nativeInitBuilder = InitializeStatsProto.newBuilder()
+ .setLatencyMs(nativeLatencyMillis)
+ .setDocumentStoreRecoveryCause(InitializeStatsProto.RecoveryCause.forNumber(
+ nativeDocumentStoreRecoveryCause))
+ .setIndexRestorationCause(
+ InitializeStatsProto.RecoveryCause.forNumber(nativeIndexRestorationCause))
+ .setSchemaStoreRecoveryCause(
+ InitializeStatsProto.RecoveryCause.forNumber(
+ nativeSchemaStoreRecoveryCause))
+ .setDocumentStoreRecoveryLatencyMs(nativeDocumentStoreRecoveryLatencyMillis)
+ .setIndexRestorationLatencyMs(nativeIndexRestorationLatencyMillis)
+ .setSchemaStoreRecoveryLatencyMs(nativeSchemaStoreRecoveryLatencyMillis)
+ .setDocumentStoreDataStatus(InitializeStatsProto.DocumentStoreDataStatus.forNumber(
+ nativeDocumentStoreDataStatus))
+ .setNumDocuments(nativeNumDocuments)
+ .setNumSchemaTypes(nativeNumSchemaTypes);
+ InitializeStats.Builder initBuilder = new InitializeStats.Builder();
+
+ AppSearchLoggerHelper.copyNativeStats(nativeInitBuilder.build(), initBuilder);
+
+ InitializeStats iStats = initBuilder.build();
+ assertThat(iStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(iStats.getDocumentStoreRecoveryCause()).isEqualTo(
+ nativeDocumentStoreRecoveryCause);
+ assertThat(iStats.getIndexRestorationCause()).isEqualTo(nativeIndexRestorationCause);
+ assertThat(iStats.getSchemaStoreRecoveryCause()).isEqualTo(
+ nativeSchemaStoreRecoveryCause);
+ assertThat(iStats.getDocumentStoreRecoveryLatencyMillis()).isEqualTo(
+ nativeDocumentStoreRecoveryLatencyMillis);
+ assertThat(iStats.getIndexRestorationLatencyMillis()).isEqualTo(
+ nativeIndexRestorationLatencyMillis);
+ assertThat(iStats.getSchemaStoreRecoveryLatencyMillis()).isEqualTo(
+ nativeSchemaStoreRecoveryLatencyMillis);
+ assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(
+ nativeDocumentStoreDataStatus);
+ assertThat(iStats.getDocumentCount()).isEqualTo(nativeNumDocuments);
+ assertThat(iStats.getSchemaTypeCount()).isEqualTo(nativeNumSchemaTypes);
+ }
+
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_putDocument() {
+ final int nativeLatencyMillis = 3;
+ final int nativeDocumentStoreLatencyMillis = 4;
+ final int nativeIndexLatencyMillis = 5;
+ final int nativeIndexMergeLatencyMillis = 6;
+ final int nativeDocumentSize = 7;
+ final int nativeNumTokensIndexed = 8;
+ final boolean nativeExceededMaxNumTokens = true;
+ PutDocumentStatsProto nativePutDocumentStats = PutDocumentStatsProto.newBuilder()
+ .setLatencyMs(nativeLatencyMillis)
+ .setDocumentStoreLatencyMs(nativeDocumentStoreLatencyMillis)
+ .setIndexLatencyMs(nativeIndexLatencyMillis)
+ .setIndexMergeLatencyMs(nativeIndexMergeLatencyMillis)
+ .setDocumentSize(nativeDocumentSize)
+ .setTokenizationStats(PutDocumentStatsProto.TokenizationStats.newBuilder()
+ .setNumTokensIndexed(nativeNumTokensIndexed)
+ .setExceededMaxTokenNum(nativeExceededMaxNumTokens)
+ .build())
+ .build();
+ PutDocumentStats.Builder pBuilder = new PutDocumentStats.Builder(PACKAGE_NAME, DATABASE);
+
+ AppSearchLoggerHelper.copyNativeStats(nativePutDocumentStats, pBuilder);
+
+ PutDocumentStats pStats = pBuilder.build();
+ assertThat(pStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(pStats.getNativeDocumentStoreLatencyMillis()).isEqualTo(
+ nativeDocumentStoreLatencyMillis);
+ assertThat(pStats.getNativeIndexLatencyMillis()).isEqualTo(nativeIndexLatencyMillis);
+ assertThat(pStats.getNativeIndexMergeLatencyMillis()).isEqualTo(
+ nativeIndexMergeLatencyMillis);
+ assertThat(pStats.getNativeDocumentSizeBytes()).isEqualTo(nativeDocumentSize);
+ assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed);
+ assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens);
+ }
+
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_search() {
+ int nativeLatencyMillis = 4;
+ int nativeNumTerms = 5;
+ int nativeQueryLength = 6;
+ int nativeNumNamespacesFiltered = 7;
+ int nativeNumSchemaTypesFiltered = 8;
+ int nativeRequestedPageSize = 9;
+ int nativeNumResultsReturnedCurrentPage = 10;
+ boolean nativeIsFirstPage = true;
+ int nativeParseQueryLatencyMillis = 11;
+ int nativeRankingStrategy = ScoringSpecProto.RankingStrategy.Code.CREATION_TIMESTAMP_VALUE;
+ int nativeNumDocumentsScored = 13;
+ int nativeScoringLatencyMillis = 14;
+ int nativeRankingLatencyMillis = 15;
+ int nativeNumResultsWithSnippets = 16;
+ int nativeDocumentRetrievingLatencyMillis = 17;
+ QueryStatsProto nativeQueryStats = QueryStatsProto.newBuilder()
+ .setLatencyMs(nativeLatencyMillis)
+ .setNumTerms(nativeNumTerms)
+ .setQueryLength(nativeQueryLength)
+ .setNumNamespacesFiltered(nativeNumNamespacesFiltered)
+ .setNumSchemaTypesFiltered(nativeNumSchemaTypesFiltered)
+ .setRequestedPageSize(nativeRequestedPageSize)
+ .setNumResultsReturnedCurrentPage(nativeNumResultsReturnedCurrentPage)
+ .setIsFirstPage(nativeIsFirstPage)
+ .setParseQueryLatencyMs(nativeParseQueryLatencyMillis)
+ .setRankingStrategy(
+ ScoringSpecProto.RankingStrategy.Code.forNumber(nativeRankingStrategy))
+ .setNumDocumentsScored(nativeNumDocumentsScored)
+ .setScoringLatencyMs(nativeScoringLatencyMillis)
+ .setRankingLatencyMs(nativeRankingLatencyMillis)
+ .setNumResultsWithSnippets(nativeNumResultsWithSnippets)
+ .setDocumentRetrievalLatencyMs(nativeDocumentRetrievingLatencyMillis)
+ .build();
+ SearchStats.Builder qBuilder = new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL,
+ PACKAGE_NAME).setDatabase(DATABASE);
+
+ AppSearchLoggerHelper.copyNativeStats(nativeQueryStats, qBuilder);
+
+ SearchStats sStats = qBuilder.build();
+ assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(sStats.getTermCount()).isEqualTo(nativeNumTerms);
+ assertThat(sStats.getQueryLength()).isEqualTo(nativeQueryLength);
+ assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(nativeNumNamespacesFiltered);
+ assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(
+ nativeNumSchemaTypesFiltered);
+ assertThat(sStats.getRequestedPageSize()).isEqualTo(nativeRequestedPageSize);
+ assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(
+ nativeNumResultsReturnedCurrentPage);
+ assertThat(sStats.isFirstPage()).isTrue();
+ assertThat(sStats.getParseQueryLatencyMillis()).isEqualTo(
+ nativeParseQueryLatencyMillis);
+ assertThat(sStats.getRankingStrategy()).isEqualTo(nativeRankingStrategy);
+ assertThat(sStats.getScoredDocumentCount()).isEqualTo(nativeNumDocumentsScored);
+ assertThat(sStats.getScoringLatencyMillis()).isEqualTo(nativeScoringLatencyMillis);
+ assertThat(sStats.getRankingLatencyMillis()).isEqualTo(nativeRankingLatencyMillis);
+ assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(nativeNumResultsWithSnippets);
+ assertThat(sStats.getDocumentRetrievingLatencyMillis()).isEqualTo(
+ nativeDocumentRetrievingLatencyMillis);
+ }
+
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_remove() {
+ final int nativeLatencyMillis = 1;
+ final int nativeDeleteType = 2;
+ final int nativeNumDocumentDeleted = 3;
+ DeleteStatsProto nativeDeleteStatsProto = DeleteStatsProto.newBuilder()
+ .setLatencyMs(nativeLatencyMillis)
+ .setDeleteType(DeleteStatsProto.DeleteType.Code.forNumber(nativeDeleteType))
+ .setNumDocumentsDeleted(nativeNumDocumentDeleted)
+ .build();
+ RemoveStats.Builder rBuilder = new RemoveStats.Builder(
+ "packageName",
+ "database");
+
+ AppSearchLoggerHelper.copyNativeStats(nativeDeleteStatsProto, rBuilder);
+
+ RemoveStats rStats = rBuilder.build();
+ assertThat(rStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(rStats.getDeleteType()).isEqualTo(nativeDeleteType);
+ assertThat(rStats.getDeletedDocumentCount()).isEqualTo(nativeNumDocumentDeleted);
+ }
+
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_optimize() {
+ int nativeLatencyMillis = 1;
+ int nativeDocumentStoreOptimizeLatencyMillis = 2;
+ int nativeIndexRestorationLatencyMillis = 3;
+ int nativeNumOriginalDocuments = 4;
+ int nativeNumDeletedDocuments = 5;
+ int nativeNumExpiredDocuments = 6;
+ long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1;
+ long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2;
+ long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3;
+ OptimizeStatsProto optimizeStatsProto = OptimizeStatsProto.newBuilder()
+ .setLatencyMs(nativeLatencyMillis)
+ .setDocumentStoreOptimizeLatencyMs(nativeDocumentStoreOptimizeLatencyMillis)
+ .setIndexRestorationLatencyMs(nativeIndexRestorationLatencyMillis)
+ .setNumOriginalDocuments(nativeNumOriginalDocuments)
+ .setNumDeletedDocuments(nativeNumDeletedDocuments)
+ .setNumExpiredDocuments(nativeNumExpiredDocuments)
+ .setStorageSizeBefore(nativeStorageSizeBeforeBytes)
+ .setStorageSizeAfter(nativeStorageSizeAfterBytes)
+ .setTimeSinceLastOptimizeMs(nativeTimeSinceLastOptimizeMillis)
+ .build();
+ OptimizeStats.Builder oBuilder = new OptimizeStats.Builder();
+
+ AppSearchLoggerHelper.copyNativeStats(optimizeStatsProto, oBuilder);
+
+ OptimizeStats oStats = oBuilder.build();
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getDocumentStoreOptimizeLatencyMillis()).isEqualTo(
+ nativeDocumentStoreOptimizeLatencyMillis);
+ assertThat(oStats.getIndexRestorationLatencyMillis()).isEqualTo(
+ nativeIndexRestorationLatencyMillis);
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments);
+ assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments);
+ assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes);
+ assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes);
+ assertThat(oStats.getTimeSinceLastOptimizeMillis()).isEqualTo(
+ nativeTimeSinceLastOptimizeMillis);
+ }
+
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_setSchema() {
+ ImmutableList<String> newSchemaTypeChangeList = ImmutableList.of("new1");
+ ImmutableList<String> deletedSchemaTypesList = ImmutableList.of("deleted1", "deleted2");
+ ImmutableList<String> compatibleTypesList = ImmutableList.of("compatible1", "compatible2");
+ ImmutableList<String> indexIncompatibleTypeChangeList = ImmutableList.of("index1");
+ ImmutableList<String> backwardsIncompatibleTypeChangeList = ImmutableList.of("backwards1");
+ SetSchemaResultProto setSchemaResultProto = SetSchemaResultProto.newBuilder()
+ .addAllNewSchemaTypes(newSchemaTypeChangeList)
+ .addAllDeletedSchemaTypes(deletedSchemaTypesList)
+ .addAllFullyCompatibleChangedSchemaTypes(compatibleTypesList)
+ .addAllIndexIncompatibleChangedSchemaTypes(indexIncompatibleTypeChangeList)
+ .addAllIncompatibleSchemaTypes(backwardsIncompatibleTypeChangeList)
+ .build();
+ SetSchemaStats.Builder sBuilder = new SetSchemaStats.Builder(PACKAGE_NAME, DATABASE);
+
+ AppSearchLoggerHelper.copyNativeStats(setSchemaResultProto, sBuilder);
+
+ SetSchemaStats sStats = sBuilder.build();
+ assertThat(sStats.getNewTypeCount()).isEqualTo(newSchemaTypeChangeList.size());
+ assertThat(sStats.getDeletedTypeCount()).isEqualTo(deletedSchemaTypesList.size());
+ assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypesList.size());
+ assertThat(sStats.getIndexIncompatibleTypeChangeCount()).isEqualTo(
+ indexIncompatibleTypeChangeList.size());
+ assertThat(sStats.getBackwardsIncompatibleTypeChangeCount()).isEqualTo(
+ backwardsIncompatibleTypeChangeList.size());
+ }
+
+ //
+ // Testing actual logging
+ //
+ @Test
+ public void testLoggingStats_initializeWithoutDocuments_success() throws Exception {
+ // Create an unused AppSearchImpl to generated an InitializeStats.
+ InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
+ AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ initStatsBuilder,
+ ALWAYS_OPTIMIZE);
+ InitializeStats iStats = initStatsBuilder.build();
+
+ assertThat(iStats).isNotNull();
+ assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ // Total latency captured in LocalStorage
+ assertThat(iStats.getTotalLatencyMillis()).isEqualTo(0);
+ assertThat(iStats.hasDeSync()).isFalse();
+ assertThat(iStats.getNativeLatencyMillis()).isGreaterThan(0);
+ assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(
+ InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE);
+ assertThat(iStats.getDocumentCount()).isEqualTo(0);
+ assertThat(iStats.getSchemaTypeCount()).isEqualTo(0);
+ assertThat(iStats.hasReset()).isEqualTo(false);
+ assertThat(iStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ }
+
+ @Test
+ public void testLoggingStats_initializeWithDocuments_success() throws Exception {
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ final File folder = mTemporaryFolder.newFolder();
+
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ folder,
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null,
+ ALWAYS_OPTIMIZE);
+ List<AppSearchSchema> schemas = ImmutableList.of(
+ new AppSearchSchema.Builder("Type1").build(),
+ new AppSearchSchema.Builder("Type2").build());
+ appSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ GenericDocument doc1 =
+ new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
+ GenericDocument doc2 =
+ new GenericDocument.Builder<>("namespace", "id2", "Type1").build();
+ appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger);
+ appSearchImpl.putDocument(testPackageName, testDatabase, doc2, mLogger);
+ appSearchImpl.close();
+
+ // Create another appsearchImpl on the same folder
+ InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
+ AppSearchImpl.create(folder, new UnlimitedLimitConfig(), initStatsBuilder, ALWAYS_OPTIMIZE);
+ InitializeStats iStats = initStatsBuilder.build();
+
+ assertThat(iStats).isNotNull();
+ assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ // Total latency captured in LocalStorage
+ assertThat(iStats.getTotalLatencyMillis()).isEqualTo(0);
+ assertThat(iStats.hasDeSync()).isFalse();
+ assertThat(iStats.getNativeLatencyMillis()).isGreaterThan(0);
+ assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(
+ InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE);
+ assertThat(iStats.getDocumentCount()).isEqualTo(2);
+ assertThat(iStats.getSchemaTypeCount()).isEqualTo(2);
+ assertThat(iStats.hasReset()).isEqualTo(false);
+ assertThat(iStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ }
+
+ @Test
+ public void testLoggingStats_initialize_failure() throws Exception {
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ final File folder = mTemporaryFolder.newFolder();
+
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ folder, new UnlimitedLimitConfig(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ List<AppSearchSchema> schemas = ImmutableList.of(
+ new AppSearchSchema.Builder("Type1").build(),
+ new AppSearchSchema.Builder("Type2").build());
+ appSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert a valid doc
+ GenericDocument doc1 =
+ new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
+ appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger);
+
+ // Insert the invalid doc with an invalid namespace right into icing
+ DocumentProto invalidDoc = DocumentProto.newBuilder()
+ .setNamespace("invalidNamespace")
+ .setUri("id2")
+ .setSchema(String.format("%s$%s/Type1", testPackageName, testDatabase))
+ .build();
+ PutResultProto putResultProto = appSearchImpl.mIcingSearchEngineLocked.put(invalidDoc);
+ assertThat(putResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ appSearchImpl.close();
+
+ // Create another appsearchImpl on the same folder
+ InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
+ AppSearchImpl.create(folder, new UnlimitedLimitConfig(), initStatsBuilder, ALWAYS_OPTIMIZE);
+ InitializeStats iStats = initStatsBuilder.build();
+
+ // Some of other fields are already covered by AppSearchImplTest#testReset()
+ assertThat(iStats).isNotNull();
+ assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
+ assertThat(iStats.hasReset()).isTrue();
+ }
+
+ @Test
+ public void testLoggingStats_putDocument_success() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ AppSearchSchema testSchema = new AppSearchSchema.Builder("type")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ List<AppSearchSchema> schemas = Collections.singletonList(testSchema);
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "id", "type")
+ .setPropertyString("subject", "testPut example1")
+ .build();
+
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger);
+
+ PutDocumentStats pStats = mLogger.mPutDocumentStats;
+ assertThat(pStats).isNotNull();
+ assertThat(pStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(pStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(pStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ // The latency related native stats have been tested in testCopyNativeStats
+ assertThat(pStats.getNativeDocumentSizeBytes()).isGreaterThan(0);
+ assertThat(pStats.getNativeNumTokensIndexed()).isGreaterThan(0);
+ }
+
+ @Test
+ public void testLoggingStats_putDocument_failure() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ AppSearchSchema testSchema = new AppSearchSchema.Builder("type")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ List<AppSearchSchema> schemas = Collections.singletonList(testSchema);
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "id", "type")
+ .setPropertyString("nonExist", "testPut example1")
+ .build();
+
+ AppSearchException exception = Assert.assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger));
+ assertThat(exception.getResultCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ PutDocumentStats pStats = mLogger.mPutDocumentStats;
+ assertThat(pStats).isNotNull();
+ assertThat(pStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(pStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(pStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testLoggingStats_search_success() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ AppSearchSchema testSchema = new AppSearchSchema.Builder("type")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ List<AppSearchSchema> schemas = Collections.singletonList(testSchema);
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "type")
+ .setPropertyString("subject", "testPut example1")
+ .build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "type")
+ .setPropertyString("subject", "testPut example2")
+ .build();
+ GenericDocument document3 =
+ new GenericDocument.Builder<>("namespace", "id3", "type")
+ .setPropertyString("subject", "testPut 3")
+ .build();
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document1, mLogger);
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document2, mLogger);
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document3, mLogger);
+
+
+ // No query filters specified. package2 should only get its own documents back.
+ SearchSpec searchSpec =
+ new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP)
+ .build();
+ String queryStr = "testPut e";
+ SearchResultPage searchResultPage = mAppSearchImpl.query(testPackageName, testDatabase,
+ queryStr, searchSpec, /*logger=*/ mLogger);
+
+ assertThat(searchResultPage.getResults()).hasSize(2);
+ // The ranking strategy is LIFO
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+ assertThat(searchResultPage.getResults().get(1).getGenericDocument()).isEqualTo(document1);
+
+ SearchStats sStats = mLogger.mSearchStats;
+
+ assertThat(sStats).isNotNull();
+ assertThat(sStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(sStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(sStats.getTotalLatencyMillis()).isGreaterThan(0);
+ assertThat(sStats.getVisibilityScope()).isEqualTo(SearchStats.VISIBILITY_SCOPE_LOCAL);
+ assertThat(sStats.getTermCount()).isEqualTo(2);
+ assertThat(sStats.getQueryLength()).isEqualTo(queryStr.length());
+ assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(1);
+ assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(1);
+ assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(2);
+ assertThat(sStats.isFirstPage()).isTrue();
+ assertThat(sStats.getRankingStrategy()).isEqualTo(
+ SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP);
+ assertThat(sStats.getScoredDocumentCount()).isEqualTo(2);
+ assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testLoggingStats_search_failure() throws Exception {
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ List<AppSearchSchema> schemas = ImmutableList.of(
+ new AppSearchSchema.Builder("Type1").build(),
+ new AppSearchSchema.Builder("Type2").build());
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ SearchSpec searchSpec =
+ new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP)
+ .addFilterPackageNames("anotherPackage")
+ .build();
+
+ mAppSearchImpl.query(testPackageName,
+ testPackageName,
+ /* queryExpression= */ "",
+ searchSpec, /*logger=*/ mLogger);
+
+ SearchStats sStats = mLogger.mSearchStats;
+ assertThat(sStats).isNotNull();
+ assertThat(sStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(sStats.getDatabase()).isEqualTo(testPackageName);
+ assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+ }
+
+ @Test
+ public void testLoggingStats_remove_success() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ final String testNamespace = "testNameSpace";
+ final String testId = "id";
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ GenericDocument document =
+ new GenericDocument.Builder<>(testNamespace, testId, "type").build();
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document, /*logger=*/ null);
+
+ RemoveStats.Builder rStatsBuilder = new RemoveStats.Builder(testPackageName, testDatabase);
+ mAppSearchImpl.remove(testPackageName, testDatabase, testNamespace, testId, rStatsBuilder);
+ RemoveStats rStats = rStatsBuilder.build();
+
+ assertThat(rStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
+ // delete by namespace + id
+ assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.SINGLE_VALUE);
+ assertThat(rStats.getDeletedDocumentCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testLoggingStats_remove_failure() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ final String testNamespace = "testNameSpace";
+ final String testId = "id";
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ GenericDocument document =
+ new GenericDocument.Builder<>(testNamespace, testId, "type").build();
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document, /*logger=*/ null);
+
+ RemoveStats.Builder rStatsBuilder = new RemoveStats.Builder(testPackageName, testDatabase);
+
+ AppSearchException exception = Assert.assertThrows(AppSearchException.class,
+ () -> mAppSearchImpl.remove(testPackageName, testDatabase, testNamespace,
+ "invalidId", rStatsBuilder));
+ assertThat(exception.getResultCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ RemoveStats rStats = rStatsBuilder.build();
+ assertThat(rStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ // delete by namespace + id
+ assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.SINGLE_VALUE);
+ assertThat(rStats.getDeletedDocumentCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testLoggingStats_removeByQuery_success() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ final String testNamespace = "testNameSpace";
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+ GenericDocument document1 =
+ new GenericDocument.Builder<>(testNamespace, "id1", "type").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>(testNamespace, "id2", "type").build();
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document1, mLogger);
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document2, mLogger);
+ // No query filters specified. package2 should only get its own documents back.
+ SearchSpec searchSpec =
+ new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
+
+ RemoveStats.Builder rStatsBuilder = new RemoveStats.Builder(testPackageName, testDatabase);
+ mAppSearchImpl.removeByQuery(testPackageName, testDatabase,
+ /*queryExpression=*/"", searchSpec,
+ rStatsBuilder);
+ RemoveStats rStats = rStatsBuilder.build();
+
+ assertThat(rStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ // delete by query
+ assertThat(rStats.getDeleteType())
+ .isEqualTo(DeleteStatsProto.DeleteType.Code.DEPRECATED_QUERY_VALUE);
+ assertThat(rStats.getDeletedDocumentCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testLoggingStats_setSchema() throws Exception {
+ AppSearchSchema schema1 = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mAppSearchImpl.setSchema(
+ PACKAGE_NAME,
+ DATABASE,
+ Collections.singletonList(schema1),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // create a backwards incompatible schema
+ SetSchemaStats.Builder sStatsBuilder = new SetSchemaStats.Builder(PACKAGE_NAME, DATABASE);
+ AppSearchSchema schema2 = new AppSearchSchema.Builder("testSchema").build();
+ mAppSearchImpl.setSchema(
+ PACKAGE_NAME,
+ DATABASE,
+ Collections.singletonList(schema2),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ sStatsBuilder);
+
+ SetSchemaStats sStats = sStatsBuilder.build();
+ assertThat(sStats.getPackageName()).isEqualTo(PACKAGE_NAME);
+ assertThat(sStats.getDatabase()).isEqualTo(DATABASE);
+ assertThat(sStats.getNewTypeCount()).isEqualTo(0);
+ assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(0);
+ assertThat(sStats.getIndexIncompatibleTypeChangeCount()).isEqualTo(1);
+ assertThat(sStats.getBackwardsIncompatibleTypeChangeCount()).isEqualTo(1);
+ }
+}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/JetpackOptimizeStrategyTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/JetpackOptimizeStrategyTest.java
new file mode 100644
index 0000000..b33caba
--- /dev/null
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/JetpackOptimizeStrategyTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.localstorage;
+
+import static androidx.appsearch.localstorage.JetpackOptimizeStrategy.BYTES_OPTIMIZE_THRESHOLD;
+import static androidx.appsearch.localstorage.JetpackOptimizeStrategy.DOC_COUNT_OPTIMIZE_THRESHOLD;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.android.icing.proto.GetOptimizeInfoResultProto;
+import com.google.android.icing.proto.StatusProto;
+
+import org.junit.Test;
+
+public class JetpackOptimizeStrategyTest {
+ JetpackOptimizeStrategy mJetpackOptimizeStrategy = new JetpackOptimizeStrategy();
+
+ @Test
+ public void testShouldOptimize_byteThreshold() {
+ GetOptimizeInfoResultProto optimizeInfo = GetOptimizeInfoResultProto.newBuilder()
+ .setTimeSinceLastOptimizeMs(0)
+ .setEstimatedOptimizableBytes(BYTES_OPTIMIZE_THRESHOLD)
+ .setOptimizableDocs(0)
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK).build())
+ .build();
+ assertThat(mJetpackOptimizeStrategy.shouldOptimize(optimizeInfo)).isTrue();
+ }
+
+ @Test
+ public void testShouldNotOptimize_timeThreshold() {
+ GetOptimizeInfoResultProto optimizeInfo = GetOptimizeInfoResultProto.newBuilder()
+ .setTimeSinceLastOptimizeMs(Integer.MAX_VALUE)
+ .setEstimatedOptimizableBytes(0)
+ .setOptimizableDocs(0)
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK).build())
+ .build();
+ assertThat(mJetpackOptimizeStrategy.shouldOptimize(optimizeInfo)).isFalse();
+ }
+
+ @Test
+ public void testShouldOptimize_docCountThreshold() {
+ GetOptimizeInfoResultProto optimizeInfo = GetOptimizeInfoResultProto.newBuilder()
+ .setTimeSinceLastOptimizeMs(0)
+ .setEstimatedOptimizableBytes(0)
+ .setOptimizableDocs(DOC_COUNT_OPTIMIZE_THRESHOLD)
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK).build())
+ .build();
+ assertThat(mJetpackOptimizeStrategy.shouldOptimize(optimizeInfo)).isTrue();
+ }
+}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/LocalStorageTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/LocalStorageTest.java
index 254f8f7..333cea3 100644
--- a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/LocalStorageTest.java
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/LocalStorageTest.java
@@ -24,29 +24,68 @@
import org.junit.Test;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
public class LocalStorageTest {
@Test
public void testSameInstance() throws Exception {
- LocalStorage b1 =
- LocalStorage.getOrCreateInstance(ApplicationProvider.getApplicationContext());
- LocalStorage b2 =
- LocalStorage.getOrCreateInstance(ApplicationProvider.getApplicationContext());
+ Executor executor = Executors.newCachedThreadPool();
+ LocalStorage b1 = LocalStorage.getOrCreateInstance(
+ ApplicationProvider.getApplicationContext(), executor, /*logger=*/ null);
+ LocalStorage b2 = LocalStorage.getOrCreateInstance(
+ ApplicationProvider.getApplicationContext(), executor, /*logger=*/ null);
assertThat(b1).isSameInstanceAs(b2);
}
@Test
- public void testDatabaseName() {
+ public void testSearchContext_databaseName() {
+ LocalStorage.SearchContext searchContext =
+ new LocalStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ /*databaseName=*/"dbName").build();
+
+ assertThat(searchContext.getDatabaseName()).isEqualTo("dbName");
+ }
+
+ @Test
+ public void testSearchContext_withClientExecutor() {
+ Executor executor = Executors.newSingleThreadExecutor();
+ LocalStorage.SearchContext searchContext = new LocalStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ /*databaseName=*/"dbName")
+ .setWorkerExecutor(executor)
+ .build();
+
+ assertThat(searchContext.getWorkerExecutor()).isEqualTo(executor);
+ assertThat(searchContext.getDatabaseName()).isEqualTo("dbName");
+ }
+
+ @Test
+ public void testSearchContext_withDefaultExecutor() {
+ LocalStorage.SearchContext searchContext = new LocalStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ /*databaseName=*/"dbName")
+ .build();
+
+ assertThat(searchContext.getWorkerExecutor()).isNotNull();
+ assertThat(searchContext.getDatabaseName()).isEqualTo("dbName");
+ }
+
+ @Test
+ public void testSearchContext_withInvalidDatabaseName() {
// Test special character can present in database name. When a special character is banned
// in database name, add checker in SearchContext.Builder and reflect it in java doc.
- LocalStorage.SearchContext.Builder contextBuilder =
- new LocalStorage.SearchContext.Builder(
- ApplicationProvider.getApplicationContext());
IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
- () -> contextBuilder.setDatabaseName("testDatabaseNameEndWith/"));
+ () -> new LocalStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ "testDatabaseNameEndWith/").build());
assertThat(e).hasMessageThat().isEqualTo("Database name cannot contain '/'");
e = assertThrows(IllegalArgumentException.class,
- () -> contextBuilder.setDatabaseName("/testDatabaseNameStartWith"));
+ () -> new LocalStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ "/testDatabaseNameStartWith").build());
assertThat(e).hasMessageThat().isEqualTo("Database name cannot contain '/'");
}
}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/SearchResultsImplTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/SearchResultsImplTest.java
new file mode 100644
index 0000000..fc15702
--- /dev/null
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/SearchResultsImplTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.localstorage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.SearchSpec;
+
+import com.google.android.icing.proto.TermMatchType;
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executors;
+
+public class SearchResultsImplTest {
+ /**
+ * Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
+ */
+ private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private AppSearchImpl mAppSearchImpl;
+
+ @Before
+ public void setUp() throws Exception {
+ mAppSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+ }
+
+ @Test
+ public void testGetEmptyNextPage() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert one package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+
+ SearchResultsImpl searchResults = new SearchResultsImpl(
+ mAppSearchImpl,
+ Executors.newCachedThreadPool(),
+ "package1",
+ "database1",
+ "",
+ searchSpec,
+ /*logger=*/ null);
+
+ List<SearchResult> results = searchResults.getNextPage().get();
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).getGenericDocument()).isEqualTo(document1);
+
+ // We get all documents, and it shouldn't fail if we keep calling getNextPage().
+ results = searchResults.getNextPage().get();
+ assertThat(results).isEmpty();
+ }
+
+ @Test
+ public void testGetEmptyNextPage_multiPages() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // Insert 3 package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ GenericDocument document3 = new GenericDocument.Builder<>("namespace", "id3",
+ "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document3, /*logger=*/ null);
+
+ // Query for only 2 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(2)
+ .build();
+
+ SearchResultsImpl searchResults = new SearchResultsImpl(
+ mAppSearchImpl,
+ Executors.newCachedThreadPool(),
+ "package1",
+ "database1",
+ "",
+ searchSpec,
+ /*logger=*/ null);
+ List<GenericDocument> outDocs = new ArrayList<>();
+ List<SearchResult> results = searchResults.getNextPage().get();
+ assertThat(results).hasSize(2);
+ outDocs.add(results.get(0).getGenericDocument());
+ outDocs.add(results.get(1).getGenericDocument());
+
+ results = searchResults.getNextPage().get();
+ assertThat(results).hasSize(1);
+ outDocs.add(results.get(0).getGenericDocument());
+ assertThat(outDocs).containsExactly(document1, document2, document3);
+
+ // We get all documents, and it shouldn't fail if we keep calling getNextPage().
+ results = searchResults.getNextPage().get();
+ assertThat(results).isEmpty();
+ }
+}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/SearchSessionImplTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/SearchSessionImplTest.java
new file mode 100644
index 0000000..8e2e2bd
--- /dev/null
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/SearchSessionImplTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.Migrator;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.localstorage.stats.SchemaMigrationStats;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+// TODO(b/173532925): Move unit tests to cts tests when logger is available in framework.
+public class SearchSessionImplTest {
+ private static final String PACKAGE_NAME = "packageName";
+ private static final String DATABASE_NAME = "dbName";
+ private static final long DOCUMENT_CREATION_TIME = 12345L;
+ private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private AppSearchLoggerTest.TestLogger mAppSearchLogger;
+ private SearchSessionImpl mSearchSessionImpl;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+ LocalStorage.SearchContext searchContext =
+ new LocalStorage.SearchContext.Builder(context, DATABASE_NAME).build();
+ mAppSearchLogger = new AppSearchLoggerTest.TestLogger();
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+ mSearchSessionImpl = new SearchSessionImpl(appSearchImpl,
+ searchContext.mExecutor, PACKAGE_NAME, DATABASE_NAME, mAppSearchLogger);
+ }
+
+ @Test
+ public void testSetSchemaStats_withoutSchemaMigration() throws Exception {
+ AppSearchSchema appSearchSchema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+
+ mSearchSessionImpl.setSchema(
+ new SetSchemaRequest.Builder().addSchemas(appSearchSchema).build()).get();
+
+ assertThat(mAppSearchLogger.mSetSchemaStats).isNotNull();
+ assertThat(mAppSearchLogger.mSetSchemaStats.getPackageName()).isEqualTo(PACKAGE_NAME);
+ assertThat(mAppSearchLogger.mSetSchemaStats.getDatabase()).isEqualTo(DATABASE_NAME);
+ assertThat(mAppSearchLogger.mSetSchemaStats.getSchemaMigrationStats()).isNull();
+ assertThat(mAppSearchLogger.mSetSchemaStats.getNewTypeCount()).isEqualTo(1);
+ assertThat(mAppSearchLogger.mSetSchemaStats.getDeletedTypeCount()).isEqualTo(0);
+ assertThat(mAppSearchLogger.mSetSchemaStats.getIndexIncompatibleTypeChangeCount())
+ .isEqualTo(0);
+ assertThat(mAppSearchLogger.mSetSchemaStats.getBackwardsIncompatibleTypeChangeCount())
+ .isEqualTo(0);
+ assertThat(mAppSearchLogger.mSetSchemaStats.getCompatibleTypeChangeCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testSetSchemaStats_withSchemaMigration() throws Exception {
+ AppSearchSchema schema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("To")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ AppSearchSchema newSchema = new AppSearchSchema.Builder("testSchema")
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ GenericDocument doc = new GenericDocument.Builder<>("namespace", "id", "testSchema")
+ .setPropertyString("subject", "testPut example")
+ .setPropertyString("To", "testTo example")
+ .build();
+ Migrator migrator = new Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return currentVersion != finalVersion;
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onUpgrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ return new GenericDocument.Builder<>(document.getNamespace(), document.getId(),
+ document.getSchemaType())
+ .setPropertyString("subject", "testPut example migrated")
+ .setCreationTimestampMillis(DOCUMENT_CREATION_TIME)
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public GenericDocument onDowngrade(int currentVersion, int finalVersion,
+ @NonNull GenericDocument document) {
+ throw new IllegalStateException("Downgrade should not be triggered for this test");
+ }
+ };
+
+ mSearchSessionImpl.setSchema(new SetSchemaRequest.Builder().addSchemas(
+ schema).setForceOverride(true).build()).get();
+ mSearchSessionImpl.put(new PutDocumentsRequest.Builder().addGenericDocuments(doc).build());
+ mSearchSessionImpl.setSchema(new SetSchemaRequest.Builder().addSchemas(newSchema)
+ .setMigrator("testSchema", migrator)
+ .setVersion(2) // upgrade version
+ .build()).get();
+
+ assertThat(mAppSearchLogger.mSetSchemaStats).isNotNull();
+ assertThat(mAppSearchLogger.mSetSchemaStats.getSchemaMigrationStats()).isNotNull();
+ SchemaMigrationStats schemaMigrationStats =
+ mAppSearchLogger.mSetSchemaStats.getSchemaMigrationStats();
+ assertThat(schemaMigrationStats.getMigratedDocumentCount()).isEqualTo(1);
+ assertThat(schemaMigrationStats.getSavedDocumentCount()).isEqualTo(1);
+ }
+}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/VisibilityStoreTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/VisibilityStoreTest.java
deleted file mode 100644
index 4577f5a..0000000
--- a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/VisibilityStoreTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.localstorage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.util.Collections;
-
-public class VisibilityStoreTest {
-
- @Rule
- public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
- private AppSearchImpl mAppSearchImpl;
- private VisibilityStore mVisibilityStore;
-
- @Before
- public void setUp() throws Exception {
- mAppSearchImpl = AppSearchImpl.create(mTemporaryFolder.newFolder());
- mVisibilityStore = mAppSearchImpl.getVisibilityStoreLocked();
- }
-
- /**
- * Make sure that we don't conflict with any special characters that AppSearchImpl has
- * reserved.
- */
- @Test
- public void testValidPackageName() {
- assertThat(VisibilityStore.PACKAGE_NAME).doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
- assertThat(VisibilityStore.PACKAGE_NAME).doesNotContain(
- "" + AppSearchImpl.DATABASE_DELIMITER); // Convert the chars to CharSequences
- }
-
- /**
- * Make sure that we don't conflict with any special characters that AppSearchImpl has
- * reserved.
- */
- @Test
- public void testValidDatabaseName() {
- assertThat(VisibilityStore.DATABASE_NAME).doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
- assertThat(VisibilityStore.DATABASE_NAME).doesNotContain(
- "" + AppSearchImpl.DATABASE_DELIMITER); // Convert the chars to CharSequences
- }
-
- @Test
- public void testSetVisibility() throws Exception {
- mVisibilityStore.setVisibility("prefix",
- /*schemasNotPlatformSurfaceable=*/
- ImmutableSet.of("prefix/schema1", "prefix/schema2"));
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema1")).isFalse();
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema2")).isFalse();
-
- // New .setVisibility() call completely overrides previous visibility settings. So
- // "schema2" isn't preserved.
- mVisibilityStore.setVisibility("prefix",
- /*schemasNotPlatformSurfaceable=*/
- ImmutableSet.of("prefix/schema1", "prefix/schema3"));
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema1")).isFalse();
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema2")).isTrue();
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema3")).isFalse();
-
- mVisibilityStore.setVisibility(
- "prefix", /*schemasNotPlatformSurfaceable=*/ Collections.emptySet());
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema1")).isTrue();
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema2")).isTrue();
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema3")).isTrue();
- }
-
- @Test
- public void testEmptyPrefix() throws Exception {
- mVisibilityStore.setVisibility(/*prefix=*/ "",
- /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of("schema1", "schema2"));
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable(/*prefix=*/ "", "schema1")).isFalse();
- assertThat(
- mVisibilityStore.isSchemaPlatformSurfaceable(/*prefix=*/ "", "schema2")).isFalse();
- }
-}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverterTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverterTest.java
index 1245262..f22818d 100644
--- a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverterTest.java
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverterTest.java
@@ -21,8 +21,11 @@
import androidx.appsearch.app.GenericDocument;
import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.protobuf.ByteString;
+import com.google.common.collect.ImmutableMap;
import org.junit.Test;
@@ -30,29 +33,42 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class GenericDocumentToProtoConverterTest {
private static final byte[] BYTE_ARRAY_1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
private static final byte[] BYTE_ARRAY_2 = new byte[]{(byte) 4, (byte) 5, (byte) 6, (byte) 7};
+ private static final String SCHEMA_TYPE_1 = "sDocumentPropertiesSchemaType1";
+ private static final String SCHEMA_TYPE_2 = "sDocumentPropertiesSchemaType2";
private static final GenericDocument DOCUMENT_PROPERTIES_1 =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "sDocumentProperties1", "sDocumentPropertiesSchemaType1")
- .setCreationTimestampMillis(12345L)
- .build();
+ "namespace", "sDocumentProperties1", SCHEMA_TYPE_1)
+ .setCreationTimestampMillis(12345L)
+ .build();
private static final GenericDocument DOCUMENT_PROPERTIES_2 =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "sDocumentProperties2", "sDocumentPropertiesSchemaType2")
- .setCreationTimestampMillis(6789L)
+ "namespace", "sDocumentProperties2", SCHEMA_TYPE_2)
+ .setCreationTimestampMillis(6789L)
+ .build();
+ private static final SchemaTypeConfigProto SCHEMA_PROTO_1 = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(SCHEMA_TYPE_1)
.build();
+ private static final SchemaTypeConfigProto SCHEMA_PROTO_2 = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(SCHEMA_TYPE_2)
+ .build();
+ private static final String PREFIX = "package$databaseName/";
+ private static final Map<String, SchemaTypeConfigProto> SCHEMA_MAP =
+ ImmutableMap.of(PREFIX + SCHEMA_TYPE_1, SCHEMA_PROTO_1, PREFIX + SCHEMA_TYPE_2,
+ SCHEMA_PROTO_2);
@Test
public void testDocumentProtoConvert() {
GenericDocument document =
- new GenericDocument.Builder<GenericDocument.Builder<?>>("uri1", "schemaType1")
+ new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace", "id1",
+ SCHEMA_TYPE_1)
.setCreationTimestampMillis(5L)
.setScore(1)
.setTtlMillis(1L)
- .setNamespace("namespace")
.setPropertyLong("longKey1", 1L)
.setPropertyDouble("doubleKey1", 1.0)
.setPropertyBoolean("booleanKey1", true)
@@ -64,8 +80,8 @@
// Create the Document proto. Need to sort the property order by key.
DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder()
- .setUri("uri1")
- .setSchema("schemaType1")
+ .setUri("id1")
+ .setSchema(SCHEMA_TYPE_1)
.setCreationTimestampMs(5L)
.setScore(1)
.setTtlMs(1L)
@@ -95,9 +111,123 @@
documentProtoBuilder.addProperties(propertyProtoMap.get(key));
}
DocumentProto documentProto = documentProtoBuilder.build();
- assertThat(GenericDocumentToProtoConverter.toDocumentProto(document))
- .isEqualTo(documentProto);
- assertThat(document)
- .isEqualTo(GenericDocumentToProtoConverter.toGenericDocument(documentProto));
+
+ GenericDocument convertedGenericDocument =
+ GenericDocumentToProtoConverter.toGenericDocument(documentProto, PREFIX,
+ SCHEMA_MAP);
+ DocumentProto convertedDocumentProto =
+ GenericDocumentToProtoConverter.toDocumentProto(document);
+
+ assertThat(convertedDocumentProto).isEqualTo(documentProto);
+ assertThat(convertedGenericDocument).isEqualTo(document);
+ }
+
+ @Test
+ public void testConvertDocument_whenPropertyHasEmptyList() {
+ String emptyStringPropertyName = "emptyStringProperty";
+ DocumentProto documentProto = DocumentProto.newBuilder()
+ .setUri("id1")
+ .setSchema(SCHEMA_TYPE_1)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder()
+ .setName(emptyStringPropertyName)
+ .build()
+ ).build();
+
+ PropertyConfigProto emptyStringListProperty = PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setPropertyName(emptyStringPropertyName)
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto = SchemaTypeConfigProto.newBuilder()
+ .addProperties(emptyStringListProperty)
+ .setSchemaType(SCHEMA_TYPE_1)
+ .build();
+ Map<String, SchemaTypeConfigProto> schemaMap =
+ ImmutableMap.of(PREFIX + SCHEMA_TYPE_1, schemaTypeConfigProto);
+
+ GenericDocument convertedDocument = GenericDocumentToProtoConverter.toGenericDocument(
+ documentProto, PREFIX, schemaMap);
+
+ GenericDocument expectedDocument =
+ new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace", "id1",
+ SCHEMA_TYPE_1)
+ .setCreationTimestampMillis(5L)
+ .setPropertyString(emptyStringPropertyName)
+ .build();
+ assertThat(convertedDocument).isEqualTo(expectedDocument);
+ assertThat(expectedDocument.getPropertyStringArray(emptyStringPropertyName)).isEmpty();
+ }
+
+ @Test
+ public void testConvertDocument_whenNestedDocumentPropertyHasEmptyList() {
+ String emptyStringPropertyName = "emptyStringProperty";
+ String documentPropertyName = "documentProperty";
+ DocumentProto nestedDocumentProto = DocumentProto.newBuilder()
+ .setUri("id2")
+ .setSchema(SCHEMA_TYPE_2)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder()
+ .setName(emptyStringPropertyName)
+ .build()
+ ).build();
+ DocumentProto documentProto = DocumentProto.newBuilder()
+ .setUri("id1")
+ .setSchema(SCHEMA_TYPE_1)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder()
+ .addDocumentValues(nestedDocumentProto)
+ .setName(documentPropertyName)
+ .build()
+ ).build();
+
+ PropertyConfigProto documentProperty = PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setPropertyName(documentPropertyName)
+ .setSchemaType(SCHEMA_TYPE_2)
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto = SchemaTypeConfigProto.newBuilder()
+ .addProperties(documentProperty)
+ .setSchemaType(SCHEMA_TYPE_1)
+ .build();
+ PropertyConfigProto emptyStringListProperty = PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setPropertyName(emptyStringPropertyName)
+ .build();
+ SchemaTypeConfigProto nestedSchemaTypeConfigProto = SchemaTypeConfigProto.newBuilder()
+ .addProperties(emptyStringListProperty)
+ .setSchemaType(SCHEMA_TYPE_2)
+ .build();
+ Map<String, SchemaTypeConfigProto> schemaMap =
+ ImmutableMap.of(PREFIX + SCHEMA_TYPE_1, schemaTypeConfigProto,
+ PREFIX + SCHEMA_TYPE_2, nestedSchemaTypeConfigProto);
+
+ GenericDocument convertedDocument = GenericDocumentToProtoConverter.toGenericDocument(
+ documentProto, PREFIX, schemaMap);
+
+ GenericDocument expectedDocument =
+ new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace", "id1",
+ SCHEMA_TYPE_1)
+ .setCreationTimestampMillis(5L)
+ .setPropertyDocument(documentPropertyName,
+ new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace",
+ "id2", SCHEMA_TYPE_2)
+ .setCreationTimestampMillis(5L)
+ .setPropertyString(emptyStringPropertyName)
+ .build()
+ )
+ .build();
+ assertThat(convertedDocument).isEqualTo(expectedDocument);
+ assertThat(
+ expectedDocument.getPropertyDocument(documentPropertyName).getPropertyStringArray(
+ emptyStringPropertyName)).isEmpty();
}
}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverterTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverterTest.java
index 889b0c7..3f2cb70 100644
--- a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverterTest.java
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverterTest.java
@@ -31,22 +31,25 @@
@Test
public void testGetProto_Email() {
AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder("body")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.build()
).build();
SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
.setSchemaType("Email")
+ .setVersion(12345)
.addProperties(PropertyConfigProto.newBuilder()
.setPropertyName("subject")
.setDataType(PropertyConfigProto.DataType.Code.STRING)
@@ -69,7 +72,7 @@
)
).build();
- assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(emailSchema))
+ assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(emailSchema, /*version=*/12345))
.isEqualTo(expectedEmailProto);
assertThat(SchemaToProtoConverter.toAppSearchSchema(expectedEmailProto))
.isEqualTo(emailSchema);
@@ -78,22 +81,21 @@
@Test
public void testGetProto_MusicRecording() {
AppSearchSchema musicRecordingSchema = new AppSearchSchema.Builder("MusicRecording")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("artist")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("artist")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("pubDate")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder("pubDate")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.build()
).build();
SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
.setSchemaType("MusicRecording")
+ .setVersion(0)
.addProperties(PropertyConfigProto.newBuilder()
.setPropertyName("artist")
.setDataType(PropertyConfigProto.DataType.Code.STRING)
@@ -108,15 +110,10 @@
.setPropertyName("pubDate")
.setDataType(PropertyConfigProto.DataType.Code.INT64)
.setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setStringIndexingConfig(
- StringIndexingConfig.newBuilder()
- .setTokenizerType(
- StringIndexingConfig.TokenizerType.Code.NONE)
- .setTermMatchType(TermMatchType.Code.UNKNOWN)
- )
).build();
- assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(musicRecordingSchema))
+ assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(
+ musicRecordingSchema, /*version=*/0))
.isEqualTo(expectedMusicRecordingProto);
assertThat(SchemaToProtoConverter.toAppSearchSchema(expectedMusicRecordingProto))
.isEqualTo(musicRecordingSchema);
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SnippetTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SnippetTest.java
index 31bc328..c28e5af 100644
--- a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SnippetTest.java
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SnippetTest.java
@@ -20,9 +20,11 @@
import androidx.appsearch.app.SearchResult;
import androidx.appsearch.app.SearchResultPage;
+import androidx.appsearch.localstorage.util.PrefixUtil;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SnippetMatchProto;
import com.google.android.icing.proto.SnippetProto;
@@ -30,189 +32,250 @@
import org.junit.Test;
import java.util.Collections;
+import java.util.Map;
public class SnippetTest {
+ private static final String SCHEMA_TYPE = "schema1";
+ private static final String PACKAGE_NAME = "packageName";
+ private static final String DATABASE_NAME = "databaseName";
+ private static final String PREFIX = PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
+ private static final SchemaTypeConfigProto SCHEMA_TYPE_CONFIG_PROTO =
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(PREFIX + SCHEMA_TYPE)
+ .build();
+ private static final Map<String, Map<String, SchemaTypeConfigProto>> SCHEMA_MAP =
+ Collections.singletonMap(PREFIX,
+ Collections.singletonMap(PREFIX + SCHEMA_TYPE,
+ SCHEMA_TYPE_CONFIG_PROTO));
- // TODO(tytytyww): Add tests for Double and Long Snippets.
@Test
public void testSingleStringSnippet() {
-
final String propertyKeyString = "content";
final String propertyValueString = "A commonly used fake word is foo.\n"
+ " Another nonsense word that’s used a lot\n"
+ " is bar.\n";
- final String uri = "uri1";
- final String schemaType = "schema1";
- final String searchWord = "foo";
+ final String id = "id1";
final String exactMatch = "foo";
final String window = "is foo";
// Building the SearchResult received from query.
- PropertyProto property = PropertyProto.newBuilder()
- .setName(propertyKeyString)
- .addStringValues(propertyValueString)
- .build();
DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri(uri)
- .setSchema(schemaType)
- .addProperties(property)
+ .setUri(id)
+ .setSchema(SCHEMA_TYPE)
+ .addProperties(PropertyProto.newBuilder()
+ .setName(propertyKeyString)
+ .addStringValues(propertyValueString))
.build();
SnippetProto snippetProto = SnippetProto.newBuilder()
.addEntries(SnippetProto.EntryProto.newBuilder()
.setPropertyName(propertyKeyString)
.addSnippetMatches(SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
- .setExactMatchPosition(29)
- .setExactMatchBytes(3)
- .setWindowPosition(26)
- .setWindowBytes(6)
- .build())
- .build())
- .build();
- SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
- .setDocument(documentProto)
- .setSnippet(snippetProto)
+ .setExactMatchBytePosition(29)
+ .setExactMatchByteLength(3)
+ .setExactMatchUtf16Position(29)
+ .setExactMatchUtf16Length(3)
+ .setWindowBytePosition(26)
+ .setWindowByteLength(6)
+ .setWindowUtf16Position(26)
+ .setWindowUtf16Length(6)))
.build();
SearchResultProto searchResultProto = SearchResultProto.newBuilder()
- .addResults(resultProto)
+ .addResults(SearchResultProto.ResultProto.newBuilder()
+ .setDocument(documentProto)
+ .setSnippet(snippetProto))
.build();
// Making ResultReader and getting Snippet values.
- SearchResultPage searchResultPage =
- SearchResultToProtoConverter.toSearchResultPage(searchResultProto,
- Collections.singletonList("packageName"));
- for (SearchResult result : searchResultPage.getResults()) {
- SearchResult.MatchInfo match = result.getMatches().get(0);
- assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
- assertThat(match.getFullText()).isEqualTo(propertyValueString);
- assertThat(match.getExactMatch()).isEqualTo(exactMatch);
- assertThat(match.getExactMatchPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/29, /*upper=*/32));
- assertThat(match.getFullText()).isEqualTo(propertyValueString);
- assertThat(match.getSnippetPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/26, /*upper=*/32));
- assertThat(match.getSnippet()).isEqualTo(window);
- }
+ SearchResultPage searchResultPage = SearchResultToProtoConverter.toSearchResultPage(
+ searchResultProto,
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ SearchResult.MatchInfo match = searchResultPage.getResults().get(0).getMatchInfos().get(0);
+ assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
+ assertThat(match.getFullText()).isEqualTo(propertyValueString);
+ assertThat(match.getExactMatch()).isEqualTo(exactMatch);
+ assertThat(match.getExactMatchRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/29, /*upper=*/32));
+ assertThat(match.getFullText()).isEqualTo(propertyValueString);
+ assertThat(match.getSnippetRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/26, /*upper=*/32));
+ assertThat(match.getSnippet()).isEqualTo(window);
}
- // TODO(tytytyww): Add tests for Double and Long Snippets.
@Test
- public void testNoSnippets() throws Exception {
-
+ public void testNoSnippets() {
final String propertyKeyString = "content";
final String propertyValueString = "A commonly used fake word is foo.\n"
+ " Another nonsense word that’s used a lot\n"
+ " is bar.\n";
- final String uri = "uri1";
- final String schemaType = "schema1";
- final String searchWord = "foo";
- final String exactMatch = "foo";
- final String window = "is foo";
+ final String id = "id1";
// Building the SearchResult received from query.
- PropertyProto property = PropertyProto.newBuilder()
- .setName(propertyKeyString)
- .addStringValues(propertyValueString)
- .build();
DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri(uri)
- .setSchema(schemaType)
- .addProperties(property)
- .build();
- SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
- .setDocument(documentProto)
+ .setUri(id)
+ .setSchema(SCHEMA_TYPE)
+ .addProperties(PropertyProto.newBuilder()
+ .setName(propertyKeyString)
+ .addStringValues(propertyValueString))
.build();
SearchResultProto searchResultProto = SearchResultProto.newBuilder()
- .addResults(resultProto)
+ .addResults(SearchResultProto.ResultProto.newBuilder().setDocument(documentProto))
.build();
- SearchResultPage searchResultPage =
- SearchResultToProtoConverter.toSearchResultPage(searchResultProto,
- Collections.singletonList("packageName"));
- for (SearchResult result : searchResultPage.getResults()) {
- assertThat(result.getMatches()).isEmpty();
- }
+ SearchResultPage searchResultPage = SearchResultToProtoConverter.toSearchResultPage(
+ searchResultProto,
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getMatchInfos()).isEmpty();
}
@Test
- public void testMultipleStringSnippet() throws Exception {
- final String searchWord = "Test";
-
+ public void testMultipleStringSnippet() {
// Building the SearchResult received from query.
- PropertyProto property1 = PropertyProto.newBuilder()
- .setName("sender.name")
- .addStringValues("Test Name Jr.")
- .build();
- PropertyProto property2 = PropertyProto.newBuilder()
- .setName("sender.email")
- .addStringValues("TestNameJr@gmail.com")
- .build();
DocumentProto documentProto = DocumentProto.newBuilder()
.setUri("uri1")
- .setSchema("schema1")
- .addProperties(property1)
- .addProperties(property2)
+ .setSchema(SCHEMA_TYPE)
+ .addProperties(PropertyProto.newBuilder()
+ .setName("senderName")
+ .addStringValues("Test Name Jr."))
+ .addProperties(PropertyProto.newBuilder()
+ .setName("senderEmail")
+ .addStringValues("TestNameJr@gmail.com"))
.build();
SnippetProto snippetProto = SnippetProto.newBuilder()
- .addEntries(
- SnippetProto.EntryProto.newBuilder()
- .setPropertyName("sender.name")
- .addSnippetMatches(
- SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
- .setExactMatchPosition(0)
- .setExactMatchBytes(4)
- .setWindowPosition(0)
- .setWindowBytes(9)
- .build())
- .build())
- .addEntries(
- SnippetProto.EntryProto.newBuilder()
- .setPropertyName("sender.email")
- .addSnippetMatches(
- SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
- .setExactMatchPosition(0)
- .setExactMatchBytes(20)
- .setWindowPosition(0)
- .setWindowBytes(20)
- .build())
- .build()
- )
- .build();
- SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
- .setDocument(documentProto)
- .setSnippet(snippetProto)
+ .addEntries(SnippetProto.EntryProto.newBuilder()
+ .setPropertyName("senderName")
+ .addSnippetMatches(SnippetMatchProto.newBuilder()
+ .setExactMatchBytePosition(0)
+ .setExactMatchByteLength(4)
+ .setExactMatchUtf16Position(0)
+ .setExactMatchUtf16Length(4)
+ .setWindowBytePosition(0)
+ .setWindowByteLength(9)
+ .setWindowUtf16Position(0)
+ .setWindowUtf16Length(9)))
+ .addEntries(SnippetProto.EntryProto.newBuilder()
+ .setPropertyName("senderEmail")
+ .addSnippetMatches(SnippetMatchProto.newBuilder()
+ .setExactMatchBytePosition(0)
+ .setExactMatchByteLength(20)
+ .setExactMatchUtf16Position(0)
+ .setExactMatchUtf16Length(20)
+ .setWindowBytePosition(0)
+ .setWindowByteLength(20)
+ .setWindowUtf16Position(0)
+ .setWindowUtf16Length(20)))
.build();
SearchResultProto searchResultProto = SearchResultProto.newBuilder()
- .addResults(resultProto)
+ .addResults(SearchResultProto.ResultProto.newBuilder()
+ .setDocument(documentProto)
+ .setSnippet(snippetProto))
.build();
// Making ResultReader and getting Snippet values.
- SearchResultPage searchResultPage =
- SearchResultToProtoConverter.toSearchResultPage(searchResultProto,
- Collections.singletonList("packageName"));
- for (SearchResult result : searchResultPage.getResults()) {
+ SearchResultPage searchResultPage = SearchResultToProtoConverter.toSearchResultPage(
+ searchResultProto,
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ SearchResult.MatchInfo match1 = searchResultPage.getResults().get(0).getMatchInfos().get(0);
+ assertThat(match1.getPropertyPath()).isEqualTo("senderName");
+ assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
+ assertThat(match1.getExactMatchRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/4));
+ assertThat(match1.getExactMatch()).isEqualTo("Test");
+ assertThat(match1.getSnippetRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/9));
+ assertThat(match1.getSnippet()).isEqualTo("Test Name");
- SearchResult.MatchInfo match1 = result.getMatches().get(0);
- assertThat(match1.getPropertyPath()).isEqualTo("sender.name");
- assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
- assertThat(match1.getExactMatchPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/0, /*upper=*/4));
- assertThat(match1.getExactMatch()).isEqualTo("Test");
- assertThat(match1.getSnippetPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/0, /*upper=*/9));
- assertThat(match1.getSnippet()).isEqualTo("Test Name");
+ SearchResult.MatchInfo match2 = searchResultPage.getResults().get(0).getMatchInfos().get(1);
+ assertThat(match2.getPropertyPath()).isEqualTo("senderEmail");
+ assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com");
+ assertThat(match2.getExactMatchRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/20));
+ assertThat(match2.getExactMatch()).isEqualTo("TestNameJr@gmail.com");
+ assertThat(match2.getSnippetRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/20));
+ assertThat(match2.getSnippet()).isEqualTo("TestNameJr@gmail.com");
+ }
- SearchResult.MatchInfo match2 = result.getMatches().get(1);
- assertThat(match2.getPropertyPath()).isEqualTo("sender.email");
- assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com");
- assertThat(match2.getExactMatchPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/0, /*upper=*/20));
- assertThat(match2.getExactMatch()).isEqualTo("TestNameJr@gmail.com");
- assertThat(match2.getSnippetPosition()).isEqualTo(
- new SearchResult.MatchRange(/*lower=*/0, /*upper=*/20));
- assertThat(match2.getSnippet()).isEqualTo("TestNameJr@gmail.com");
- }
+ @Test
+ public void testNestedDocumentSnippet() {
+ // Building the SearchResult received from query.
+ DocumentProto documentProto = DocumentProto.newBuilder()
+ .setUri("id1")
+ .setSchema(SCHEMA_TYPE)
+ .addProperties(PropertyProto.newBuilder()
+ .setName("sender")
+ .addDocumentValues(DocumentProto.newBuilder()
+ .addProperties(PropertyProto.newBuilder()
+ .setName("name")
+ .addStringValues("Test Name Jr."))
+ .addProperties(PropertyProto.newBuilder()
+ .setName("email")
+ .addStringValues("TestNameJr@gmail.com")
+ .addStringValues("TestNameJr2@gmail.com"))))
+ .build();
+ SnippetProto snippetProto = SnippetProto.newBuilder()
+ .addEntries(SnippetProto.EntryProto.newBuilder()
+ .setPropertyName("sender.name")
+ .addSnippetMatches(SnippetMatchProto.newBuilder()
+ .setExactMatchBytePosition(0)
+ .setExactMatchByteLength(4)
+ .setExactMatchUtf16Position(0)
+ .setExactMatchUtf16Length(4)
+ .setWindowBytePosition(0)
+ .setWindowByteLength(9)
+ .setWindowUtf16Position(0)
+ .setWindowUtf16Length(9)))
+ .addEntries(SnippetProto.EntryProto.newBuilder()
+ .setPropertyName("sender.email[1]")
+ .addSnippetMatches(SnippetMatchProto.newBuilder()
+ .setExactMatchBytePosition(0)
+ .setExactMatchByteLength(21)
+ .setExactMatchUtf16Position(0)
+ .setExactMatchUtf16Length(21)
+ .setWindowBytePosition(0)
+ .setWindowByteLength(21)
+ .setWindowUtf16Position(0)
+ .setWindowUtf16Length(21)))
+ .build();
+ SearchResultProto searchResultProto = SearchResultProto.newBuilder()
+ .addResults(SearchResultProto.ResultProto.newBuilder()
+ .setDocument(documentProto)
+ .setSnippet(snippetProto))
+ .build();
+
+ // Making ResultReader and getting Snippet values.
+ SearchResultPage searchResultPage = SearchResultToProtoConverter.toSearchResultPage(
+ searchResultProto,
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ SearchResult.MatchInfo match1 = searchResultPage.getResults().get(0).getMatchInfos().get(0);
+ assertThat(match1.getPropertyPath()).isEqualTo("sender.name");
+ assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
+ assertThat(match1.getExactMatchRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/4));
+ assertThat(match1.getExactMatch()).isEqualTo("Test");
+ assertThat(match1.getSnippetRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/9));
+ assertThat(match1.getSnippet()).isEqualTo("Test Name");
+
+ SearchResult.MatchInfo match2 = searchResultPage.getResults().get(0).getMatchInfos().get(1);
+ assertThat(match2.getPropertyPath()).isEqualTo("sender.email[1]");
+ assertThat(match2.getFullText()).isEqualTo("TestNameJr2@gmail.com");
+ assertThat(match2.getExactMatchRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/21));
+ assertThat(match2.getExactMatch()).isEqualTo("TestNameJr2@gmail.com");
+ assertThat(match2.getSnippetRange()).isEqualTo(
+ new SearchResult.MatchRange(/*lower=*/0, /*upper=*/21));
+ assertThat(match2.getSnippet()).isEqualTo("TestNameJr2@gmail.com");
}
}
diff --git a/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/stats/AppSearchStatsTest.java b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/stats/AppSearchStatsTest.java
new file mode 100644
index 0000000..3d23c0a
--- /dev/null
+++ b/appsearch/local-storage/src/androidTest/java/androidx/appsearch/localstorage/stats/AppSearchStatsTest.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.AppSearchResult;
+
+import org.junit.Test;
+
+public class AppSearchStatsTest {
+ static final String TEST_PACKAGE_NAME = "com.google.test";
+ static final String TEST_DATA_BASE = "testDataBase";
+ static final int TEST_STATUS_CODE = AppSearchResult.RESULT_INTERNAL_ERROR;
+ static final int TEST_TOTAL_LATENCY_MILLIS = 20;
+
+ @Test
+ public void testAppSearchStats_CallStats() {
+ final int estimatedBinderLatencyMillis = 1;
+ final int numOperationsSucceeded = 2;
+ final int numOperationsFailed = 3;
+ final @CallStats.CallType int callType =
+ CallStats.CALL_TYPE_PUT_DOCUMENTS;
+
+ final CallStats cStats = new CallStats.Builder()
+ .setPackageName(TEST_PACKAGE_NAME)
+ .setDatabase(TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setCallType(callType)
+ .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
+ .setNumOperationsSucceeded(numOperationsSucceeded)
+ .setNumOperationsFailed(numOperationsFailed)
+ .build();
+
+ assertThat(cStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(cStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(cStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(cStats.getTotalLatencyMillis()).isEqualTo(
+ TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(cStats.getEstimatedBinderLatencyMillis())
+ .isEqualTo(estimatedBinderLatencyMillis);
+ assertThat(cStats.getCallType()).isEqualTo(callType);
+ assertThat(cStats.getNumOperationsSucceeded()).isEqualTo(numOperationsSucceeded);
+ assertThat(cStats.getNumOperationsFailed()).isEqualTo(numOperationsFailed);
+ }
+
+ @Test
+ public void testAppSearchCallStats_nullValues() {
+ final @CallStats.CallType int callType =
+ CallStats.CALL_TYPE_PUT_DOCUMENTS;
+
+ final CallStats.Builder cStatsBuilder = new CallStats.Builder()
+ .setCallType(callType);
+
+ final CallStats cStats = cStatsBuilder.build();
+
+ assertThat(cStats.getPackageName()).isNull();
+ assertThat(cStats.getDatabase()).isNull();
+ assertThat(cStats.getCallType()).isEqualTo(callType);
+ }
+
+ @Test
+ public void testAppSearchStats_PutDocumentStats() {
+ final int generateDocumentProtoLatencyMillis = 1;
+ final int rewriteDocumentTypesLatencyMillis = 2;
+ final int nativeLatencyMillis = 3;
+ final int nativeDocumentStoreLatencyMillis = 4;
+ final int nativeIndexLatencyMillis = 5;
+ final int nativeIndexMergeLatencyMillis = 6;
+ final int nativeDocumentSize = 7;
+ final int nativeNumTokensIndexed = 8;
+ final boolean nativeExceededMaxNumTokens = true;
+ final PutDocumentStats.Builder pStatsBuilder =
+ new PutDocumentStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setGenerateDocumentProtoLatencyMillis(generateDocumentProtoLatencyMillis)
+ .setRewriteDocumentTypesLatencyMillis(rewriteDocumentTypesLatencyMillis)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setNativeDocumentStoreLatencyMillis(nativeDocumentStoreLatencyMillis)
+ .setNativeIndexLatencyMillis(nativeIndexLatencyMillis)
+ .setNativeIndexMergeLatencyMillis(nativeIndexMergeLatencyMillis)
+ .setNativeDocumentSizeBytes(nativeDocumentSize)
+ .setNativeNumTokensIndexed(nativeNumTokensIndexed)
+ .setNativeExceededMaxNumTokens(nativeExceededMaxNumTokens);
+
+ final PutDocumentStats pStats = pStatsBuilder.build();
+
+ assertThat(pStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(pStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(pStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(pStats.getTotalLatencyMillis()).isEqualTo(
+ TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(pStats.getGenerateDocumentProtoLatencyMillis()).isEqualTo(
+ generateDocumentProtoLatencyMillis);
+ assertThat(pStats.getRewriteDocumentTypesLatencyMillis()).isEqualTo(
+ rewriteDocumentTypesLatencyMillis);
+ assertThat(pStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(pStats.getNativeDocumentStoreLatencyMillis()).isEqualTo(
+ nativeDocumentStoreLatencyMillis);
+ assertThat(pStats.getNativeIndexLatencyMillis()).isEqualTo(nativeIndexLatencyMillis);
+ assertThat(pStats.getNativeIndexMergeLatencyMillis()).isEqualTo(
+ nativeIndexMergeLatencyMillis);
+ assertThat(pStats.getNativeDocumentSizeBytes()).isEqualTo(nativeDocumentSize);
+ assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed);
+ assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens);
+ }
+
+ @Test
+ public void testAppSearchStats_InitializeStats() {
+ int prepareSchemaAndNamespacesLatencyMillis = 1;
+ int prepareVisibilityFileLatencyMillis = 2;
+ int nativeLatencyMillis = 3;
+ int nativeDocumentStoreRecoveryCause = 4;
+ int nativeIndexRestorationCause = 5;
+ int nativeSchemaStoreRecoveryCause = 6;
+ int nativeDocumentStoreRecoveryLatencyMillis = 7;
+ int nativeIndexRestorationLatencyMillis = 8;
+ int nativeSchemaStoreRecoveryLatencyMillis = 9;
+ int nativeDocumentStoreDataStatus = 10;
+ int nativeNumDocuments = 11;
+ int nativeNumSchemaTypes = 12;
+
+ final InitializeStats.Builder iStatsBuilder = new InitializeStats.Builder()
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setHasDeSync(/* hasDeSyncs= */ true)
+ .setPrepareSchemaAndNamespacesLatencyMillis(prepareSchemaAndNamespacesLatencyMillis)
+ .setPrepareVisibilityStoreLatencyMillis(prepareVisibilityFileLatencyMillis)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setDocumentStoreRecoveryCause(nativeDocumentStoreRecoveryCause)
+ .setIndexRestorationCause(nativeIndexRestorationCause)
+ .setSchemaStoreRecoveryCause(nativeSchemaStoreRecoveryCause)
+ .setDocumentStoreRecoveryLatencyMillis(
+ nativeDocumentStoreRecoveryLatencyMillis)
+ .setIndexRestorationLatencyMillis(nativeIndexRestorationLatencyMillis)
+ .setSchemaStoreRecoveryLatencyMillis(nativeSchemaStoreRecoveryLatencyMillis)
+ .setDocumentStoreDataStatus(nativeDocumentStoreDataStatus)
+ .setDocumentCount(nativeNumDocuments)
+ .setSchemaTypeCount(nativeNumSchemaTypes)
+ .setHasReset(true)
+ .setResetStatusCode(AppSearchResult.RESULT_INVALID_SCHEMA);
+ final InitializeStats iStats = iStatsBuilder.build();
+
+
+ assertThat(iStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(iStats.getTotalLatencyMillis()).isEqualTo(
+ TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(iStats.hasDeSync()).isTrue();
+ assertThat(iStats.getPrepareSchemaAndNamespacesLatencyMillis()).isEqualTo(
+ prepareSchemaAndNamespacesLatencyMillis);
+ assertThat(iStats.getPrepareVisibilityStoreLatencyMillis()).isEqualTo(
+ prepareVisibilityFileLatencyMillis);
+ assertThat(iStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(iStats.getDocumentStoreRecoveryCause()).isEqualTo(
+ nativeDocumentStoreRecoveryCause);
+ assertThat(iStats.getIndexRestorationCause()).isEqualTo(nativeIndexRestorationCause);
+ assertThat(iStats.getSchemaStoreRecoveryCause()).isEqualTo(
+ nativeSchemaStoreRecoveryCause);
+ assertThat(iStats.getDocumentStoreRecoveryLatencyMillis()).isEqualTo(
+ nativeDocumentStoreRecoveryLatencyMillis);
+ assertThat(iStats.getIndexRestorationLatencyMillis()).isEqualTo(
+ nativeIndexRestorationLatencyMillis);
+ assertThat(iStats.getSchemaStoreRecoveryLatencyMillis()).isEqualTo(
+ nativeSchemaStoreRecoveryLatencyMillis);
+ assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(
+ nativeDocumentStoreDataStatus);
+ assertThat(iStats.getDocumentCount()).isEqualTo(nativeNumDocuments);
+ assertThat(iStats.getSchemaTypeCount()).isEqualTo(nativeNumSchemaTypes);
+ assertThat(iStats.hasReset()).isTrue();
+ assertThat(iStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_INVALID_SCHEMA);
+ }
+
+ @Test
+ public void testAppSearchStats_SearchStats() {
+ int rewriteSearchSpecLatencyMillis = 1;
+ int rewriteSearchResultLatencyMillis = 2;
+ int visibilityScope = SearchStats.VISIBILITY_SCOPE_LOCAL;
+ int nativeLatencyMillis = 4;
+ int nativeNumTerms = 5;
+ int nativeQueryLength = 6;
+ int nativeNumNamespacesFiltered = 7;
+ int nativeNumSchemaTypesFiltered = 8;
+ int nativeRequestedPageSize = 9;
+ int nativeNumResultsReturnedCurrentPage = 10;
+ boolean nativeIsFirstPage = true;
+ int nativeParseQueryLatencyMillis = 11;
+ int nativeRankingStrategy = 12;
+ int nativeNumDocumentsScored = 13;
+ int nativeScoringLatencyMillis = 14;
+ int nativeRankingLatencyMillis = 15;
+ int nativeNumResultsSnippeted = 16;
+ int nativeDocumentRetrievingLatencyMillis = 17;
+ final SearchStats.Builder sStatsBuilder = new SearchStats.Builder(visibilityScope,
+ TEST_PACKAGE_NAME)
+ .setDatabase(TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setRewriteSearchSpecLatencyMillis(rewriteSearchSpecLatencyMillis)
+ .setRewriteSearchResultLatencyMillis(rewriteSearchResultLatencyMillis)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setTermCount(nativeNumTerms)
+ .setQueryLength(nativeQueryLength)
+ .setFilteredNamespaceCount(nativeNumNamespacesFiltered)
+ .setFilteredSchemaTypeCount(nativeNumSchemaTypesFiltered)
+ .setRequestedPageSize(nativeRequestedPageSize)
+ .setCurrentPageReturnedResultCount(nativeNumResultsReturnedCurrentPage)
+ .setIsFirstPage(nativeIsFirstPage)
+ .setParseQueryLatencyMillis(nativeParseQueryLatencyMillis)
+ .setRankingStrategy(nativeRankingStrategy)
+ .setScoredDocumentCount(nativeNumDocumentsScored)
+ .setScoringLatencyMillis(nativeScoringLatencyMillis)
+ .setRankingLatencyMillis(nativeRankingLatencyMillis)
+ .setResultWithSnippetsCount(nativeNumResultsSnippeted)
+ .setDocumentRetrievingLatencyMillis(nativeDocumentRetrievingLatencyMillis);
+ final SearchStats sStats = sStatsBuilder.build();
+
+ assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(sStats.getTotalLatencyMillis()).isEqualTo(
+ TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(sStats.getRewriteSearchSpecLatencyMillis()).isEqualTo(
+ rewriteSearchSpecLatencyMillis);
+ assertThat(sStats.getRewriteSearchResultLatencyMillis()).isEqualTo(
+ rewriteSearchResultLatencyMillis);
+ assertThat(sStats.getVisibilityScope()).isEqualTo(visibilityScope);
+ assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(sStats.getTermCount()).isEqualTo(nativeNumTerms);
+ assertThat(sStats.getQueryLength()).isEqualTo(nativeQueryLength);
+ assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(nativeNumNamespacesFiltered);
+ assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(
+ nativeNumSchemaTypesFiltered);
+ assertThat(sStats.getRequestedPageSize()).isEqualTo(nativeRequestedPageSize);
+ assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(
+ nativeNumResultsReturnedCurrentPage);
+ assertThat(sStats.isFirstPage()).isTrue();
+ assertThat(sStats.getParseQueryLatencyMillis()).isEqualTo(
+ nativeParseQueryLatencyMillis);
+ assertThat(sStats.getRankingStrategy()).isEqualTo(nativeRankingStrategy);
+ assertThat(sStats.getScoredDocumentCount()).isEqualTo(nativeNumDocumentsScored);
+ assertThat(sStats.getScoringLatencyMillis()).isEqualTo(nativeScoringLatencyMillis);
+ assertThat(sStats.getRankingLatencyMillis()).isEqualTo(nativeRankingLatencyMillis);
+ assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(nativeNumResultsSnippeted);
+ assertThat(sStats.getDocumentRetrievingLatencyMillis()).isEqualTo(
+ nativeDocumentRetrievingLatencyMillis);
+ }
+
+ @Test
+ public void testAppSearchStats_SetSchemaStats() {
+ SchemaMigrationStats schemaMigrationStats = new SchemaMigrationStats.Builder()
+ .setGetSchemaLatencyMillis(1)
+ .setQueryAndTransformLatencyMillis(2)
+ .setFirstSetSchemaLatencyMillis(3)
+ .setSecondSetSchemaLatencyMillis(4)
+ .setSaveDocumentLatencyMillis(5)
+ .setMigratedDocumentCount(6)
+ .setSavedDocumentCount(7)
+ .build();
+ int newTypeCount = 1;
+ int compatibleTypeChangeCount = 2;
+ int indexIncompatibleTypeChangeCount = 3;
+ int backwardsIncompatibleTypeChangeCount = 4;
+ SetSchemaStats sStats = new SetSchemaStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setSchemaMigrationStats(schemaMigrationStats)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setNewTypeCount(newTypeCount)
+ .setCompatibleTypeChangeCount(compatibleTypeChangeCount)
+ .setIndexIncompatibleTypeChangeCount(indexIncompatibleTypeChangeCount)
+ .setBackwardsIncompatibleTypeChangeCount(backwardsIncompatibleTypeChangeCount)
+ .build();
+
+ assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(sStats.getSchemaMigrationStats()).isEqualTo(schemaMigrationStats);
+ assertThat(sStats.getTotalLatencyMillis()).isEqualTo(
+ TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(sStats.getNewTypeCount()).isEqualTo(newTypeCount);
+ assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypeChangeCount);
+ assertThat(sStats.getIndexIncompatibleTypeChangeCount()).isEqualTo(
+ indexIncompatibleTypeChangeCount);
+ assertThat(sStats.getBackwardsIncompatibleTypeChangeCount()).isEqualTo(
+ backwardsIncompatibleTypeChangeCount);
+ }
+
+ @Test
+ public void testAppSearchStats_SchemaMigrationStats() {
+ int getSchemaLatency = 1;
+ int queryAndTransformLatency = 2;
+ int firstSetSchemaLatency = 3;
+ int secondSetSchemaLatency = 4;
+ int saveDocumentLatency = 5;
+ int migratedDocumentCount = 6;
+ int savedDocumentCount = 7;
+ SchemaMigrationStats sStats = new SchemaMigrationStats.Builder()
+ .setGetSchemaLatencyMillis(getSchemaLatency)
+ .setQueryAndTransformLatencyMillis(queryAndTransformLatency)
+ .setFirstSetSchemaLatencyMillis(firstSetSchemaLatency)
+ .setSecondSetSchemaLatencyMillis(secondSetSchemaLatency)
+ .setSaveDocumentLatencyMillis(saveDocumentLatency)
+ .setMigratedDocumentCount(migratedDocumentCount)
+ .setSavedDocumentCount(savedDocumentCount)
+ .build();
+
+ assertThat(sStats.getGetSchemaLatencyMillis()).isEqualTo(getSchemaLatency);
+ assertThat(sStats.getQueryAndTransformLatencyMillis()).isEqualTo(queryAndTransformLatency);
+ assertThat(sStats.getFirstSetSchemaLatencyMillis()).isEqualTo(firstSetSchemaLatency);
+ assertThat(sStats.getSecondSetSchemaLatencyMillis()).isEqualTo(secondSetSchemaLatency);
+ assertThat(sStats.getSaveDocumentLatencyMillis()).isEqualTo(saveDocumentLatency);
+ assertThat(sStats.getMigratedDocumentCount()).isEqualTo(migratedDocumentCount);
+ assertThat(sStats.getSavedDocumentCount()).isEqualTo(
+ savedDocumentCount);
+ }
+
+ @Test
+ public void testAppSearchStats_RemoveStats() {
+ int nativeLatencyMillis = 1;
+ @RemoveStats.DeleteType int deleteType = 2;
+ int documentDeletedCount = 3;
+
+ final RemoveStats rStats = new RemoveStats.Builder(TEST_PACKAGE_NAME,
+ TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setDeleteType(deleteType)
+ .setDeletedDocumentCount(documentDeletedCount)
+ .build();
+
+
+ assertThat(rStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(rStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(rStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(rStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(rStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(rStats.getDeleteType()).isEqualTo(deleteType);
+ assertThat(rStats.getDeletedDocumentCount()).isEqualTo(documentDeletedCount);
+ }
+
+ @Test
+ public void testAppSearchStats_OptimizeStats() {
+ int nativeLatencyMillis = 1;
+ int nativeDocumentStoreOptimizeLatencyMillis = 2;
+ int nativeIndexRestorationLatencyMillis = 3;
+ int nativeNumOriginalDocuments = 4;
+ int nativeNumDeletedDocuments = 5;
+ int nativeNumExpiredDocuments = 6;
+ long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1;
+ long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2;
+ long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3;
+
+ final OptimizeStats oStats = new OptimizeStats.Builder()
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setDocumentStoreOptimizeLatencyMillis(nativeDocumentStoreOptimizeLatencyMillis)
+ .setIndexRestorationLatencyMillis(nativeIndexRestorationLatencyMillis)
+ .setOriginalDocumentCount(nativeNumOriginalDocuments)
+ .setDeletedDocumentCount(nativeNumDeletedDocuments)
+ .setExpiredDocumentCount(nativeNumExpiredDocuments)
+ .setStorageSizeBeforeBytes(nativeStorageSizeBeforeBytes)
+ .setStorageSizeAfterBytes(nativeStorageSizeAfterBytes)
+ .setTimeSinceLastOptimizeMillis(nativeTimeSinceLastOptimizeMillis)
+ .build();
+
+ assertThat(oStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(oStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getDocumentStoreOptimizeLatencyMillis()).isEqualTo(
+ nativeDocumentStoreOptimizeLatencyMillis);
+ assertThat(oStats.getIndexRestorationLatencyMillis()).isEqualTo(
+ nativeIndexRestorationLatencyMillis);
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments);
+ assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments);
+ assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes);
+ assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes);
+ assertThat(oStats.getTimeSinceLastOptimizeMillis()).isEqualTo(
+ nativeTimeSinceLastOptimizeMillis);
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
index e97d137..4ed3f7c 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
@@ -16,31 +16,60 @@
package androidx.appsearch.localstorage;
+import static androidx.appsearch.localstorage.util.PrefixUtil.addPrefixToDocument;
+import static androidx.appsearch.localstorage.util.PrefixUtil.createPrefix;
+import static androidx.appsearch.localstorage.util.PrefixUtil.getDatabaseName;
+import static androidx.appsearch.localstorage.util.PrefixUtil.getPackageName;
+import static androidx.appsearch.localstorage.util.PrefixUtil.getPrefix;
+import static androidx.appsearch.localstorage.util.PrefixUtil.removePrefix;
+import static androidx.appsearch.localstorage.util.PrefixUtil.removePrefixesFromDocument;
+
import android.os.Bundle;
+import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.GetByDocumentIdRequest;
+import androidx.appsearch.app.GetSchemaResponse;
+import androidx.appsearch.app.PackageIdentifier;
import androidx.appsearch.app.SearchResultPage;
import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.appsearch.app.StorageInfo;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.localstorage.converter.GenericDocumentToProtoConverter;
+import androidx.appsearch.localstorage.converter.ResultCodeToProtoConverter;
import androidx.appsearch.localstorage.converter.SchemaToProtoConverter;
import androidx.appsearch.localstorage.converter.SearchResultToProtoConverter;
import androidx.appsearch.localstorage.converter.SearchSpecToProtoConverter;
+import androidx.appsearch.localstorage.converter.SetSchemaResponseToProtoConverter;
+import androidx.appsearch.localstorage.converter.TypePropertyPathToProtoConverter;
+import androidx.appsearch.localstorage.stats.InitializeStats;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
+import androidx.appsearch.localstorage.stats.PutDocumentStats;
+import androidx.appsearch.localstorage.stats.RemoveStats;
+import androidx.appsearch.localstorage.stats.SearchStats;
+import androidx.appsearch.localstorage.stats.SetSchemaStats;
+import androidx.appsearch.localstorage.visibilitystore.VisibilityStore;
+import androidx.appsearch.util.LogUtil;
+import androidx.collection.ArrayMap;
import androidx.collection.ArraySet;
+import androidx.core.util.ObjectsCompat;
import androidx.core.util.Preconditions;
import com.google.android.icing.IcingSearchEngine;
import com.google.android.icing.proto.DeleteByQueryResultProto;
import com.google.android.icing.proto.DeleteResultProto;
import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.DocumentStorageInfoProto;
import com.google.android.icing.proto.GetAllNamespacesResultProto;
import com.google.android.icing.proto.GetOptimizeInfoResultProto;
import com.google.android.icing.proto.GetResultProto;
@@ -48,11 +77,13 @@
import com.google.android.icing.proto.GetSchemaResultProto;
import com.google.android.icing.proto.IcingSearchEngineOptions;
import com.google.android.icing.proto.InitializeResultProto;
+import com.google.android.icing.proto.NamespaceStorageInfoProto;
import com.google.android.icing.proto.OptimizeResultProto;
import com.google.android.icing.proto.PersistToDiskResultProto;
+import com.google.android.icing.proto.PersistType;
import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.PropertyProto;
import com.google.android.icing.proto.PutResultProto;
+import com.google.android.icing.proto.ReportUsageResultProto;
import com.google.android.icing.proto.ResetResultProto;
import com.google.android.icing.proto.ResultSpecProto;
import com.google.android.icing.proto.SchemaProto;
@@ -62,12 +93,17 @@
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.SetSchemaResultProto;
import com.google.android.icing.proto.StatusProto;
+import com.google.android.icing.proto.StorageInfoProto;
+import com.google.android.icing.proto.StorageInfoResultProto;
import com.google.android.icing.proto.TypePropertyMask;
+import com.google.android.icing.proto.UsageReport;
+import java.io.Closeable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -109,35 +145,29 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@WorkerThread
-public final class AppSearchImpl {
+public final class AppSearchImpl implements Closeable {
private static final String TAG = "AppSearchImpl";
- @VisibleForTesting
- static final char DATABASE_DELIMITER = '/';
-
- @VisibleForTesting
- static final char PACKAGE_DELIMITER = '$';
-
- @VisibleForTesting
- static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
- @VisibleForTesting
- static final int OPTIMIZE_THRESHOLD_BYTES = 1_000_000; // 1MB
+ /** A value 0 means that there're no more pages in the search results. */
+ private static final long EMPTY_PAGE_TOKEN = 0;
@VisibleForTesting
static final int CHECK_OPTIMIZE_INTERVAL = 100;
private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
+ private final LogUtil mLogUtil = new LogUtil(TAG);
+ private final OptimizeStrategy mOptimizeStrategy;
+ private final LimitConfig mLimitConfig;
@GuardedBy("mReadWriteLock")
- private final IcingSearchEngine mIcingSearchEngineLocked;
+ @VisibleForTesting
+ final IcingSearchEngine mIcingSearchEngineLocked;
+ // This map contains schema types and SchemaTypeConfigProtos for all package-database
+ // prefixes. It maps each package-database prefix to an inner-map. The inner-map maps each
+ // prefixed schema type to its respective SchemaTypeConfigProto.
@GuardedBy("mReadWriteLock")
- private final VisibilityStore mVisibilityStoreLocked;
-
- // This map contains schemaTypes for all package-database prefixes. All values in the map are
- // prefixed with the package-database prefix.
- // TODO(b/172360376): Check if this can be replaced with an ArrayMap
- @GuardedBy("mReadWriteLock")
- private final Map<String, Set<String>> mSchemaMapLocked = new HashMap<>();
+ private final Map<String, Map<String, SchemaTypeConfigProto>> mSchemaMapLocked =
+ new ArrayMap<>();
// This map contains namespaces for all package-database prefixes. All values in the map are
// prefixed with the package-database prefix.
@@ -145,84 +175,202 @@
@GuardedBy("mReadWriteLock")
private final Map<String, Set<String>> mNamespaceMapLocked = new HashMap<>();
+ /** Maps package name to active document count. */
+ @GuardedBy("mReadWriteLock")
+ private final Map<String, Integer> mDocumentCountMapLocked = new ArrayMap<>();
+
+ // Maps packages to the set of valid nextPageTokens that the package can manipulate. A token
+ // is unique and constant per query (i.e. the same token '123' is used to iterate through
+ // pages of search results). The tokens themselves are generated and tracked by
+ // IcingSearchEngine. IcingSearchEngine considers a token valid and won't be reused
+ // until we call invalidateNextPageToken on the token.
+ //
+ // Note that we synchronize on itself because the nextPageToken cache is checked at
+ // query-time, and queries are done in parallel with a read lock. Ideally, this would be
+ // guarded by the normal mReadWriteLock.writeLock, but ReentrantReadWriteLocks can't upgrade
+ // read to write locks. This lock should be acquired at the smallest scope possible.
+ // mReadWriteLock is a higher-level lock, so calls shouldn't be made out
+ // to any functions that grab the lock.
+ @GuardedBy("mNextPageTokensLocked")
+ private final Map<String, Set<Long>> mNextPageTokensLocked = new ArrayMap<>();
+
/**
- * The counter to check when to call {@link #checkForOptimizeLocked(boolean)}. The
+ * The counter to check when to call {@link #checkForOptimize}. The
* interval is
* {@link #CHECK_OPTIMIZE_INTERVAL}.
*/
@GuardedBy("mReadWriteLock")
private int mOptimizeIntervalCountLocked = 0;
+ /** Whether this instance has been closed, and therefore unusable. */
+ @GuardedBy("mReadWriteLock")
+ private boolean mClosedLocked = false;
+
/**
* Creates and initializes an instance of {@link AppSearchImpl} which writes data to the given
* folder.
+ *
+ * <p>Clients can pass a {@link AppSearchLogger} here through their AppSearchSession, but it
+ * can't be saved inside {@link AppSearchImpl}, because the impl will be shared by all the
+ * sessions for the same package in JetPack.
+ *
+ * <p>Instead, logger instance needs to be passed to each individual method, like create, query
+ * and putDocument.
+ *
+ * @param initStatsBuilder collects stats for initialization if provided.
*/
@NonNull
- public static AppSearchImpl create(@NonNull File icingDir) throws AppSearchException {
- Preconditions.checkNotNull(icingDir);
- AppSearchImpl appSearchImpl = new AppSearchImpl(icingDir);
- appSearchImpl.initializeVisibilityStore();
- return appSearchImpl;
+ public static AppSearchImpl create(
+ @NonNull File icingDir,
+ @NonNull LimitConfig limitConfig,
+ @Nullable InitializeStats.Builder initStatsBuilder,
+ @NonNull OptimizeStrategy optimizeStrategy)
+ throws AppSearchException {
+ return new AppSearchImpl(icingDir, limitConfig, initStatsBuilder, optimizeStrategy);
}
- private AppSearchImpl(@NonNull File icingDir) throws AppSearchException {
- mReadWriteLock.writeLock().lock();
+ /**
+ * @param initStatsBuilder collects stats for initialization if provided.
+ */
+ private AppSearchImpl(
+ @NonNull File icingDir,
+ @NonNull LimitConfig limitConfig,
+ @Nullable InitializeStats.Builder initStatsBuilder,
+ @NonNull OptimizeStrategy optimizeStrategy)
+ throws AppSearchException {
+ Preconditions.checkNotNull(icingDir);
+ mLimitConfig = Preconditions.checkNotNull(limitConfig);
+ mOptimizeStrategy = Preconditions.checkNotNull(optimizeStrategy);
+ mReadWriteLock.writeLock().lock();
try {
// We synchronize here because we don't want to call IcingSearchEngine.initialize() more
// than once. It's unnecessary and can be a costly operation.
IcingSearchEngineOptions options = IcingSearchEngineOptions.newBuilder()
.setBaseDir(icingDir.getAbsolutePath()).build();
+ mLogUtil.piiTrace("Constructing IcingSearchEngine, request", options);
mIcingSearchEngineLocked = new IcingSearchEngine(options);
+ mLogUtil.piiTrace(
+ "Constructing IcingSearchEngine, response",
+ ObjectsCompat.hashCode(mIcingSearchEngineLocked));
- mVisibilityStoreLocked = new VisibilityStore(this);
-
- InitializeResultProto initializeResultProto = mIcingSearchEngineLocked.initialize();
- SchemaProto schemaProto;
- GetAllNamespacesResultProto getAllNamespacesResultProto;
+ // The core initialization procedure. If any part of this fails, we bail into
+ // resetLocked(), deleting all data (but hopefully allowing AppSearchImpl to come up).
try {
+ mLogUtil.piiTrace("icingSearchEngine.initialize, request");
+ InitializeResultProto initializeResultProto = mIcingSearchEngineLocked.initialize();
+ mLogUtil.piiTrace(
+ "icingSearchEngine.initialize, response",
+ initializeResultProto.getStatus(),
+ initializeResultProto);
+
+ if (initStatsBuilder != null) {
+ initStatsBuilder
+ .setStatusCode(
+ statusProtoToResultCode(initializeResultProto.getStatus()))
+ // TODO(b/173532925) how to get DeSyncs value
+ .setHasDeSync(false);
+ AppSearchLoggerHelper.copyNativeStats(
+ initializeResultProto.getInitializeStats(), initStatsBuilder);
+ }
checkSuccess(initializeResultProto.getStatus());
- schemaProto = getSchemaProtoLocked();
- getAllNamespacesResultProto = mIcingSearchEngineLocked.getAllNamespaces();
+
+ // Read all protos we need to construct AppSearchImpl's cache maps
+ long prepareSchemaAndNamespacesLatencyStartMillis = SystemClock.elapsedRealtime();
+ SchemaProto schemaProto = getSchemaProtoLocked();
+
+ mLogUtil.piiTrace("init:getAllNamespaces, request");
+ GetAllNamespacesResultProto getAllNamespacesResultProto =
+ mIcingSearchEngineLocked.getAllNamespaces();
+ mLogUtil.piiTrace(
+ "init:getAllNamespaces, response",
+ getAllNamespacesResultProto.getNamespacesCount(),
+ getAllNamespacesResultProto);
+
+ StorageInfoProto storageInfoProto = getRawStorageInfoProto();
+
+ // Log the time it took to read the data that goes into the cache maps
+ if (initStatsBuilder != null) {
+ // In case there is some error for getAllNamespaces, we can still
+ // set the latency for preparation.
+ // If there is no error, the value will be overridden by the actual one later.
+ initStatsBuilder.setStatusCode(
+ statusProtoToResultCode(getAllNamespacesResultProto.getStatus()))
+ .setPrepareSchemaAndNamespacesLatencyMillis(
+ (int) (SystemClock.elapsedRealtime()
+ - prepareSchemaAndNamespacesLatencyStartMillis));
+ }
checkSuccess(getAllNamespacesResultProto.getStatus());
+
+ // Populate schema map
+ List<SchemaTypeConfigProto> schemaProtoTypesList = schemaProto.getTypesList();
+ for (int i = 0; i < schemaProtoTypesList.size(); i++) {
+ SchemaTypeConfigProto schema = schemaProtoTypesList.get(i);
+ String prefixedSchemaType = schema.getSchemaType();
+ addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType), schema);
+ }
+
+ // Populate namespace map
+ List<String> prefixedNamespaceList =
+ getAllNamespacesResultProto.getNamespacesList();
+ for (int i = 0; i < prefixedNamespaceList.size(); i++) {
+ String prefixedNamespace = prefixedNamespaceList.get(i);
+ addToMap(mNamespaceMapLocked, getPrefix(prefixedNamespace), prefixedNamespace);
+ }
+
+ // Populate document count map
+ rebuildDocumentCountMapLocked(storageInfoProto);
+
+ // logging prepare_schema_and_namespaces latency
+ if (initStatsBuilder != null) {
+ initStatsBuilder.setPrepareSchemaAndNamespacesLatencyMillis(
+ (int) (SystemClock.elapsedRealtime()
+ - prepareSchemaAndNamespacesLatencyStartMillis));
+ }
+
+ mLogUtil.piiTrace("Init completed successfully");
+
} catch (AppSearchException e) {
- Log.w(TAG, "Error initializing, resetting IcingSearchEngine.", e);
// Some error. Reset and see if it fixes it.
- reset();
- return;
+ Log.e(TAG, "Error initializing, resetting IcingSearchEngine.", e);
+ if (initStatsBuilder != null) {
+ initStatsBuilder.setStatusCode(e.getResultCode());
+ }
+ resetLocked(initStatsBuilder);
}
- // Populate schema map
- for (SchemaTypeConfigProto schema : schemaProto.getTypesList()) {
- String prefixedSchemaType = schema.getSchemaType();
- addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType),
- prefixedSchemaType);
- }
-
- // Populate namespace map
- for (String prefixedNamespace : getAllNamespacesResultProto.getNamespacesList()) {
- addToMap(mNamespaceMapLocked, getPrefix(prefixedNamespace),
- prefixedNamespace);
- }
-
- // TODO(b/155939114): It's possible to optimize after init, which would reduce the time
- // to when we're able to serve queries. Consider moving this optimize call out.
- checkForOptimizeLocked(/* force= */ true);
-
} finally {
mReadWriteLock.writeLock().unlock();
}
}
+ @GuardedBy("mReadWriteLock")
+ private void throwIfClosedLocked() {
+ if (mClosedLocked) {
+ throw new IllegalStateException("Trying to use a closed AppSearchImpl instance.");
+ }
+ }
+
/**
- * Initialize the visibility store in AppSearchImpl.
+ * Persists data to disk and closes the instance.
*
- * @throws AppSearchException on IcingSearchEngine error.
+ * <p>This instance is no longer usable after it's been closed. Call {@link #create} to
+ * create a new, usable instance.
*/
- void initializeVisibilityStore() throws AppSearchException {
+ @Override
+ public void close() {
mReadWriteLock.writeLock().lock();
try {
- mVisibilityStoreLocked.initialize();
+ if (mClosedLocked) {
+ return;
+ }
+ persistToDisk(PersistType.Code.FULL);
+ mLogUtil.piiTrace("icingSearchEngine.close, request");
+ mIcingSearchEngineLocked.close();
+ mLogUtil.piiTrace("icingSearchEngine.close, response");
+ mClosedLocked = true;
+ } catch (AppSearchException e) {
+ Log.w(TAG, "Error when closing AppSearchImpl.", e);
} finally {
mReadWriteLock.writeLock().unlock();
}
@@ -236,27 +384,46 @@
* @param packageName The package name that owns the schemas.
* @param databaseName The name of the database where this schema lives.
* @param schemas Schemas to set for this app.
- * @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform
+ * @param visibilityStore If set, {@code schemasNotDisplayedBySystem} and {@code
+ * schemasVisibleToPackages} will be saved here if the
+ * schema is successfully applied.
+ * @param schemasNotDisplayedBySystem Schema types that should not be surfaced on platform
* surfaces.
+ * @param schemasVisibleToPackages Schema types that are visible to the specified packages.
* @param forceOverride Whether to force-apply the schema even if it is
* incompatible. Documents
* which do not comply with the new schema will be deleted.
- * @throws AppSearchException on IcingSearchEngine error.
+ * @param version The overall version number of the request.
+ * @param setSchemaStatsBuilder Builder for {@link SetSchemaStats} to hold stats for
+ * setSchema
+ * @return The response contains deleted schema types and incompatible schema types of this
+ * call.
+ * @throws AppSearchException On IcingSearchEngine error. If the status code is
+ * FAILED_PRECONDITION for the incompatible change, the
+ * exception will be converted to the SetSchemaResponse.
*/
- public void setSchema(
+ @NonNull
+ public SetSchemaResponse setSchema(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull List<AppSearchSchema> schemas,
- @NonNull List<String> schemasNotPlatformSurfaceable,
- boolean forceOverride) throws AppSearchException {
+ @Nullable VisibilityStore visibilityStore,
+ @NonNull List<String> schemasNotDisplayedBySystem,
+ @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages,
+ boolean forceOverride,
+ int version,
+ @Nullable SetSchemaStats.Builder setSchemaStatsBuilder) throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
+ throwIfClosedLocked();
+
SchemaProto.Builder existingSchemaBuilder = getSchemaProtoLocked().toBuilder();
SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
for (int i = 0; i < schemas.size(); i++) {
+ AppSearchSchema schema = schemas.get(i);
SchemaTypeConfigProto schemaTypeProto =
- SchemaToProtoConverter.toSchemaTypeConfigProto(schemas.get(i));
+ SchemaToProtoConverter.toSchemaTypeConfigProto(schema, version);
newSchemaBuilder.addTypes(schemaTypeProto);
}
@@ -268,49 +435,72 @@
newSchemaBuilder.build());
// Apply schema
+ SchemaProto finalSchema = existingSchemaBuilder.build();
+ mLogUtil.piiTrace("setSchema, request", finalSchema.getTypesCount(), finalSchema);
SetSchemaResultProto setSchemaResultProto =
- mIcingSearchEngineLocked.setSchema(existingSchemaBuilder.build(),
- forceOverride);
+ mIcingSearchEngineLocked.setSchema(finalSchema, forceOverride);
+ mLogUtil.piiTrace(
+ "setSchema, response", setSchemaResultProto.getStatus(), setSchemaResultProto);
+
+ if (setSchemaStatsBuilder != null) {
+ setSchemaStatsBuilder.setStatusCode(statusProtoToResultCode(
+ setSchemaResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(setSchemaResultProto,
+ setSchemaStatsBuilder);
+ }
// Determine whether it succeeded.
try {
checkSuccess(setSchemaResultProto.getStatus());
} catch (AppSearchException e) {
- // Improve the error message by merging in information about incompatible types.
- if (setSchemaResultProto.getDeletedSchemaTypesCount() > 0
- || setSchemaResultProto.getIncompatibleSchemaTypesCount() > 0) {
- String newMessage = e.getMessage()
- + "\n Deleted types: "
- + setSchemaResultProto.getDeletedSchemaTypesList()
- + "\n Incompatible types: "
- + setSchemaResultProto.getIncompatibleSchemaTypesList();
- throw new AppSearchException(e.getResultCode(), newMessage, e.getCause());
+ // Swallow the exception for the incompatible change case. We will propagate
+ // those deleted schemas and incompatible types to the SetSchemaResponse.
+ boolean isFailedPrecondition = setSchemaResultProto.getStatus().getCode()
+ == StatusProto.Code.FAILED_PRECONDITION;
+ boolean isIncompatible = setSchemaResultProto.getDeletedSchemaTypesCount() > 0
+ || setSchemaResultProto.getIncompatibleSchemaTypesCount() > 0;
+ if (isFailedPrecondition && isIncompatible) {
+ return SetSchemaResponseToProtoConverter
+ .toSetSchemaResponse(setSchemaResultProto, prefix);
} else {
throw e;
}
}
// Update derived data structures.
- mSchemaMapLocked.put(prefix, rewrittenSchemaResults.mRewrittenPrefixedTypes);
-
- Set<String> prefixedSchemasNotPlatformSurfaceable =
- new ArraySet<>(schemasNotPlatformSurfaceable.size());
- for (int i = 0; i < schemasNotPlatformSurfaceable.size(); i++) {
- prefixedSchemasNotPlatformSurfaceable.add(
- prefix + schemasNotPlatformSurfaceable.get(i));
+ for (SchemaTypeConfigProto schemaTypeConfigProto :
+ rewrittenSchemaResults.mRewrittenPrefixedTypes.values()) {
+ addToMap(mSchemaMapLocked, prefix, schemaTypeConfigProto);
}
- mVisibilityStoreLocked.setVisibility(prefix,
- prefixedSchemasNotPlatformSurfaceable);
- // Determine whether to schedule an immediate optimize.
- if (setSchemaResultProto.getDeletedSchemaTypesCount() > 0
- || (setSchemaResultProto.getIncompatibleSchemaTypesCount() > 0
- && forceOverride)) {
- // Any existing schemas which is not in 'schemas' will be deleted, and all
- // documents of these types were also deleted. And so well if we force override
- // incompatible schemas.
- checkForOptimizeLocked(/* force= */true);
+ for (String schemaType : rewrittenSchemaResults.mDeletedPrefixedTypes) {
+ removeFromMap(mSchemaMapLocked, prefix, schemaType);
}
+
+ if (visibilityStore != null) {
+ Set<String> prefixedSchemasNotDisplayedBySystem =
+ new ArraySet<>(schemasNotDisplayedBySystem.size());
+ for (int i = 0; i < schemasNotDisplayedBySystem.size(); i++) {
+ prefixedSchemasNotDisplayedBySystem.add(
+ prefix + schemasNotDisplayedBySystem.get(i));
+ }
+
+ Map<String, List<PackageIdentifier>> prefixedSchemasVisibleToPackages =
+ new ArrayMap<>(schemasVisibleToPackages.size());
+ for (Map.Entry<String, List<PackageIdentifier>> entry
+ : schemasVisibleToPackages.entrySet()) {
+ prefixedSchemasVisibleToPackages.put(prefix + entry.getKey(), entry.getValue());
+ }
+
+ visibilityStore.setVisibility(
+ packageName,
+ databaseName,
+ prefixedSchemasNotDisplayedBySystem,
+ prefixedSchemasVisibleToPackages);
+ }
+
+ return SetSchemaResponseToProtoConverter
+ .toSetSchemaResponse(setSchemaResultProto, prefix);
} finally {
mReadWriteLock.writeLock().unlock();
}
@@ -326,47 +516,94 @@
* @throws AppSearchException on IcingSearchEngine error.
*/
@NonNull
- public List<AppSearchSchema> getSchema(@NonNull String packageName,
+ public GetSchemaResponse getSchema(@NonNull String packageName,
@NonNull String databaseName) throws AppSearchException {
- SchemaProto fullSchema;
mReadWriteLock.readLock().lock();
try {
- fullSchema = getSchemaProtoLocked();
+ throwIfClosedLocked();
+
+ SchemaProto fullSchema = getSchemaProtoLocked();
+
+ String prefix = createPrefix(packageName, databaseName);
+ GetSchemaResponse.Builder responseBuilder = new GetSchemaResponse.Builder();
+ for (int i = 0; i < fullSchema.getTypesCount(); i++) {
+ String typePrefix = getPrefix(fullSchema.getTypes(i).getSchemaType());
+ if (!prefix.equals(typePrefix)) {
+ continue;
+ }
+ // Rewrite SchemaProto.types.schema_type
+ SchemaTypeConfigProto.Builder typeConfigBuilder = fullSchema.getTypes(
+ i).toBuilder();
+ String newSchemaType =
+ typeConfigBuilder.getSchemaType().substring(prefix.length());
+ typeConfigBuilder.setSchemaType(newSchemaType);
+
+ // Rewrite SchemaProto.types.properties.schema_type
+ for (int propertyIdx = 0;
+ propertyIdx < typeConfigBuilder.getPropertiesCount();
+ propertyIdx++) {
+ PropertyConfigProto.Builder propertyConfigBuilder =
+ typeConfigBuilder.getProperties(propertyIdx).toBuilder();
+ if (!propertyConfigBuilder.getSchemaType().isEmpty()) {
+ String newPropertySchemaType = propertyConfigBuilder.getSchemaType()
+ .substring(prefix.length());
+ propertyConfigBuilder.setSchemaType(newPropertySchemaType);
+ typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder);
+ }
+ }
+
+ AppSearchSchema schema = SchemaToProtoConverter.toAppSearchSchema(
+ typeConfigBuilder);
+
+ //TODO(b/183050495) find a place to store the version for the database, rather
+ // than read from a schema.
+ responseBuilder.setVersion(fullSchema.getTypes(i).getVersion());
+ responseBuilder.addSchema(schema);
+ }
+ return responseBuilder.build();
} finally {
mReadWriteLock.readLock().unlock();
}
+ }
- String prefix = createPrefix(packageName, databaseName);
- List<AppSearchSchema> result = new ArrayList<>();
- for (int i = 0; i < fullSchema.getTypesCount(); i++) {
- String typePrefix = getPrefix(fullSchema.getTypes(i).getSchemaType());
- if (!prefix.equals(typePrefix)) {
- continue;
- }
- // Rewrite SchemaProto.types.schema_type
- SchemaTypeConfigProto.Builder typeConfigBuilder = fullSchema.getTypes(i).toBuilder();
- String newSchemaType =
- typeConfigBuilder.getSchemaType().substring(prefix.length());
- typeConfigBuilder.setSchemaType(newSchemaType);
-
- // Rewrite SchemaProto.types.properties.schema_type
- for (int propertyIdx = 0;
- propertyIdx < typeConfigBuilder.getPropertiesCount();
- propertyIdx++) {
- PropertyConfigProto.Builder propertyConfigBuilder =
- typeConfigBuilder.getProperties(propertyIdx).toBuilder();
- if (!propertyConfigBuilder.getSchemaType().isEmpty()) {
- String newPropertySchemaType = propertyConfigBuilder.getSchemaType()
- .substring(prefix.length());
- propertyConfigBuilder.setSchemaType(newPropertySchemaType);
- typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder);
+ /**
+ * Retrieves the list of namespaces with at least one document for this package name, database.
+ *
+ * <p>This method belongs to query group.
+ *
+ * @param packageName Package name that owns this schema
+ * @param databaseName The name of the database where this schema lives.
+ * @throws AppSearchException on IcingSearchEngine error.
+ */
+ @NonNull
+ public List<String> getNamespaces(
+ @NonNull String packageName, @NonNull String databaseName) throws AppSearchException {
+ mReadWriteLock.readLock().lock();
+ try {
+ throwIfClosedLocked();
+ mLogUtil.piiTrace("getAllNamespaces, request");
+ // We can't just use mNamespaceMap here because we have no way to prune namespaces from
+ // mNamespaceMap when they have no more documents (e.g. after setting schema to empty or
+ // using deleteByQuery).
+ GetAllNamespacesResultProto getAllNamespacesResultProto =
+ mIcingSearchEngineLocked.getAllNamespaces();
+ mLogUtil.piiTrace(
+ "getAllNamespaces, response",
+ getAllNamespacesResultProto.getNamespacesCount(),
+ getAllNamespacesResultProto);
+ checkSuccess(getAllNamespacesResultProto.getStatus());
+ String prefix = createPrefix(packageName, databaseName);
+ List<String> results = new ArrayList<>();
+ for (int i = 0; i < getAllNamespacesResultProto.getNamespacesCount(); i++) {
+ String prefixedNamespace = getAllNamespacesResultProto.getNamespaces(i);
+ if (prefixedNamespace.startsWith(prefix)) {
+ results.add(prefixedNamespace.substring(prefix.length()));
}
}
-
- AppSearchSchema schema = SchemaToProtoConverter.toAppSearchSchema(typeConfigBuilder);
- result.add(schema);
+ return results;
+ } finally {
+ mReadWriteLock.readLock().unlock();
}
- return result;
}
/**
@@ -380,57 +617,188 @@
* @throws AppSearchException on IcingSearchEngine error.
*/
public void putDocument(@NonNull String packageName, @NonNull String databaseName,
- @NonNull GenericDocument document)
+ @NonNull GenericDocument document, @Nullable AppSearchLogger logger)
throws AppSearchException {
- DocumentProto.Builder documentBuilder = GenericDocumentToProtoConverter.toDocumentProto(
- document).toBuilder();
- String prefix = createPrefix(packageName, databaseName);
- addPrefixToDocument(documentBuilder, prefix);
+ PutDocumentStats.Builder pStatsBuilder = null;
+ if (logger != null) {
+ pStatsBuilder = new PutDocumentStats.Builder(packageName, databaseName);
+ }
+ long totalStartTimeMillis = SystemClock.elapsedRealtime();
- PutResultProto putResultProto;
mReadWriteLock.writeLock().lock();
try {
- putResultProto = mIcingSearchEngineLocked.put(documentBuilder.build());
- addToMap(mNamespaceMapLocked, prefix, documentBuilder.getNamespace());
- // The existing documents with same URI will be deleted, so there maybe some resources
- // could be released after optimize().
- checkForOptimizeLocked(/* force= */ false);
+ throwIfClosedLocked();
+
+ // Generate Document Proto
+ long generateDocumentProtoStartTimeMillis = SystemClock.elapsedRealtime();
+ DocumentProto.Builder documentBuilder = GenericDocumentToProtoConverter.toDocumentProto(
+ document).toBuilder();
+ long generateDocumentProtoEndTimeMillis = SystemClock.elapsedRealtime();
+
+ // Rewrite Document Type
+ long rewriteDocumentTypeStartTimeMillis = SystemClock.elapsedRealtime();
+ String prefix = createPrefix(packageName, databaseName);
+ addPrefixToDocument(documentBuilder, prefix);
+ long rewriteDocumentTypeEndTimeMillis = SystemClock.elapsedRealtime();
+ DocumentProto finalDocument = documentBuilder.build();
+
+ // Check limits
+ int newDocumentCount = enforceLimitConfigLocked(
+ packageName, finalDocument.getUri(), finalDocument.getSerializedSize());
+
+ // Insert document
+ mLogUtil.piiTrace("putDocument, request", finalDocument.getUri(), finalDocument);
+ PutResultProto putResultProto = mIcingSearchEngineLocked.put(finalDocument);
+ mLogUtil.piiTrace("putDocument, response", putResultProto.getStatus(), putResultProto);
+
+ // Update caches
+ addToMap(mNamespaceMapLocked, prefix, finalDocument.getNamespace());
+ mDocumentCountMapLocked.put(packageName, newDocumentCount);
+
+ // Logging stats
+ if (pStatsBuilder != null) {
+ pStatsBuilder
+ .setStatusCode(statusProtoToResultCode(putResultProto.getStatus()))
+ .setGenerateDocumentProtoLatencyMillis(
+ (int) (generateDocumentProtoEndTimeMillis
+ - generateDocumentProtoStartTimeMillis))
+ .setRewriteDocumentTypesLatencyMillis(
+ (int) (rewriteDocumentTypeEndTimeMillis
+ - rewriteDocumentTypeStartTimeMillis));
+ AppSearchLoggerHelper.copyNativeStats(putResultProto.getPutDocumentStats(),
+ pStatsBuilder);
+ }
+
+ checkSuccess(putResultProto.getStatus());
} finally {
mReadWriteLock.writeLock().unlock();
+
+ if (logger != null) {
+ long totalEndTimeMillis = SystemClock.elapsedRealtime();
+ pStatsBuilder.setTotalLatencyMillis(
+ (int) (totalEndTimeMillis - totalStartTimeMillis));
+ logger.logStats(pStatsBuilder.build());
+ }
}
- checkSuccess(putResultProto.getStatus());
}
/**
- * Retrieves a document from the AppSearch index by URI.
+ * Checks that a new document can be added to the given packageName with the given serialized
+ * size without violating our {@link LimitConfig}.
+ *
+ * @return the new count of documents for the given package, including the new document.
+ * @throws AppSearchException with a code of {@link AppSearchResult#RESULT_OUT_OF_SPACE} if the
+ * limits are violated by the new document.
+ */
+ @GuardedBy("mReadWriteLock")
+ private int enforceLimitConfigLocked(String packageName, String newDocUri, int newDocSize)
+ throws AppSearchException {
+ // Limits check: size of document
+ if (newDocSize > mLimitConfig.getMaxDocumentSizeBytes()) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_OUT_OF_SPACE,
+ "Document \"" + newDocUri + "\" for package \"" + packageName
+ + "\" serialized to " + newDocSize + " bytes, which exceeds "
+ + "limit of " + mLimitConfig.getMaxDocumentSizeBytes() + " bytes");
+ }
+
+ // Limits check: number of documents
+ Integer oldDocumentCount = mDocumentCountMapLocked.get(packageName);
+ int newDocumentCount;
+ if (oldDocumentCount == null) {
+ newDocumentCount = 1;
+ } else {
+ newDocumentCount = oldDocumentCount + 1;
+ }
+ if (newDocumentCount > mLimitConfig.getMaxDocumentCount()) {
+ // Our management of mDocumentCountMapLocked doesn't account for document
+ // replacements, so our counter might have overcounted if the app has replaced docs.
+ // Rebuild the counter from StorageInfo in case this is so.
+ // TODO(b/170371356): If Icing lib exposes something in the result which says
+ // whether the document was a replacement, we could subtract 1 again after the put
+ // to keep the count accurate. That would allow us to remove this code.
+ rebuildDocumentCountMapLocked(getRawStorageInfoProto());
+ oldDocumentCount = mDocumentCountMapLocked.get(packageName);
+ if (oldDocumentCount == null) {
+ newDocumentCount = 1;
+ } else {
+ newDocumentCount = oldDocumentCount + 1;
+ }
+ }
+ if (newDocumentCount > mLimitConfig.getMaxDocumentCount()) {
+ // Now we really can't fit it in, even accounting for replacements.
+ throw new AppSearchException(
+ AppSearchResult.RESULT_OUT_OF_SPACE,
+ "Package \"" + packageName + "\" exceeded limit of "
+ + mLimitConfig.getMaxDocumentCount() + " documents. Some documents "
+ + "must be removed to index additional ones.");
+ }
+
+ return newDocumentCount;
+ }
+
+ /**
+ * Retrieves a document from the AppSearch index by namespace and document ID.
*
* <p>This method belongs to query group.
*
- * @param packageName The package that owns this document.
- * @param databaseName The databaseName this document resides in.
- * @param namespace The namespace this document resides in.
- * @param uri The URI of the document to get.
+ * @param packageName The package that owns this document.
+ * @param databaseName The databaseName this document resides in.
+ * @param namespace The namespace this document resides in.
+ * @param id The ID of the document to get.
+ * @param typePropertyPaths A map of schema type to a list of property paths to return in the
+ * result.
* @return The Document contents
* @throws AppSearchException on IcingSearchEngine error.
*/
@NonNull
- public GenericDocument getDocument(@NonNull String packageName, @NonNull String databaseName,
+ public GenericDocument getDocument(
+ @NonNull String packageName, @NonNull String databaseName,
@NonNull String namespace,
- @NonNull String uri) throws AppSearchException {
- GetResultProto getResultProto;
+ @NonNull String id,
+ @NonNull Map<String, List<String>> typePropertyPaths) throws AppSearchException {
mReadWriteLock.readLock().lock();
try {
- getResultProto = mIcingSearchEngineLocked.get(
- createPrefix(packageName, databaseName) + namespace, uri,
- GetResultSpecProto.getDefaultInstance());
+ throwIfClosedLocked();
+ String prefix = createPrefix(packageName, databaseName);
+ List<TypePropertyMask> nonPrefixedPropertyMasks =
+ TypePropertyPathToProtoConverter.toTypePropertyMaskList(typePropertyPaths);
+ List<TypePropertyMask> prefixedPropertyMasks =
+ new ArrayList<>(nonPrefixedPropertyMasks.size());
+ for (int i = 0; i < nonPrefixedPropertyMasks.size(); ++i) {
+ TypePropertyMask typePropertyMask = nonPrefixedPropertyMasks.get(i);
+ String nonPrefixedType = typePropertyMask.getSchemaType();
+ String prefixedType = nonPrefixedType.equals(
+ GetByDocumentIdRequest.PROJECTION_SCHEMA_TYPE_WILDCARD)
+ ? nonPrefixedType : prefix + nonPrefixedType;
+ prefixedPropertyMasks.add(
+ typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
+ }
+ GetResultSpecProto getResultSpec =
+ GetResultSpecProto.newBuilder().addAllTypePropertyMasks(prefixedPropertyMasks
+ ).build();
+
+ String finalNamespace = createPrefix(packageName, databaseName) + namespace;
+ if (mLogUtil.isPiiTraceEnabled()) {
+ mLogUtil.piiTrace(
+ "getDocument, request", finalNamespace + ", " + id + "," + getResultSpec);
+ }
+ GetResultProto getResultProto =
+ mIcingSearchEngineLocked.get(finalNamespace, id, getResultSpec);
+ mLogUtil.piiTrace("getDocument, response", getResultProto.getStatus(), getResultProto);
+ checkSuccess(getResultProto.getStatus());
+
+ // The schema type map cannot be null at this point. It could only be null if no
+ // schema had ever been set for that prefix. Given we have retrieved a document from
+ // the index, we know a schema had to have been set.
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = mSchemaMapLocked.get(prefix);
+ DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
+ removePrefixesFromDocument(documentBuilder);
+ return GenericDocumentToProtoConverter.toGenericDocument(documentBuilder.build(),
+ prefix, schemaTypeMap);
} finally {
mReadWriteLock.readLock().unlock();
}
- checkSuccess(getResultProto.getStatus());
-
- DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
- removePrefixesFromDocument(documentBuilder);
- return GenericDocumentToProtoConverter.toGenericDocument(documentBuilder.build());
}
/**
@@ -442,6 +810,7 @@
* @param databaseName The databaseName this query for.
* @param queryExpression Query String to search.
* @param searchSpec Spec for setting filters, raw query etc.
+ * @param logger logger to collect query stats
* @return The results of performing this search. It may contain an empty list of results if
* no documents matched the query.
* @throws AppSearchException on IcingSearchEngine error.
@@ -451,14 +820,48 @@
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String queryExpression,
- @NonNull SearchSpec searchSpec) throws AppSearchException {
+ @NonNull SearchSpec searchSpec,
+ @Nullable AppSearchLogger logger) throws AppSearchException {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ SearchStats.Builder sStatsBuilder = null;
+ if (logger != null) {
+ sStatsBuilder =
+ new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL,
+ packageName).setDatabase(databaseName);
+ }
+
mReadWriteLock.readLock().lock();
try {
- return doQueryLocked(Collections.singleton(createPrefix(packageName, databaseName)),
- queryExpression,
- searchSpec);
+ throwIfClosedLocked();
+
+ List<String> filterPackageNames = searchSpec.getFilterPackageNames();
+ if (!filterPackageNames.isEmpty() && !filterPackageNames.contains(packageName)) {
+ // Client wanted to query over some packages that weren't its own. This isn't
+ // allowed through local query so we can return early with no results.
+ if (logger != null) {
+ sStatsBuilder.setStatusCode(AppSearchResult.RESULT_SECURITY_ERROR);
+ }
+ return new SearchResultPage(Bundle.EMPTY);
+ }
+
+ String prefix = createPrefix(packageName, databaseName);
+ Set<String> allowedPrefixedSchemas = getAllowedPrefixSchemasLocked(prefix, searchSpec);
+
+ SearchResultPage searchResultPage =
+ doQueryLocked(Collections.singleton(createPrefix(packageName, databaseName)),
+ allowedPrefixedSchemas,
+ queryExpression,
+ searchSpec,
+ sStatsBuilder);
+ addNextPageToken(packageName, searchResultPage.getNextPageToken());
+ return searchResultPage;
} finally {
mReadWriteLock.readLock().unlock();
+ if (logger != null) {
+ sStatsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis));
+ logger.logStats(sStatsBuilder.build());
+ }
}
}
@@ -468,8 +871,16 @@
*
* <p>This method belongs to query group.
*
- * @param queryExpression Query String to search.
- * @param searchSpec Spec for setting filters, raw query etc.
+ * @param queryExpression Query String to search.
+ * @param searchSpec Spec for setting filters, raw query etc.
+ * @param callerPackageName Package name of the caller, should belong to the {@code
+ * callerUserHandle}.
+ * @param visibilityStore Optional visibility store to obtain system and package
+ * visibility settings from
+ * @param callerUid UID of the client making the globalQuery call.
+ * @param callerHasSystemAccess Whether the caller has been positively identified as having
+ * access to schemas marked system surfaceable.
+ * @param logger logger to collect globalQuery stats
* @return The results of performing this search. It may contain an empty list of results if
* no documents matched the query.
* @throws AppSearchException on IcingSearchEngine error.
@@ -477,21 +888,129 @@
@NonNull
public SearchResultPage globalQuery(
@NonNull String queryExpression,
- @NonNull SearchSpec searchSpec) throws AppSearchException {
- // TODO(b/169883602): Check if the platform is querying us at a higher level. At this
- // point, we should add all platform-surfaceable schemas assuming the querier has been
- // verified.
+ @NonNull SearchSpec searchSpec,
+ @NonNull String callerPackageName,
+ @Nullable VisibilityStore visibilityStore,
+ int callerUid,
+ boolean callerHasSystemAccess,
+ @Nullable AppSearchLogger logger) throws AppSearchException {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ SearchStats.Builder sStatsBuilder = null;
+ if (logger != null) {
+ sStatsBuilder =
+ new SearchStats.Builder(
+ SearchStats.VISIBILITY_SCOPE_GLOBAL,
+ callerPackageName);
+ }
+
mReadWriteLock.readLock().lock();
try {
- // We use the mNamespaceMap.keySet here because it's the smaller set of valid prefixes
- // that could exist.
- Set<String> prefixes = mNamespaceMapLocked.keySet();
+ throwIfClosedLocked();
- // Filter out any VisibilityStore documents which are AppSearch-internal only.
- prefixes.remove(createPrefix(VisibilityStore.PACKAGE_NAME,
- VisibilityStore.DATABASE_NAME));
+ // Convert package filters to prefix filters
+ Set<String> packageFilters = new ArraySet<>(searchSpec.getFilterPackageNames());
+ Set<String> prefixFilters = new ArraySet<>();
+ if (packageFilters.isEmpty()) {
+ // Client didn't restrict their search over packages. Try to query over all
+ // packages/prefixes
+ prefixFilters = mNamespaceMapLocked.keySet();
+ } else {
+ // Client did restrict their search over packages. Only include the prefixes that
+ // belong to the specified packages.
+ for (String prefix : mNamespaceMapLocked.keySet()) {
+ String packageName = getPackageName(prefix);
+ if (packageFilters.contains(packageName)) {
+ prefixFilters.add(prefix);
+ }
+ }
+ }
- return doQueryLocked(prefixes, queryExpression, searchSpec);
+ // Convert schema filters to prefixed schema filters
+ ArraySet<String> prefixedSchemaFilters = new ArraySet<>();
+ for (String prefix : prefixFilters) {
+ List<String> schemaFilters = searchSpec.getFilterSchemas();
+ if (schemaFilters.isEmpty()) {
+ // Client didn't specify certain schemas to search over, check all schemas
+ prefixedSchemaFilters.addAll(mSchemaMapLocked.get(prefix).keySet());
+ } else {
+ // Client specified some schemas to search over, check each one
+ for (int i = 0; i < schemaFilters.size(); i++) {
+ prefixedSchemaFilters.add(prefix + schemaFilters.get(i));
+ }
+ }
+ }
+
+ // Remove the schemas the client is not allowed to search over
+ Iterator<String> prefixedSchemaIt = prefixedSchemaFilters.iterator();
+ while (prefixedSchemaIt.hasNext()) {
+ String prefixedSchema = prefixedSchemaIt.next();
+ String packageName = getPackageName(prefixedSchema);
+
+ boolean allow;
+ if (packageName.equals(callerPackageName)) {
+ // Callers can always retrieve their own data
+ allow = true;
+ } else if (visibilityStore == null) {
+ // If there's no visibility store, there's no extra access
+ allow = false;
+ } else {
+ String databaseName = getDatabaseName(prefixedSchema);
+ allow = visibilityStore.isSchemaSearchableByCaller(
+ packageName,
+ databaseName,
+ prefixedSchema,
+ callerUid,
+ callerHasSystemAccess);
+ }
+
+ if (!allow) {
+ prefixedSchemaIt.remove();
+ }
+ }
+
+ SearchResultPage searchResultPage = doQueryLocked(
+ prefixFilters,
+ prefixedSchemaFilters,
+ queryExpression,
+ searchSpec,
+ sStatsBuilder);
+ addNextPageToken(callerPackageName, searchResultPage.getNextPageToken());
+ return searchResultPage;
+ } finally {
+ mReadWriteLock.readLock().unlock();
+
+ if (logger != null) {
+ sStatsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis));
+ logger.logStats(sStatsBuilder.build());
+ }
+ }
+ }
+
+ /**
+ * Returns a mapping of package names to all the databases owned by that package.
+ *
+ * <p>This method is inefficient to call repeatedly.
+ */
+ @NonNull
+ public Map<String, Set<String>> getPackageToDatabases() {
+ mReadWriteLock.readLock().lock();
+ try {
+ Map<String, Set<String>> packageToDatabases = new ArrayMap<>();
+ for (String prefix : mSchemaMapLocked.keySet()) {
+ String packageName = getPackageName(prefix);
+
+ Set<String> databases = packageToDatabases.get(packageName);
+ if (databases == null) {
+ databases = new ArraySet<>();
+ packageToDatabases.put(packageName, databases);
+ }
+
+ String databaseName = getDatabaseName(prefix);
+ databases.add(databaseName);
+ }
+
+ return packageToDatabases;
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -499,35 +1018,85 @@
@GuardedBy("mReadWriteLock")
private SearchResultPage doQueryLocked(
- @NonNull Set<String> prefixes, @NonNull String queryExpression,
- @NonNull SearchSpec searchSpec)
+ @NonNull Set<String> prefixes,
+ @NonNull Set<String> allowedPrefixedSchemas,
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec,
+ @Nullable SearchStats.Builder sStatsBuilder)
throws AppSearchException {
+ long rewriteSearchSpecLatencyStartMillis = SystemClock.elapsedRealtime();
+
SearchSpecProto.Builder searchSpecBuilder =
SearchSpecToProtoConverter.toSearchSpecProto(searchSpec).toBuilder().setQuery(
queryExpression);
- // rewriteSearchSpecForPrefixesLocked will return false if none of the prefixes that the
- // client is trying to search on exist, so we can return an empty SearchResult and skip
+ // rewriteSearchSpecForPrefixesLocked will return false if there is nothing to search
+ // over given their search filters, so we can return an empty SearchResult and skip
// sending request to Icing.
- if (!rewriteSearchSpecForPrefixesLocked(searchSpecBuilder, prefixes)) {
+ if (!rewriteSearchSpecForPrefixesLocked(searchSpecBuilder, prefixes,
+ allowedPrefixedSchemas)) {
+ if (sStatsBuilder != null) {
+ sStatsBuilder.setRewriteSearchSpecLatencyMillis(
+ (int) (SystemClock.elapsedRealtime()
+ - rewriteSearchSpecLatencyStartMillis));
+ }
return new SearchResultPage(Bundle.EMPTY);
}
+ // rewriteSearchSpec, rewriteResultSpec and convertScoringSpec are all counted in
+ // rewriteSearchSpecLatencyMillis
ResultSpecProto.Builder resultSpecBuilder =
SearchSpecToProtoConverter.toResultSpecProto(searchSpec).toBuilder();
- // rewriteResultSpecForPrefixesLocked will return false if none of the prefixes that the
- // client is trying to search on exist, so we can return an empty SearchResult and skip
- // sending request to Icing.
- if (!rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes)) {
- return new SearchResultPage(Bundle.EMPTY);
+ int groupingType = searchSpec.getResultGroupingTypeFlags();
+ if ((groupingType & SearchSpec.GROUPING_TYPE_PER_PACKAGE) != 0
+ && (groupingType & SearchSpec.GROUPING_TYPE_PER_NAMESPACE) != 0) {
+ addPerPackagePerNamespaceResultGroupingsLocked(resultSpecBuilder, prefixes,
+ searchSpec.getResultGroupingLimit());
+ } else if ((groupingType & SearchSpec.GROUPING_TYPE_PER_PACKAGE) != 0) {
+ addPerPackageResultGroupingsLocked(resultSpecBuilder, prefixes,
+ searchSpec.getResultGroupingLimit());
+ } else if ((groupingType & SearchSpec.GROUPING_TYPE_PER_NAMESPACE) != 0) {
+ addPerNamespaceResultGroupingsLocked(resultSpecBuilder, prefixes,
+ searchSpec.getResultGroupingLimit());
}
+ rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes, allowedPrefixedSchemas);
ScoringSpecProto scoringSpec = SearchSpecToProtoConverter.toScoringSpecProto(searchSpec);
+ SearchSpecProto finalSearchSpec = searchSpecBuilder.build();
+ ResultSpecProto finalResultSpec = resultSpecBuilder.build();
+
+ long rewriteSearchSpecLatencyEndMillis = SystemClock.elapsedRealtime();
+
+ if (mLogUtil.isPiiTraceEnabled()) {
+ mLogUtil.piiTrace(
+ "search, request",
+ finalSearchSpec.getQuery(),
+ finalSearchSpec + ", " + scoringSpec + ", " + finalResultSpec);
+ }
SearchResultProto searchResultProto = mIcingSearchEngineLocked.search(
- searchSpecBuilder.build(), scoringSpec, resultSpecBuilder.build());
+ finalSearchSpec, scoringSpec, finalResultSpec);
+ mLogUtil.piiTrace(
+ "search, response", searchResultProto.getResultsCount(), searchResultProto);
+
+ if (sStatsBuilder != null) {
+ sStatsBuilder
+ .setStatusCode(statusProtoToResultCode(searchResultProto.getStatus()))
+ .setRewriteSearchSpecLatencyMillis((int) (rewriteSearchSpecLatencyEndMillis
+ - rewriteSearchSpecLatencyStartMillis));
+ AppSearchLoggerHelper.copyNativeStats(searchResultProto.getQueryStats(), sStatsBuilder);
+ }
+
checkSuccess(searchResultProto.getStatus());
- return rewriteSearchResultProto(searchResultProto);
+ long rewriteSearchResultLatencyStartMillis = SystemClock.elapsedRealtime();
+ SearchResultPage resultPage = rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
+ if (sStatsBuilder != null) {
+ sStatsBuilder.setRewriteSearchResultLatencyMillis(
+ (int) (SystemClock.elapsedRealtime()
+ - rewriteSearchResultLatencyStartMillis));
+ }
+
+ return resultPage;
}
/**
@@ -536,21 +1105,62 @@
*
* <p>This method belongs to query group.
*
+ * @param packageName Package name of the caller.
* @param nextPageToken The token of pre-loaded results of previously executed query.
* @return The next page of results of previously executed query.
- * @throws AppSearchException on IcingSearchEngine error.
+ * @throws AppSearchException on IcingSearchEngine error or if can't advance on nextPageToken.
*/
@NonNull
- public SearchResultPage getNextPage(long nextPageToken)
+ public SearchResultPage getNextPage(@NonNull String packageName, long nextPageToken,
+ @Nullable SearchStats.Builder statsBuilder)
throws AppSearchException {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+
mReadWriteLock.readLock().lock();
try {
+ throwIfClosedLocked();
+
+ mLogUtil.piiTrace("getNextPage, request", nextPageToken);
+ checkNextPageToken(packageName, nextPageToken);
SearchResultProto searchResultProto = mIcingSearchEngineLocked.getNextPage(
nextPageToken);
+
+ if (statsBuilder != null) {
+ statsBuilder.setStatusCode(statusProtoToResultCode(searchResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(searchResultProto.getQueryStats(),
+ statsBuilder);
+ }
+
+ mLogUtil.piiTrace(
+ "getNextPage, response",
+ searchResultProto.getResultsCount(),
+ searchResultProto);
checkSuccess(searchResultProto.getStatus());
- return rewriteSearchResultProto(searchResultProto);
+ if (nextPageToken != EMPTY_PAGE_TOKEN
+ && searchResultProto.getNextPageToken() == EMPTY_PAGE_TOKEN) {
+ // At this point, we're guaranteed that this nextPageToken exists for this package,
+ // otherwise checkNextPageToken would've thrown an exception.
+ // Since the new token is 0, this is the last page. We should remove the old token
+ // from our cache since it no longer refers to this query.
+ synchronized (mNextPageTokensLocked) {
+ mNextPageTokensLocked.get(packageName).remove(nextPageToken);
+ }
+ }
+ long rewriteSearchResultLatencyStartMillis = SystemClock.elapsedRealtime();
+ SearchResultPage resultPage = rewriteSearchResultProto(searchResultProto,
+ mSchemaMapLocked);
+ if (statsBuilder != null) {
+ statsBuilder.setRewriteSearchResultLatencyMillis(
+ (int) (SystemClock.elapsedRealtime()
+ - rewriteSearchResultLatencyStartMillis));
+ }
+ return resultPage;
} finally {
mReadWriteLock.readLock().unlock();
+ if (statsBuilder != null) {
+ statsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis));
+ }
}
}
@@ -559,42 +1169,111 @@
*
* <p>This method belongs to query group.
*
+ * @param packageName Package name of the caller.
* @param nextPageToken The token of pre-loaded results of previously executed query to be
* Invalidated.
+ * @throws AppSearchException if nextPageToken is unusable.
*/
- public void invalidateNextPageToken(long nextPageToken) {
+ public void invalidateNextPageToken(@NonNull String packageName, long nextPageToken)
+ throws AppSearchException {
mReadWriteLock.readLock().lock();
try {
+ throwIfClosedLocked();
+
+ mLogUtil.piiTrace("invalidateNextPageToken, request", nextPageToken);
+ checkNextPageToken(packageName, nextPageToken);
mIcingSearchEngineLocked.invalidateNextPageToken(nextPageToken);
+
+ synchronized (mNextPageTokensLocked) {
+ // At this point, we're guaranteed that this nextPageToken exists for this package,
+ // otherwise checkNextPageToken would've thrown an exception.
+ mNextPageTokensLocked.get(packageName).remove(nextPageToken);
+ }
} finally {
mReadWriteLock.readLock().unlock();
}
}
- /**
- * Removes the given document by URI.
- *
- * <p>This method belongs to mutate group.
- *
- * @param packageName The package name that owns the document.
- * @param databaseName The databaseName the document is in.
- * @param namespace Namespace of the document to remove.
- * @param uri URI of the document to remove.
- * @throws AppSearchException on IcingSearchEngine error.
- */
- public void remove(@NonNull String packageName, @NonNull String databaseName,
+ /** Reports a usage of the given document at the given timestamp. */
+ public void reportUsage(
+ @NonNull String packageName,
+ @NonNull String databaseName,
@NonNull String namespace,
- @NonNull String uri) throws AppSearchException {
- String prefixedNamespace = createPrefix(packageName, databaseName) + namespace;
- DeleteResultProto deleteResultProto;
+ @NonNull String documentId,
+ long usageTimestampMillis,
+ boolean systemUsage) throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
- deleteResultProto = mIcingSearchEngineLocked.delete(prefixedNamespace, uri);
- checkForOptimizeLocked(/* force= */false);
+ throwIfClosedLocked();
+
+ String prefixedNamespace = createPrefix(packageName, databaseName) + namespace;
+ UsageReport.UsageType usageType = systemUsage
+ ? UsageReport.UsageType.USAGE_TYPE2 : UsageReport.UsageType.USAGE_TYPE1;
+ UsageReport report = UsageReport.newBuilder()
+ .setDocumentNamespace(prefixedNamespace)
+ .setDocumentUri(documentId)
+ .setUsageTimestampMs(usageTimestampMillis)
+ .setUsageType(usageType)
+ .build();
+
+ mLogUtil.piiTrace("reportUsage, request", report.getDocumentUri(), report);
+ ReportUsageResultProto result = mIcingSearchEngineLocked.reportUsage(report);
+ mLogUtil.piiTrace("reportUsage, response", result.getStatus(), result);
+ checkSuccess(result.getStatus());
} finally {
mReadWriteLock.writeLock().unlock();
}
- checkSuccess(deleteResultProto.getStatus());
+ }
+
+ /**
+ * Removes the given document by id.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @param packageName The package name that owns the document.
+ * @param databaseName The databaseName the document is in.
+ * @param namespace Namespace of the document to remove.
+ * @param id ID of the document to remove.
+ * @param removeStatsBuilder builder for {@link RemoveStats} to hold stats for remove
+ * @throws AppSearchException on IcingSearchEngine error.
+ */
+ public void remove(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull String namespace,
+ @NonNull String id,
+ @Nullable RemoveStats.Builder removeStatsBuilder) throws AppSearchException {
+ long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
+ mReadWriteLock.writeLock().lock();
+ try {
+ throwIfClosedLocked();
+
+ String prefixedNamespace = createPrefix(packageName, databaseName) + namespace;
+ if (mLogUtil.isPiiTraceEnabled()) {
+ mLogUtil.piiTrace("removeById, request", prefixedNamespace + ", " + id);
+ }
+ DeleteResultProto deleteResultProto =
+ mIcingSearchEngineLocked.delete(prefixedNamespace, id);
+ mLogUtil.piiTrace(
+ "removeById, response", deleteResultProto.getStatus(), deleteResultProto);
+
+ if (removeStatsBuilder != null) {
+ removeStatsBuilder.setStatusCode(statusProtoToResultCode(
+ deleteResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(deleteResultProto.getDeleteStats(),
+ removeStatsBuilder);
+ }
+ checkSuccess(deleteResultProto.getStatus());
+
+ // Update derived maps
+ updateDocumentCountAfterRemovalLocked(packageName, /*numDocumentsDeleted=*/ 1);
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ if (removeStatsBuilder != null) {
+ removeStatsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis));
+ }
+ }
}
/**
@@ -602,95 +1281,423 @@
*
* <p>This method belongs to mutate group.
*
- * @param packageName The package name that owns the documents.
- * @param databaseName The databaseName the document is in.
- * @param queryExpression Query String to search.
- * @param searchSpec Defines what and how to remove
+ * @param packageName The package name that owns the documents.
+ * @param databaseName The databaseName the document is in.
+ * @param queryExpression Query String to search.
+ * @param searchSpec Defines what and how to remove
+ * @param removeStatsBuilder builder for {@link RemoveStats} to hold stats for remove
* @throws AppSearchException on IcingSearchEngine error.
*/
public void removeByQuery(@NonNull String packageName, @NonNull String databaseName,
@NonNull String queryExpression,
- @NonNull SearchSpec searchSpec)
+ @NonNull SearchSpec searchSpec,
+ @Nullable RemoveStats.Builder removeStatsBuilder)
throws AppSearchException {
- SearchSpecProto searchSpecProto =
- SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
- SearchSpecProto.Builder searchSpecBuilder = searchSpecProto.toBuilder()
- .setQuery(queryExpression);
- DeleteByQueryResultProto deleteResultProto;
+ long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
mReadWriteLock.writeLock().lock();
try {
- // Only rewrite SearchSpec for non empty prefixes.
- // rewriteSearchSpecForPrefixesLocked will return false for empty prefixes, we
- // should skip sending request to Icing and return in here.
- if (!rewriteSearchSpecForPrefixesLocked(searchSpecBuilder,
- Collections.singleton(createPrefix(packageName, databaseName)))) {
+ throwIfClosedLocked();
+
+ List<String> filterPackageNames = searchSpec.getFilterPackageNames();
+ if (!filterPackageNames.isEmpty() && !filterPackageNames.contains(packageName)) {
+ // We're only removing documents within the parameter `packageName`. If we're not
+ // restricting our remove-query to this package name, then there's nothing for us to
+ // remove.
return;
}
- deleteResultProto = mIcingSearchEngineLocked.deleteByQuery(
- searchSpecBuilder.build());
- checkForOptimizeLocked(/* force= */true);
+
+ SearchSpecProto searchSpecProto =
+ SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
+ SearchSpecProto.Builder searchSpecBuilder = searchSpecProto.toBuilder()
+ .setQuery(queryExpression);
+
+ String prefix = createPrefix(packageName, databaseName);
+ Set<String> allowedPrefixedSchemas = getAllowedPrefixSchemasLocked(prefix, searchSpec);
+
+ // rewriteSearchSpecForPrefixesLocked will return false if there is nothing to search
+ // over given their search filters, so we can return early and skip sending request
+ // to Icing.
+ if (!rewriteSearchSpecForPrefixesLocked(searchSpecBuilder,
+ Collections.singleton(prefix), allowedPrefixedSchemas)) {
+ return;
+ }
+ SearchSpecProto finalSearchSpec = searchSpecBuilder.build();
+ mLogUtil.piiTrace("removeByQuery, request", finalSearchSpec);
+ DeleteByQueryResultProto deleteResultProto = mIcingSearchEngineLocked.deleteByQuery(
+ finalSearchSpec);
+ mLogUtil.piiTrace(
+ "removeByQuery, response", deleteResultProto.getStatus(), deleteResultProto);
+
+ if (removeStatsBuilder != null) {
+ removeStatsBuilder.setStatusCode(statusProtoToResultCode(
+ deleteResultProto.getStatus()));
+ // TODO(b/187206766) also log query stats here once IcingLib returns it
+ AppSearchLoggerHelper.copyNativeStats(deleteResultProto.getDeleteByQueryStats(),
+ removeStatsBuilder);
+ }
+
+ // It seems that the caller wants to get success if the data matching the query is
+ // not in the DB because it was not there or was successfully deleted.
+ checkCodeOneOf(deleteResultProto.getStatus(),
+ StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
+
+ // Update derived maps
+ int numDocumentsDeleted =
+ deleteResultProto.getDeleteByQueryStats().getNumDocumentsDeleted();
+ updateDocumentCountAfterRemovalLocked(packageName, numDocumentsDeleted);
} finally {
mReadWriteLock.writeLock().unlock();
+ if (removeStatsBuilder != null) {
+ removeStatsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis));
+ }
}
- // It seems that the caller wants to get success if the data matching the query is not in
- // the DB because it was not there or was successfully deleted.
- checkCodeOneOf(deleteResultProto.getStatus(),
- StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
+ }
+
+ @GuardedBy("mReadWriteLock")
+ private void updateDocumentCountAfterRemovalLocked(
+ @NonNull String packageName, int numDocumentsDeleted) {
+ if (numDocumentsDeleted > 0) {
+ Integer oldDocumentCount = mDocumentCountMapLocked.get(packageName);
+ // This should always be true: how can we delete documents for a package without
+ // having seen that package during init? This is just a safeguard.
+ if (oldDocumentCount != null) {
+ // This should always be >0; how can we remove more documents than we've indexed?
+ // This is just a safeguard.
+ int newDocumentCount = Math.max(oldDocumentCount - numDocumentsDeleted, 0);
+ mDocumentCountMapLocked.put(packageName, newDocumentCount);
+ }
+ }
+ }
+
+ /** Estimates the storage usage info for a specific package. */
+ @NonNull
+ public StorageInfo getStorageInfoForPackage(@NonNull String packageName)
+ throws AppSearchException {
+ mReadWriteLock.readLock().lock();
+ try {
+ throwIfClosedLocked();
+
+ Map<String, Set<String>> packageToDatabases = getPackageToDatabases();
+ Set<String> databases = packageToDatabases.get(packageName);
+ if (databases == null) {
+ // Package doesn't exist, no storage info to report
+ return new StorageInfo.Builder().build();
+ }
+
+ // Accumulate all the namespaces we're interested in.
+ Set<String> wantedPrefixedNamespaces = new ArraySet<>();
+ for (String database : databases) {
+ Set<String> prefixedNamespaces = mNamespaceMapLocked.get(createPrefix(packageName,
+ database));
+ if (prefixedNamespaces != null) {
+ wantedPrefixedNamespaces.addAll(prefixedNamespaces);
+ }
+ }
+ if (wantedPrefixedNamespaces.isEmpty()) {
+ return new StorageInfo.Builder().build();
+ }
+
+ return getStorageInfoForNamespaces(getRawStorageInfoProto(),
+ wantedPrefixedNamespaces);
+ } finally {
+ mReadWriteLock.readLock().unlock();
+ }
+ }
+
+ /** Estimates the storage usage info for a specific database in a package. */
+ @NonNull
+ public StorageInfo getStorageInfoForDatabase(@NonNull String packageName,
+ @NonNull String databaseName)
+ throws AppSearchException {
+ mReadWriteLock.readLock().lock();
+ try {
+ throwIfClosedLocked();
+
+ Map<String, Set<String>> packageToDatabases = getPackageToDatabases();
+ Set<String> databases = packageToDatabases.get(packageName);
+ if (databases == null) {
+ // Package doesn't exist, no storage info to report
+ return new StorageInfo.Builder().build();
+ }
+ if (!databases.contains(databaseName)) {
+ // Database doesn't exist, no storage info to report
+ return new StorageInfo.Builder().build();
+ }
+
+ Set<String> wantedPrefixedNamespaces =
+ mNamespaceMapLocked.get(createPrefix(packageName, databaseName));
+ if (wantedPrefixedNamespaces == null || wantedPrefixedNamespaces.isEmpty()) {
+ return new StorageInfo.Builder().build();
+ }
+
+ return getStorageInfoForNamespaces(getRawStorageInfoProto(),
+ wantedPrefixedNamespaces);
+ } finally {
+ mReadWriteLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Returns the native storage info capsuled in {@link StorageInfoResultProto} directly from
+ * IcingSearchEngine.
+ */
+ @NonNull
+ public StorageInfoProto getRawStorageInfoProto() throws AppSearchException {
+ mReadWriteLock.readLock().lock();
+ try {
+ throwIfClosedLocked();
+ mLogUtil.piiTrace("getStorageInfo, request");
+ StorageInfoResultProto storageInfoResult = mIcingSearchEngineLocked.getStorageInfo();
+ mLogUtil.piiTrace("getStorageInfo, response", storageInfoResult.getStatus(),
+ storageInfoResult);
+ checkSuccess(storageInfoResult.getStatus());
+ return storageInfoResult.getStorageInfo();
+ } finally {
+ mReadWriteLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Extracts and returns {@link StorageInfo} from {@link StorageInfoProto} based on
+ * prefixed namespaces.
+ */
+ @NonNull
+ private static StorageInfo getStorageInfoForNamespaces(
+ @NonNull StorageInfoProto storageInfoProto,
+ @NonNull Set<String> prefixedNamespaces) {
+ if (!storageInfoProto.hasDocumentStorageInfo()) {
+ return new StorageInfo.Builder().build();
+ }
+
+ long totalStorageSize = storageInfoProto.getTotalStorageSize();
+ DocumentStorageInfoProto documentStorageInfo =
+ storageInfoProto.getDocumentStorageInfo();
+ int totalDocuments =
+ documentStorageInfo.getNumAliveDocuments()
+ + documentStorageInfo.getNumExpiredDocuments();
+
+ if (totalStorageSize == 0 || totalDocuments == 0) {
+ // Maybe we can exit early and also avoid a divide by 0 error.
+ return new StorageInfo.Builder().build();
+ }
+
+ // Accumulate stats across the package's namespaces.
+ int aliveDocuments = 0;
+ int expiredDocuments = 0;
+ int aliveNamespaces = 0;
+ List<NamespaceStorageInfoProto> namespaceStorageInfos =
+ documentStorageInfo.getNamespaceStorageInfoList();
+ for (int i = 0; i < namespaceStorageInfos.size(); i++) {
+ NamespaceStorageInfoProto namespaceStorageInfo = namespaceStorageInfos.get(i);
+ // The namespace from icing lib is already the prefixed format
+ if (prefixedNamespaces.contains(namespaceStorageInfo.getNamespace())) {
+ if (namespaceStorageInfo.getNumAliveDocuments() > 0) {
+ aliveNamespaces++;
+ aliveDocuments += namespaceStorageInfo.getNumAliveDocuments();
+ }
+ expiredDocuments += namespaceStorageInfo.getNumExpiredDocuments();
+ }
+ }
+ int namespaceDocuments = aliveDocuments + expiredDocuments;
+
+ // Since we don't have the exact size of all the documents, we do an estimation. Note
+ // that while the total storage takes into account schema, index, etc. in addition to
+ // documents, we'll only calculate the percentage based on number of documents a
+ // client has.
+ return new StorageInfo.Builder()
+ .setSizeBytes((long) (namespaceDocuments * 1.0 / totalDocuments * totalStorageSize))
+ .setAliveDocumentsCount(aliveDocuments)
+ .setAliveNamespacesCount(aliveNamespaces)
+ .build();
}
/**
* Persists all update/delete requests to the disk.
*
- * <p>If the app crashes after a call to PersistToDisk(), Icing would be able to fully recover
- * all data written up to this point without a costly recovery process.
+ * <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#FULL}, Icing
+ * would be able to fully recover all data written up to this point without a costly recovery
+ * process.
*
- * <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly
- * recovery process in next initialization. After that, Icing would still be able to recover
- * all written data.
+ * <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#LITE}, Icing
+ * would trigger a costly recovery process in next initialization. After that, Icing would still
+ * be able to recover all written data - excepting Usage data. Usage data is only guaranteed
+ * to be safe after a call to PersistToDisk with {@link PersistType.Code#FULL}
+ *
+ * <p>If the app crashes after an update/delete request has been made, but before any call to
+ * PersistToDisk, then all data in Icing will be lost.
+ *
+ * @param persistType the amount of data to persist. {@link PersistType.Code#LITE} will only
+ * persist the minimal amount of data to ensure all data can be recovered.
+ * {@link PersistType.Code#FULL} will persist all data necessary to
+ * prevent data loss without needing data recovery.
+ * @throws AppSearchException on any error that AppSearch persist data to disk.
*/
- public void persistToDisk() throws AppSearchException {
- PersistToDiskResultProto persistToDiskResultProto =
- mIcingSearchEngineLocked.persistToDisk();
- checkSuccess(persistToDiskResultProto.getStatus());
+ public void persistToDisk(@NonNull PersistType.Code persistType) throws AppSearchException {
+ mReadWriteLock.writeLock().lock();
+ try {
+ throwIfClosedLocked();
+
+ mLogUtil.piiTrace("persistToDisk, request", persistType);
+ PersistToDiskResultProto persistToDiskResultProto =
+ mIcingSearchEngineLocked.persistToDisk(persistType);
+ mLogUtil.piiTrace(
+ "persistToDisk, response",
+ persistToDiskResultProto.getStatus(),
+ persistToDiskResultProto);
+ checkSuccess(persistToDiskResultProto.getStatus());
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
}
+ /**
+ * Remove all {@link AppSearchSchema}s and {@link GenericDocument}s under the given package.
+ *
+ * @param packageName The name of package to be removed.
+ * @throws AppSearchException if we cannot remove the data.
+ */
+ public void clearPackageData(@NonNull String packageName) throws AppSearchException {
+ mReadWriteLock.writeLock().lock();
+ try {
+ throwIfClosedLocked();
+ Set<String> existingPackages = getPackageToDatabases().keySet();
+ if (existingPackages.contains(packageName)) {
+ existingPackages.remove(packageName);
+ prunePackageData(existingPackages);
+ }
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Remove all {@link AppSearchSchema}s and {@link GenericDocument}s that doesn't belong to any
+ * of the given installed packages
+ *
+ * @param installedPackages The name of all installed package.
+ * @throws AppSearchException if we cannot remove the data.
+ */
+ public void prunePackageData(@NonNull Set<String> installedPackages) throws AppSearchException {
+ mReadWriteLock.writeLock().lock();
+ try {
+ throwIfClosedLocked();
+ Map<String, Set<String>> packageToDatabases = getPackageToDatabases();
+ if (installedPackages.containsAll(packageToDatabases.keySet())) {
+ // No package got removed. We are good.
+ return;
+ }
+
+ // Prune schema proto
+ SchemaProto existingSchema = getSchemaProtoLocked();
+ SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
+ for (int i = 0; i < existingSchema.getTypesCount(); i++) {
+ String packageName = getPackageName(existingSchema.getTypes(i).getSchemaType());
+ if (installedPackages.contains(packageName)) {
+ newSchemaBuilder.addTypes(existingSchema.getTypes(i));
+ }
+ }
+
+ SchemaProto finalSchema = newSchemaBuilder.build();
+
+ // Apply schema, set force override to true to remove all schemas and documents that
+ // doesn't belong to any of these installed packages.
+ mLogUtil.piiTrace(
+ "clearPackageData.setSchema, request",
+ finalSchema.getTypesCount(),
+ finalSchema);
+ SetSchemaResultProto setSchemaResultProto = mIcingSearchEngineLocked.setSchema(
+ finalSchema, /*ignoreErrorsAndDeleteDocuments=*/ true);
+ mLogUtil.piiTrace(
+ "clearPackageData.setSchema, response",
+ setSchemaResultProto.getStatus(),
+ setSchemaResultProto);
+
+ // Determine whether it succeeded.
+ checkSuccess(setSchemaResultProto.getStatus());
+
+ // Prune cached maps
+ for (Map.Entry<String, Set<String>> entry : packageToDatabases.entrySet()) {
+ String packageName = entry.getKey();
+ Set<String> databaseNames = entry.getValue();
+ if (!installedPackages.contains(packageName) && databaseNames != null) {
+ mDocumentCountMapLocked.remove(packageName);
+ synchronized (mNextPageTokensLocked) {
+ mNextPageTokensLocked.remove(packageName);
+ }
+ for (String databaseName : databaseNames) {
+ String removedPrefix = createPrefix(packageName, databaseName);
+ mSchemaMapLocked.remove(removedPrefix);
+ mNamespaceMapLocked.remove(removedPrefix);
+ }
+ }
+ }
+ //TODO(b/145759910) clear visibility setting for package.
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
/**
* Clears documents and schema across all packages and databaseNames.
*
- * <p>This method also clear all data in {@link VisibilityStore}, an
- * {@link #initializeVisibilityStore()} must be called after this.
- *
* <p>This method belongs to mutate group.
*
* @throws AppSearchException on IcingSearchEngine error.
*/
- private void reset() throws AppSearchException {
- ResetResultProto resetResultProto;
- mReadWriteLock.writeLock().lock();
- try {
- resetResultProto = mIcingSearchEngineLocked.reset();
- mOptimizeIntervalCountLocked = 0;
- mSchemaMapLocked.clear();
- mNamespaceMapLocked.clear();
-
- // Must be called after everything else since VisibilityStore may repopulate
- // IcingSearchEngine with an initial schema.
- mVisibilityStoreLocked.handleReset();
- } finally {
- mReadWriteLock.writeLock().unlock();
+ @GuardedBy("mReadWriteLock")
+ private void resetLocked(@Nullable InitializeStats.Builder initStatsBuilder)
+ throws AppSearchException {
+ mLogUtil.piiTrace("icingSearchEngine.reset, request");
+ ResetResultProto resetResultProto = mIcingSearchEngineLocked.reset();
+ mLogUtil.piiTrace(
+ "icingSearchEngine.reset, response",
+ resetResultProto.getStatus(),
+ resetResultProto);
+ mOptimizeIntervalCountLocked = 0;
+ mSchemaMapLocked.clear();
+ mNamespaceMapLocked.clear();
+ mDocumentCountMapLocked.clear();
+ synchronized (mNextPageTokensLocked) {
+ mNextPageTokensLocked.clear();
}
+ if (initStatsBuilder != null) {
+ initStatsBuilder
+ .setHasReset(true)
+ .setResetStatusCode(statusProtoToResultCode(resetResultProto.getStatus()));
+ }
+
checkSuccess(resetResultProto.getStatus());
}
+ @GuardedBy("mReadWriteLock")
+ private void rebuildDocumentCountMapLocked(@NonNull StorageInfoProto storageInfoProto) {
+ mDocumentCountMapLocked.clear();
+ List<NamespaceStorageInfoProto> namespaceStorageInfoProtoList =
+ storageInfoProto.getDocumentStorageInfo().getNamespaceStorageInfoList();
+ for (int i = 0; i < namespaceStorageInfoProtoList.size(); i++) {
+ NamespaceStorageInfoProto namespaceStorageInfoProto =
+ namespaceStorageInfoProtoList.get(i);
+ String packageName = getPackageName(namespaceStorageInfoProto.getNamespace());
+ Integer oldCount = mDocumentCountMapLocked.get(packageName);
+ int newCount;
+ if (oldCount == null) {
+ newCount = namespaceStorageInfoProto.getNumAliveDocuments();
+ } else {
+ newCount = oldCount + namespaceStorageInfoProto.getNumAliveDocuments();
+ }
+ mDocumentCountMapLocked.put(packageName, newCount);
+ }
+ }
+
/** Wrapper around schema changes */
@VisibleForTesting
static class RewrittenSchemaResults {
// Any prefixed types that used to exist in the schema, but are deleted in the new one.
final Set<String> mDeletedPrefixedTypes = new ArraySet<>();
- // Prefixed types that were part of the new schema.
- final Set<String> mRewrittenPrefixedTypes = new ArraySet<>();
+ // Map of prefixed schema types to SchemaTypeConfigProtos that were part of the new schema.
+ final Map<String, SchemaTypeConfigProto> mRewrittenPrefixedTypes = new ArrayMap<>();
}
/**
@@ -738,7 +1745,7 @@
// newTypesToProto is modified below, so we need a copy first
RewrittenSchemaResults rewrittenSchemaResults = new RewrittenSchemaResults();
- rewrittenSchemaResults.mRewrittenPrefixedTypes.addAll(newTypesToProto.keySet());
+ rewrittenSchemaResults.mRewrittenPrefixedTypes.putAll(newTypesToProto);
// Combine the existing schema (which may have types from other prefixes) with this
// prefix's new schema. Modifies the existingSchemaBuilder.
@@ -764,107 +1771,24 @@
}
/**
- * Prepends {@code prefix} to all types and namespaces mentioned anywhere in
- * {@code documentBuilder}.
+ * Rewrites the search spec filters with {@code prefixes}.
*
- * @param documentBuilder The document to mutate
- * @param prefix The prefix to add
- */
- @VisibleForTesting
- static void addPrefixToDocument(
- @NonNull DocumentProto.Builder documentBuilder,
- @NonNull String prefix) {
- // Rewrite the type name to include/remove the prefix.
- String newSchema = prefix + documentBuilder.getSchema();
- documentBuilder.setSchema(newSchema);
-
- // Rewrite the namespace to include/remove the prefix.
- documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- addPrefixToDocument(derivedDocumentBuilder, prefix);
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
- }
-
- /**
- * Removes any prefixes from types and namespaces mentioned anywhere in
- * {@code documentBuilder}.
- *
- * @param documentBuilder The document to mutate
- * @return Prefix name that was removed from the document.
- * @throws AppSearchException if there are unexpected database prefixing errors.
- */
- @NonNull
- @VisibleForTesting
- static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
- throws AppSearchException {
- // Rewrite the type name and namespace to remove the prefix.
- String schemaPrefix = getPrefix(documentBuilder.getSchema());
- String namespacePrefix = getPrefix(documentBuilder.getNamespace());
-
- if (!schemaPrefix.equals(namespacePrefix)) {
- throw new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR, "Found unexpected"
- + " multiple prefix names in document: " + schemaPrefix + ", "
- + namespacePrefix);
- }
-
- documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
- documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
- if (!nestedPrefix.equals(schemaPrefix)) {
- throw new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR,
- "Found unexpected multiple prefix names in document: "
- + schemaPrefix + ", " + nestedPrefix);
- }
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
-
- return schemaPrefix;
- }
-
- /**
- * Rewrites the schemaTypeFilters and namespacesFilters that exist with {@code prefixes}.
- *
- * <p>If the searchSpec has empty filter lists, all prefixes filters will be added.
* <p>This method should be only called in query methods and get the READ lock to keep thread
* safety.
*
- * @return false if none of the requested prefixes exist.
+ * @param searchSpecBuilder Client-provided SearchSpec
+ * @param prefixes Prefixes that we should prepend to all our filters
+ * @param allowedPrefixedSchemas Prefixed schemas that the client is allowed to query over. This
+ * supersedes the schema filters that may exist on the {@code
+ * searchSpecBuilder}.
+ * @return false if none there would be nothing to search over.
*/
@VisibleForTesting
@GuardedBy("mReadWriteLock")
boolean rewriteSearchSpecForPrefixesLocked(
@NonNull SearchSpecProto.Builder searchSpecBuilder,
- @NonNull Set<String> prefixes) {
+ @NonNull Set<String> prefixes,
+ @NonNull Set<String> allowedPrefixedSchemas) {
// Create a copy since retainAll() modifies the original set.
Set<String> existingPrefixes = new ArraySet<>(mNamespaceMapLocked.keySet());
existingPrefixes.retainAll(prefixes);
@@ -874,39 +1798,40 @@
return false;
}
- // Cache the schema type filters and namespaces before clearing everything.
- List<String> schemaTypeFilters = searchSpecBuilder.getSchemaTypeFiltersList();
- searchSpecBuilder.clearSchemaTypeFilters();
+ if (allowedPrefixedSchemas.isEmpty()) {
+ // Not allowed to search over any schemas, empty query.
+ return false;
+ }
+ // Clear the schema type filters since we'll be rewriting them with the
+ // allowedPrefixedSchemas.
+ searchSpecBuilder.clearSchemaTypeFilters();
+ searchSpecBuilder.addAllSchemaTypeFilters(allowedPrefixedSchemas);
+
+ // Cache the namespaces before clearing everything.
List<String> namespaceFilters = searchSpecBuilder.getNamespaceFiltersList();
searchSpecBuilder.clearNamespaceFilters();
- // Rewrite filters to include a prefix.
+ // Rewrite non-schema filters to include a prefix.
for (String prefix : existingPrefixes) {
- Set<String> existingSchemaTypes = mSchemaMapLocked.get(prefix);
- if (schemaTypeFilters.isEmpty()) {
- // Include all schema types
- searchSpecBuilder.addAllSchemaTypeFilters(existingSchemaTypes);
- } else {
- // Add the prefix to the given schema types
- for (int i = 0; i < schemaTypeFilters.size(); i++) {
- String prefixedType = prefix + schemaTypeFilters.get(i);
- if (existingSchemaTypes.contains(prefixedType)) {
- searchSpecBuilder.addSchemaTypeFilters(prefixedType);
- }
- }
- }
+ // TODO(b/169883602): We currently grab every namespace for every prefix. We can
+ // optimize this by checking if a prefix has any allowedSchemaTypes. If not, that
+ // means we don't want to query over anything in that prefix anyways, so we don't
+ // need to grab its namespaces either.
+ // Empty namespaces on the search spec means to query over all namespaces.
Set<String> existingNamespaces = mNamespaceMapLocked.get(prefix);
- if (namespaceFilters.isEmpty()) {
- // Include all namespaces
- searchSpecBuilder.addAllNamespaceFilters(existingNamespaces);
- } else {
- // Prefix the given namespaces.
- for (int i = 0; i < namespaceFilters.size(); i++) {
- String prefixedNamespace = prefix + namespaceFilters.get(i);
- if (existingNamespaces.contains(prefixedNamespace)) {
- searchSpecBuilder.addNamespaceFilters(prefixedNamespace);
+ if (existingNamespaces != null) {
+ if (namespaceFilters.isEmpty()) {
+ // Include all namespaces
+ searchSpecBuilder.addAllNamespaceFilters(existingNamespaces);
+ } else {
+ // Prefix the given namespaces.
+ for (int i = 0; i < namespaceFilters.size(); i++) {
+ String prefixedNamespace = prefix + namespaceFilters.get(i);
+ if (existingNamespaces.contains(prefixedNamespace)) {
+ searchSpecBuilder.addNamespaceFilters(prefixedNamespace);
+ }
}
}
}
@@ -916,31 +1841,55 @@
}
/**
+ * Returns the set of allowed prefixed schemas that the {@code prefix} can query while taking
+ * into account the {@code searchSpec} schema filters.
+ *
+ * <p>This only checks intersection of schema filters on the search spec with those that the
+ * prefix owns itself. This does not check global query permissions.
+ */
+ @GuardedBy("mReadWriteLock")
+ private Set<String> getAllowedPrefixSchemasLocked(@NonNull String prefix,
+ @NonNull SearchSpec searchSpec) {
+ Set<String> allowedPrefixedSchemas = new ArraySet<>();
+
+ // Add all the schema filters the client specified.
+ List<String> schemaFilters = searchSpec.getFilterSchemas();
+ for (int i = 0; i < schemaFilters.size(); i++) {
+ allowedPrefixedSchemas.add(prefix + schemaFilters.get(i));
+ }
+
+ if (allowedPrefixedSchemas.isEmpty()) {
+ // If the client didn't specify any schema filters, search over all of their schemas
+ Map<String, SchemaTypeConfigProto> prefixedSchemaMap = mSchemaMapLocked.get(prefix);
+ if (prefixedSchemaMap != null) {
+ allowedPrefixedSchemas.addAll(prefixedSchemaMap.keySet());
+ }
+ }
+ return allowedPrefixedSchemas;
+ }
+
+ /**
* Rewrites the typePropertyMasks that exist in {@code prefixes}.
*
* <p>This method should be only called in query methods and get the READ lock to keep thread
* safety.
*
- * @return false if none of the requested prefixes exist.
+ * @param resultSpecBuilder ResultSpecs as specified by client
+ * @param prefixes Prefixes that we should prepend to all our filters
+ * @param allowedPrefixedSchemas Prefixed schemas that the client is allowed to query over.
*/
@VisibleForTesting
@GuardedBy("mReadWriteLock")
- boolean rewriteResultSpecForPrefixesLocked(
+ void rewriteResultSpecForPrefixesLocked(
@NonNull ResultSpecProto.Builder resultSpecBuilder,
- @NonNull Set<String> prefixes) {
+ @NonNull Set<String> prefixes, @NonNull Set<String> allowedPrefixedSchemas) {
// Create a copy since retainAll() modifies the original set.
Set<String> existingPrefixes = new ArraySet<>(mNamespaceMapLocked.keySet());
existingPrefixes.retainAll(prefixes);
- if (existingPrefixes.isEmpty()) {
- // None of the prefixes exist, empty query.
- return false;
- }
-
List<TypePropertyMask> prefixedTypePropertyMasks = new ArrayList<>();
// Rewrite filters to include a database prefix.
for (String prefix : existingPrefixes) {
- Set<String> existingSchemaTypes = mSchemaMapLocked.get(prefix);
// Qualify the given schema types
for (TypePropertyMask typePropertyMask :
resultSpecBuilder.getTypePropertyMasksList()) {
@@ -948,7 +1897,7 @@
boolean isWildcard =
unprefixedType.equals(SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD);
String prefixedType = isWildcard ? unprefixedType : prefix + unprefixedType;
- if (isWildcard || existingSchemaTypes.contains(prefixedType)) {
+ if (isWildcard || allowedPrefixedSchemas.contains(prefixedType)) {
prefixedTypePropertyMasks.add(
typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
}
@@ -956,94 +1905,201 @@
}
resultSpecBuilder.clearTypePropertyMasks().addAllTypePropertyMasks(
prefixedTypePropertyMasks);
- return true;
+ }
+
+ /**
+ * Adds result groupings for each namespace in each package being queried for.
+ *
+ * <p>This method should be only called in query methods and get the READ lock to keep thread
+ * safety.
+ *
+ * @param resultSpecBuilder ResultSpecs as specified by client
+ * @param prefixes Prefixes that we should prepend to all our filters
+ * @param maxNumResults The maximum number of results for each grouping to support.
+ */
+ @GuardedBy("mReadWriteLock")
+ private void addPerPackagePerNamespaceResultGroupingsLocked(
+ @NonNull ResultSpecProto.Builder resultSpecBuilder,
+ @NonNull Set<String> prefixes, int maxNumResults) {
+ Set<String> existingPrefixes = new ArraySet<>(mNamespaceMapLocked.keySet());
+ existingPrefixes.retainAll(prefixes);
+
+ // Create a map for package+namespace to prefixedNamespaces. This is NOT necessarily the
+ // same as the list of namespaces. If one package has multiple databases, each with the same
+ // namespace, then those should be grouped together.
+ Map<String, List<String>> packageAndNamespaceToNamespaces = new ArrayMap<>();
+ for (String prefix : existingPrefixes) {
+ Set<String> prefixedNamespaces = mNamespaceMapLocked.get(prefix);
+ if (prefixedNamespaces == null) {
+ continue;
+ }
+ String packageName = getPackageName(prefix);
+ // Create a new prefix without the database name. This will allow us to group namespaces
+ // that have the same name and package but a different database name together.
+ String emptyDatabasePrefix = createPrefix(packageName, /*databaseName*/"");
+ for (String prefixedNamespace : prefixedNamespaces) {
+ String namespace;
+ try {
+ namespace = removePrefix(prefixedNamespace);
+ } catch (AppSearchException e) {
+ // This should never happen. Skip this namespace if it does.
+ Log.e(TAG, "Prefixed namespace " + prefixedNamespace + " is malformed.");
+ continue;
+ }
+ String emptyDatabasePrefixedNamespace = emptyDatabasePrefix + namespace;
+ List<String> namespaceList =
+ packageAndNamespaceToNamespaces.get(emptyDatabasePrefixedNamespace);
+ if (namespaceList == null) {
+ namespaceList = new ArrayList<>();
+ packageAndNamespaceToNamespaces.put(emptyDatabasePrefixedNamespace,
+ namespaceList);
+ }
+ namespaceList.add(prefixedNamespace);
+ }
+ }
+
+ for (List<String> namespaces : packageAndNamespaceToNamespaces.values()) {
+ resultSpecBuilder.addResultGroupings(
+ ResultSpecProto.ResultGrouping.newBuilder()
+ .addAllNamespaces(namespaces).setMaxResults(maxNumResults));
+ }
+ }
+
+ /**
+ * Adds result groupings for each package being queried for.
+ *
+ * <p>This method should be only called in query methods and get the READ lock to keep thread
+ * safety.
+ *
+ * @param resultSpecBuilder ResultSpecs as specified by client
+ * @param prefixes Prefixes that we should prepend to all our filters
+ * @param maxNumResults The maximum number of results for each grouping to support.
+ */
+ @GuardedBy("mReadWriteLock")
+ private void addPerPackageResultGroupingsLocked(
+ @NonNull ResultSpecProto.Builder resultSpecBuilder,
+ @NonNull Set<String> prefixes, int maxNumResults) {
+ Set<String> existingPrefixes = new ArraySet<>(mNamespaceMapLocked.keySet());
+ existingPrefixes.retainAll(prefixes);
+
+ // Build up a map of package to namespaces.
+ Map<String, List<String>> packageToNamespacesMap = new ArrayMap<>();
+ for (String prefix : existingPrefixes) {
+ Set<String> prefixedNamespaces = mNamespaceMapLocked.get(prefix);
+ if (prefixedNamespaces == null) {
+ continue;
+ }
+ String packageName = getPackageName(prefix);
+ List<String> packageNamespaceList = packageToNamespacesMap.get(packageName);
+ if (packageNamespaceList == null) {
+ packageNamespaceList = new ArrayList<>();
+ packageToNamespacesMap.put(packageName, packageNamespaceList);
+ }
+ packageNamespaceList.addAll(prefixedNamespaces);
+ }
+
+ for (List<String> prefixedNamespaces : packageToNamespacesMap.values()) {
+ resultSpecBuilder.addResultGroupings(
+ ResultSpecProto.ResultGrouping.newBuilder()
+ .addAllNamespaces(prefixedNamespaces).setMaxResults(maxNumResults));
+ }
+ }
+
+ /**
+ * Adds result groupings for each namespace being queried for.
+ *
+ * <p>This method should be only called in query methods and get the READ lock to keep thread
+ * safety.
+ *
+ * @param resultSpecBuilder ResultSpecs as specified by client
+ * @param prefixes Prefixes that we should prepend to all our filters
+ * @param maxNumResults The maximum number of results for each grouping to support.
+ */
+ @GuardedBy("mReadWriteLock")
+ private void addPerNamespaceResultGroupingsLocked(
+ @NonNull ResultSpecProto.Builder resultSpecBuilder,
+ @NonNull Set<String> prefixes, int maxNumResults) {
+ Set<String> existingPrefixes = new ArraySet<>(mNamespaceMapLocked.keySet());
+ existingPrefixes.retainAll(prefixes);
+
+ // Create a map of namespace to prefixedNamespaces. This is NOT necessarily the
+ // same as the list of namespaces. If a namespace exists under different packages and/or
+ // different databases, they should still be grouped together.
+ Map<String, List<String>> namespaceToPrefixedNamespaces = new ArrayMap<>();
+ for (String prefix : existingPrefixes) {
+ Set<String> prefixedNamespaces = mNamespaceMapLocked.get(prefix);
+ if (prefixedNamespaces == null) {
+ continue;
+ }
+ for (String prefixedNamespace : prefixedNamespaces) {
+ String namespace;
+ try {
+ namespace = removePrefix(prefixedNamespace);
+ } catch (AppSearchException e) {
+ // This should never happen. Skip this namespace if it does.
+ Log.e(TAG, "Prefixed namespace " + prefixedNamespace + " is malformed.");
+ continue;
+ }
+ List<String> groupedPrefixedNamespaces =
+ namespaceToPrefixedNamespaces.get(namespace);
+ if (groupedPrefixedNamespaces == null) {
+ groupedPrefixedNamespaces = new ArrayList<>();
+ namespaceToPrefixedNamespaces.put(namespace,
+ groupedPrefixedNamespaces);
+ }
+ groupedPrefixedNamespaces.add(prefixedNamespace);
+ }
+ }
+
+ for (List<String> namespaces : namespaceToPrefixedNamespaces.values()) {
+ resultSpecBuilder.addResultGroupings(
+ ResultSpecProto.ResultGrouping.newBuilder()
+ .addAllNamespaces(namespaces).setMaxResults(maxNumResults));
+ }
}
@VisibleForTesting
@GuardedBy("mReadWriteLock")
SchemaProto getSchemaProtoLocked() throws AppSearchException {
+ mLogUtil.piiTrace("getSchema, request");
GetSchemaResultProto schemaProto = mIcingSearchEngineLocked.getSchema();
+ mLogUtil.piiTrace("getSchema, response", schemaProto.getStatus(), schemaProto);
// TODO(b/161935693) check GetSchemaResultProto is success or not. Call reset() if it's not.
// TODO(b/161935693) only allow GetSchemaResultProto NOT_FOUND on first run
checkCodeOneOf(schemaProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
return schemaProto.getSchema();
}
- /**
- * Returns true if the {@code packageName} and {@code databaseName} has the
- * {@code schemaType}
- */
- @GuardedBy("mReadWriteLock")
- boolean hasSchemaTypeLocked(@NonNull String packageName, @NonNull String databaseName,
- @NonNull String schemaType) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(schemaType);
-
- String prefix = createPrefix(packageName, databaseName);
- Set<String> schemaTypes = mSchemaMapLocked.get(prefix);
- if (schemaTypes == null) {
- return false;
+ private void addNextPageToken(String packageName, long nextPageToken) {
+ if (nextPageToken == EMPTY_PAGE_TOKEN) {
+ // There is no more pages. No need to add it.
+ return;
}
-
- return schemaTypes.contains(prefix + schemaType);
- }
-
- /** Returns a set of all prefixes AppSearchImpl knows about. */
- @GuardedBy("mReadWriteLock")
- @NonNull
- Set<String> getPrefixesLocked() {
- return mSchemaMapLocked.keySet();
- }
-
- @NonNull
- static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
- return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
- }
-
- /**
- * Returns the package name that's contained within the {@code prefix}.
- *
- * @param prefix Prefix string that contains the package name inside of it. The package name
- * must be in the front of the string, and separated from the rest of the
- * string by the {@link #PACKAGE_DELIMITER}.
- * @return Valid package name.
- */
- @NonNull
- private static String getPackageName(@NonNull String prefix) {
- int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
- if (delimiterIndex == -1) {
- // This should never happen if we construct our prefixes properly
- Log.wtf(TAG, "Malformed prefix doesn't contain package name: " + prefix);
- return "";
+ synchronized (mNextPageTokensLocked) {
+ Set<Long> tokens = mNextPageTokensLocked.get(packageName);
+ if (tokens == null) {
+ tokens = new ArraySet<>();
+ mNextPageTokensLocked.put(packageName, tokens);
+ }
+ tokens.add(nextPageToken);
}
- return prefix.substring(0, delimiterIndex);
}
- @NonNull
- private static String removePrefix(@NonNull String prefixedString)
+ private void checkNextPageToken(String packageName, long nextPageToken)
throws AppSearchException {
- // The prefix is made up of the package, then the database. So we only need to find the
- // database cutoff.
- int delimiterIndex;
- if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
- // Add 1 to include the char size of the DATABASE_DELIMITER
- return prefixedString.substring(delimiterIndex + 1);
+ if (nextPageToken == EMPTY_PAGE_TOKEN) {
+ // Swallow the check for empty page token, token = 0 means there is no more page and it
+ // won't return anything from Icing.
+ return;
}
- throw new AppSearchException(AppSearchResult.RESULT_UNKNOWN_ERROR,
- "The prefixed value doesn't contains a valid database name.");
- }
-
- @NonNull
- private static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
- int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
- if (databaseDelimiterIndex == -1) {
- throw new AppSearchException(AppSearchResult.RESULT_UNKNOWN_ERROR,
- "The databaseName prefixed value doesn't contain a valid database name.");
+ synchronized (mNextPageTokensLocked) {
+ Set<Long> nextPageTokens = mNextPageTokensLocked.get(packageName);
+ if (nextPageTokens == null || !nextPageTokens.contains(nextPageToken)) {
+ throw new AppSearchException(AppSearchResult.RESULT_SECURITY_ERROR,
+ "Package \"" + packageName + "\" cannot use nextPageToken: "
+ + nextPageToken);
+ }
}
-
- // Add 1 to include the char size of the DATABASE_DELIMITER
- return prefixedString.substring(0, databaseDelimiterIndex + 1);
}
private static void addToMap(Map<String, Set<String>> map, String prefix,
@@ -1056,6 +2112,24 @@
values.add(prefixedValue);
}
+ private static void addToMap(Map<String, Map<String, SchemaTypeConfigProto>> map, String prefix,
+ SchemaTypeConfigProto schemaTypeConfigProto) {
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
+ if (schemaTypeMap == null) {
+ schemaTypeMap = new ArrayMap<>();
+ map.put(prefix, schemaTypeMap);
+ }
+ schemaTypeMap.put(schemaTypeConfigProto.getSchemaType(), schemaTypeConfigProto);
+ }
+
+ private static void removeFromMap(Map<String, Map<String, SchemaTypeConfigProto>> map,
+ String prefix, String schemaType) {
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
+ if (schemaTypeMap != null) {
+ schemaTypeMap.remove(schemaType);
+ }
+ }
+
/**
* Checks the given status code and throws an {@link AppSearchException} if code is an error.
*
@@ -1085,40 +2159,86 @@
return;
}
- throw statusProtoToAppSearchException(statusProto);
+ throw new AppSearchException(
+ ResultCodeToProtoConverter.toResultCode(statusProto.getCode()),
+ statusProto.getMessage());
}
/**
* Checks whether {@link IcingSearchEngine#optimize()} should be called to release resources.
*
- * <p>This method should be only called in mutate methods and get the WRITE lock to keep thread
- * safety.
+ * <p>This method should be only called after a mutation to local storage backend which
+ * deletes a mass of data and could release lots resources after
+ * {@link IcingSearchEngine#optimize()}.
+ *
+ * <p>This method will trigger {@link IcingSearchEngine#getOptimizeInfo()} to check
+ * resources that could be released for every {@link #CHECK_OPTIMIZE_INTERVAL} mutations.
+ *
* <p>{@link IcingSearchEngine#optimize()} should be called only if
* {@link GetOptimizeInfoResultProto} shows there is enough resources could be released.
- * <p>{@link IcingSearchEngine#getOptimizeInfo()} should be called once per
- * {@link #CHECK_OPTIMIZE_INTERVAL} of remove executions.
*
- * @param force whether we should directly call {@link IcingSearchEngine#getOptimizeInfo()}.
+ * @param mutationSize The number of how many mutations have been executed for current request.
+ * An inside counter will accumulates it. Once the counter reaches
+ * {@link #CHECK_OPTIMIZE_INTERVAL},
+ * {@link IcingSearchEngine#getOptimizeInfo()} will be triggered and the
+ * counter will be reset.
*/
- @GuardedBy("mReadWriteLock")
- private void checkForOptimizeLocked(boolean force) throws AppSearchException {
- ++mOptimizeIntervalCountLocked;
- if (force || mOptimizeIntervalCountLocked >= CHECK_OPTIMIZE_INTERVAL) {
- mOptimizeIntervalCountLocked = 0;
+ public void checkForOptimize(int mutationSize, @Nullable OptimizeStats.Builder builder)
+ throws AppSearchException {
+ mReadWriteLock.writeLock().lock();
+ try {
+ mOptimizeIntervalCountLocked += mutationSize;
+ if (mOptimizeIntervalCountLocked >= CHECK_OPTIMIZE_INTERVAL) {
+ checkForOptimize(builder);
+ }
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Checks whether {@link IcingSearchEngine#optimize()} should be called to release resources.
+ *
+ * <p>This method will directly trigger {@link IcingSearchEngine#getOptimizeInfo()} to check
+ * resources that could be released.
+ *
+ * <p>{@link IcingSearchEngine#optimize()} should be called only if
+ * {@link OptimizeStrategy#shouldOptimize(GetOptimizeInfoResultProto)} return true.
+ */
+ public void checkForOptimize(@Nullable OptimizeStats.Builder builder)
+ throws AppSearchException {
+ mReadWriteLock.writeLock().lock();
+ try {
GetOptimizeInfoResultProto optimizeInfo = getOptimizeInfoResultLocked();
checkSuccess(optimizeInfo.getStatus());
- // Second threshold, decide when to call optimize().
- if (optimizeInfo.getOptimizableDocs() >= OPTIMIZE_THRESHOLD_DOC_COUNT
- || optimizeInfo.getEstimatedOptimizableBytes()
- >= OPTIMIZE_THRESHOLD_BYTES) {
- // TODO(b/155939114): call optimize in the same thread will slow down api calls
- // significantly. Move this call to background.
- OptimizeResultProto optimizeResultProto = mIcingSearchEngineLocked.optimize();
- checkSuccess(optimizeResultProto.getStatus());
+ mOptimizeIntervalCountLocked = 0;
+ if (mOptimizeStrategy.shouldOptimize(optimizeInfo)) {
+ optimize(builder);
}
- // TODO(b/147699081): Return OptimizeResultProto & log lost data detail once we add
- // a field to indicate lost_schema and lost_documents in OptimizeResultProto.
- // go/icing-library-apis.
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ // TODO(b/147699081): Return OptimizeResultProto & log lost data detail once we add
+ // a field to indicate lost_schema and lost_documents in OptimizeResultProto.
+ // go/icing-library-apis.
+ }
+
+ /** Triggers {@link IcingSearchEngine#optimize()} directly. */
+ public void optimize(@Nullable OptimizeStats.Builder builder) throws AppSearchException {
+ mReadWriteLock.writeLock().lock();
+ try {
+ mLogUtil.piiTrace("optimize, request");
+ OptimizeResultProto optimizeResultProto = mIcingSearchEngineLocked.optimize();
+ mLogUtil.piiTrace(
+ "optimize, response", optimizeResultProto.getStatus(), optimizeResultProto);
+ if (builder != null) {
+ builder.setStatusCode(statusProtoToResultCode(optimizeResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(optimizeResultProto.getOptimizeStats(),
+ builder);
+ }
+ checkSuccess(optimizeResultProto.getStatus());
+ } finally {
+ mReadWriteLock.writeLock().unlock();
}
}
@@ -1126,10 +2246,15 @@
@NonNull
@VisibleForTesting
static SearchResultPage rewriteSearchResultProto(
- @NonNull SearchResultProto searchResultProto) throws AppSearchException {
+ @NonNull SearchResultProto searchResultProto,
+ @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap)
+ throws AppSearchException {
// Parallel array of package names for each document search result.
List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());
+ // Parallel array of database names for each document search result.
+ List<String> databaseNames = new ArrayList<>(searchResultProto.getResultsCount());
+
SearchResultProto.Builder resultsBuilder = searchResultProto.toBuilder();
for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
SearchResultProto.ResultProto.Builder resultBuilder =
@@ -1137,54 +2262,34 @@
DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
String prefix = removePrefixesFromDocument(documentBuilder);
packageNames.add(getPackageName(prefix));
+ databaseNames.add(getDatabaseName(prefix));
resultBuilder.setDocument(documentBuilder);
resultsBuilder.setResults(i, resultBuilder);
}
- return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder, packageNames);
+ return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder, packageNames,
+ databaseNames, schemaMap);
}
@GuardedBy("mReadWriteLock")
@VisibleForTesting
GetOptimizeInfoResultProto getOptimizeInfoResultLocked() {
- return mIcingSearchEngineLocked.getOptimizeInfo();
- }
-
- @GuardedBy("mReadWriteLock")
- @VisibleForTesting
- VisibilityStore getVisibilityStoreLocked() {
- return mVisibilityStoreLocked;
+ mLogUtil.piiTrace("getOptimizeInfo, request");
+ GetOptimizeInfoResultProto result = mIcingSearchEngineLocked.getOptimizeInfo();
+ mLogUtil.piiTrace("getOptimizeInfo, response", result.getStatus(), result);
+ return result;
}
/**
- * Converts an erroneous status code to an AppSearchException. Callers should ensure that
- * the status code is not OK or WARNING_DATA_LOSS.
+ * Converts an erroneous status code from the Icing status enums to the AppSearchResult enums.
*
- * @param statusProto StatusProto with error code and message to translate into
- * AppSearchException.
- * @return AppSearchException with the parallel error code.
+ * <p>Callers should ensure that the status code is not OK or WARNING_DATA_LOSS.
+ *
+ * @param statusProto StatusProto with error code to translate into an
+ * {@link AppSearchResult} code.
+ * @return {@link AppSearchResult} error code
*/
- private static AppSearchException statusProtoToAppSearchException(StatusProto statusProto) {
- switch (statusProto.getCode()) {
- case INVALID_ARGUMENT:
- return new AppSearchException(AppSearchResult.RESULT_INVALID_ARGUMENT,
- statusProto.getMessage());
- case NOT_FOUND:
- return new AppSearchException(AppSearchResult.RESULT_NOT_FOUND,
- statusProto.getMessage());
- case FAILED_PRECONDITION:
- // Fallthrough
- case ABORTED:
- // Fallthrough
- case INTERNAL:
- return new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR,
- statusProto.getMessage());
- case OUT_OF_SPACE:
- return new AppSearchException(AppSearchResult.RESULT_OUT_OF_SPACE,
- statusProto.getMessage());
- default:
- // Some unknown/unsupported error
- return new AppSearchException(AppSearchResult.RESULT_UNKNOWN_ERROR,
- "Unknown IcingSearchEngine status code: " + statusProto.getCode());
- }
+ private static @AppSearchResult.ResultCode int statusProtoToResultCode(
+ @NonNull StatusProto statusProto) {
+ return ResultCodeToProtoConverter.toResultCode(statusProto.getCode());
}
}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchLogger.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchLogger.java
new file mode 100644
index 0000000..741ed1f
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchLogger.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.localstorage.stats.CallStats;
+import androidx.appsearch.localstorage.stats.InitializeStats;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
+import androidx.appsearch.localstorage.stats.PutDocumentStats;
+import androidx.appsearch.localstorage.stats.RemoveStats;
+import androidx.appsearch.localstorage.stats.SearchStats;
+import androidx.appsearch.localstorage.stats.SetSchemaStats;
+
+/**
+ * An interface for implementing client-defined logging AppSearch operations stats.
+ *
+ * <p>Any implementation needs to provide general information on how to log all the stats types.
+ * (e.g. {@link CallStats})
+ *
+ * <p>All implementations of this interface must be thread safe.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface AppSearchLogger {
+ /**
+ * Logs {@link CallStats}
+ */
+ void logStats(@NonNull CallStats stats);
+
+ /**
+ * Logs {@link PutDocumentStats}
+ */
+ void logStats(@NonNull PutDocumentStats stats);
+
+ /**
+ * Logs {@link InitializeStats}
+ */
+ void logStats(@NonNull InitializeStats stats);
+
+ /**
+ * Logs {@link SearchStats}
+ */
+ void logStats(@NonNull SearchStats stats);
+
+ /**
+ * Logs {@link RemoveStats}
+ */
+ void logStats(@NonNull RemoveStats stats);
+
+ /**
+ * Logs {@link OptimizeStats}
+ */
+ void logStats(@NonNull OptimizeStats stats);
+
+ /**
+ * Logs {@link SetSchemaStats}
+ */
+ void logStats(@NonNull SetSchemaStats stats);
+
+ // TODO(b/173532925) Add remaining logStats once we add all the stats.
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchLoggerHelper.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchLoggerHelper.java
new file mode 100644
index 0000000..5f19263
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchLoggerHelper.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.localstorage.stats.InitializeStats;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
+import androidx.appsearch.localstorage.stats.PutDocumentStats;
+import androidx.appsearch.localstorage.stats.RemoveStats;
+import androidx.appsearch.localstorage.stats.SearchStats;
+import androidx.appsearch.localstorage.stats.SetSchemaStats;
+import androidx.core.util.Preconditions;
+
+import com.google.android.icing.proto.DeleteByQueryStatsProto;
+import com.google.android.icing.proto.DeleteStatsProto;
+import com.google.android.icing.proto.InitializeStatsProto;
+import com.google.android.icing.proto.OptimizeStatsProto;
+import com.google.android.icing.proto.PutDocumentStatsProto;
+import com.google.android.icing.proto.QueryStatsProto;
+import com.google.android.icing.proto.SetSchemaResultProto;
+
+/**
+ * Class contains helper functions for logging.
+ *
+ * <p>E.g. we need to have helper functions to copy numbers from IcingLib to stats classes.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class AppSearchLoggerHelper {
+ private AppSearchLoggerHelper() {
+ }
+
+ /**
+ * Copies native PutDocument stats to builder.
+ *
+ * @param fromNativeStats stats copied from
+ * @param toStatsBuilder stats copied to
+ */
+ static void copyNativeStats(@NonNull PutDocumentStatsProto fromNativeStats,
+ @NonNull PutDocumentStats.Builder toStatsBuilder) {
+ Preconditions.checkNotNull(fromNativeStats);
+ Preconditions.checkNotNull(toStatsBuilder);
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setNativeDocumentStoreLatencyMillis(
+ fromNativeStats.getDocumentStoreLatencyMs())
+ .setNativeIndexLatencyMillis(fromNativeStats.getIndexLatencyMs())
+ .setNativeIndexMergeLatencyMillis(fromNativeStats.getIndexMergeLatencyMs())
+ .setNativeDocumentSizeBytes(fromNativeStats.getDocumentSize())
+ .setNativeNumTokensIndexed(
+ fromNativeStats.getTokenizationStats().getNumTokensIndexed())
+ .setNativeExceededMaxNumTokens(
+ fromNativeStats.getTokenizationStats().getExceededMaxTokenNum());
+ }
+
+ /**
+ * Copies native Initialize stats to builder.
+ *
+ * @param fromNativeStats stats copied from
+ * @param toStatsBuilder stats copied to
+ */
+ static void copyNativeStats(@NonNull InitializeStatsProto fromNativeStats,
+ @NonNull InitializeStats.Builder toStatsBuilder) {
+ Preconditions.checkNotNull(fromNativeStats);
+ Preconditions.checkNotNull(toStatsBuilder);
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setDocumentStoreRecoveryCause(
+ fromNativeStats.getDocumentStoreRecoveryCause().getNumber())
+ .setIndexRestorationCause(
+ fromNativeStats.getIndexRestorationCause().getNumber())
+ .setSchemaStoreRecoveryCause(
+ fromNativeStats.getSchemaStoreRecoveryCause().getNumber())
+ .setDocumentStoreRecoveryLatencyMillis(
+ fromNativeStats.getDocumentStoreRecoveryLatencyMs())
+ .setIndexRestorationLatencyMillis(
+ fromNativeStats.getIndexRestorationLatencyMs())
+ .setSchemaStoreRecoveryLatencyMillis(
+ fromNativeStats.getSchemaStoreRecoveryLatencyMs())
+ .setDocumentStoreDataStatus(
+ fromNativeStats.getDocumentStoreDataStatus().getNumber())
+ .setDocumentCount(fromNativeStats.getNumDocuments())
+ .setSchemaTypeCount(fromNativeStats.getNumSchemaTypes());
+ }
+
+ /**
+ * Copies native Query stats to builder.
+ *
+ * @param fromNativeStats Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(@NonNull QueryStatsProto fromNativeStats,
+ @NonNull SearchStats.Builder toStatsBuilder) {
+ Preconditions.checkNotNull(fromNativeStats);
+ Preconditions.checkNotNull(toStatsBuilder);
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setTermCount(fromNativeStats.getNumTerms())
+ .setQueryLength(fromNativeStats.getQueryLength())
+ .setFilteredNamespaceCount(fromNativeStats.getNumNamespacesFiltered())
+ .setFilteredSchemaTypeCount(fromNativeStats.getNumSchemaTypesFiltered())
+ .setRequestedPageSize(fromNativeStats.getRequestedPageSize())
+ .setCurrentPageReturnedResultCount(
+ fromNativeStats.getNumResultsReturnedCurrentPage())
+ .setIsFirstPage(fromNativeStats.getIsFirstPage())
+ .setParseQueryLatencyMillis(fromNativeStats.getParseQueryLatencyMs())
+ .setRankingStrategy(fromNativeStats.getRankingStrategy().getNumber())
+ .setScoredDocumentCount(fromNativeStats.getNumDocumentsScored())
+ .setScoringLatencyMillis(fromNativeStats.getScoringLatencyMs())
+ .setRankingLatencyMillis(fromNativeStats.getRankingLatencyMs())
+ .setResultWithSnippetsCount(fromNativeStats.getNumResultsWithSnippets())
+ .setDocumentRetrievingLatencyMillis(
+ fromNativeStats.getDocumentRetrievalLatencyMs());
+ }
+
+ /**
+ * Copies native Delete stats to builder.
+ *
+ * @param fromNativeStats Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(@NonNull DeleteStatsProto fromNativeStats,
+ @NonNull RemoveStats.Builder toStatsBuilder) {
+ Preconditions.checkNotNull(fromNativeStats);
+ Preconditions.checkNotNull(toStatsBuilder);
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setDeleteType(fromNativeStats.getDeleteType().getNumber())
+ .setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted());
+ }
+
+ /**
+ * Copies native DeleteByQuery stats to builder.
+ *
+ * @param fromNativeStats Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(@NonNull DeleteByQueryStatsProto fromNativeStats,
+ @NonNull RemoveStats.Builder toStatsBuilder) {
+ Preconditions.checkNotNull(fromNativeStats);
+ Preconditions.checkNotNull(toStatsBuilder);
+
+ @SuppressWarnings("deprecation")
+ int deleteType = DeleteStatsProto.DeleteType.Code.DEPRECATED_QUERY.getNumber();
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setDeleteType(deleteType)
+ .setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted());
+ }
+
+ /**
+ * Copies native {@link OptimizeStatsProto} to builder.
+ *
+ * @param fromNativeStats Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(@NonNull OptimizeStatsProto fromNativeStats,
+ @NonNull OptimizeStats.Builder toStatsBuilder) {
+ Preconditions.checkNotNull(fromNativeStats);
+ Preconditions.checkNotNull(toStatsBuilder);
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setDocumentStoreOptimizeLatencyMillis(
+ fromNativeStats.getDocumentStoreOptimizeLatencyMs())
+ .setIndexRestorationLatencyMillis(fromNativeStats.getIndexRestorationLatencyMs())
+ .setOriginalDocumentCount(fromNativeStats.getNumOriginalDocuments())
+ .setDeletedDocumentCount(fromNativeStats.getNumDeletedDocuments())
+ .setExpiredDocumentCount(fromNativeStats.getNumExpiredDocuments())
+ .setStorageSizeBeforeBytes(fromNativeStats.getStorageSizeBefore())
+ .setStorageSizeAfterBytes(fromNativeStats.getStorageSizeAfter())
+ .setTimeSinceLastOptimizeMillis(fromNativeStats.getTimeSinceLastOptimizeMs());
+ }
+
+ /*
+ * Copy SetSchema result stats to builder.
+ *
+ * @param fromProto Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(@NonNull SetSchemaResultProto fromProto,
+ @NonNull SetSchemaStats.Builder toStatsBuilder) {
+ Preconditions.checkNotNull(fromProto);
+ Preconditions.checkNotNull(toStatsBuilder);
+ toStatsBuilder
+ .setNewTypeCount(fromProto.getNewSchemaTypesCount())
+ .setDeletedTypeCount(fromProto.getDeletedSchemaTypesCount())
+ .setCompatibleTypeChangeCount(fromProto.getFullyCompatibleChangedSchemaTypesCount())
+ .setIndexIncompatibleTypeChangeCount(
+ fromProto.getIndexIncompatibleChangedSchemaTypesCount())
+ .setBackwardsIncompatibleTypeChangeCount(
+ fromProto.getIncompatibleSchemaTypesCount());
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchMigrationHelper.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchMigrationHelper.java
new file mode 100644
index 0000000..393f8f2
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchMigrationHelper.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.localstorage;
+
+import static androidx.appsearch.app.AppSearchResult.RESULT_INVALID_SCHEMA;
+import static androidx.appsearch.app.AppSearchResult.throwableToFailedResult;
+
+import android.os.Bundle;
+import android.os.Parcel;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.Migrator;
+import androidx.appsearch.app.SearchResultPage;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.stats.SchemaMigrationStats;
+import androidx.collection.ArraySet;
+import androidx.core.util.Preconditions;
+
+import com.google.android.icing.proto.PersistType;
+import com.google.android.icing.protobuf.CodedInputStream;
+import com.google.android.icing.protobuf.CodedOutputStream;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The helper class for {@link AppSearchSchema} migration.
+ *
+ * <p>It will query and migrate {@link GenericDocument} in given type to a new version.
+ */
+class AppSearchMigrationHelper implements Closeable {
+ private final AppSearchImpl mAppSearchImpl;
+ private final String mPackageName;
+ private final String mDatabaseName;
+ private final File mFile;
+ private final Set<String> mDestinationTypes;
+ private boolean mAreDocumentsMigrated = false;
+
+ AppSearchMigrationHelper(@NonNull AppSearchImpl appSearchImpl,
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull Set<AppSearchSchema> newSchemas) throws IOException {
+ mAppSearchImpl = Preconditions.checkNotNull(appSearchImpl);
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabaseName = Preconditions.checkNotNull(databaseName);
+ Preconditions.checkNotNull(newSchemas);
+ mFile = File.createTempFile(/*prefix=*/"appsearch", /*suffix=*/null);
+ mDestinationTypes = new ArraySet<>(newSchemas.size());
+ for (AppSearchSchema newSchema : newSchemas) {
+ mDestinationTypes.add(newSchema.getSchemaType());
+ }
+ }
+
+ /**
+ * Queries all documents that need to be migrated to new version, and transform documents to
+ * new version by passing them to the provided Transformer.
+ *
+ * <p>This method will be invoked on the background worker thread.
+ *
+ * @param migrators The map of active {@link Migrator}s that will upgrade or downgrade a
+ * {@link GenericDocument} to new version. The key is the schema type that
+ * {@link Migrator} applies to.
+ * @param currentVersion The current version of the document's schema.
+ * @param finalVersion The final version that documents need to be migrated to.
+ *
+ * @throws IOException on i/o problem
+ * @throws AppSearchException on AppSearch problem
+ */
+ @WorkerThread
+ public void queryAndTransform(@NonNull Map<String, Migrator> migrators, int currentVersion,
+ int finalVersion, @Nullable SchemaMigrationStats.Builder schemaMigrationStatsBuilder)
+ throws IOException, AppSearchException {
+ Preconditions.checkState(mFile.exists(), "Internal temp file does not exist.");
+ int migratedDocsCount = 0;
+ try (FileOutputStream outputStream = new FileOutputStream(mFile, /*append=*/ true)) {
+ CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream);
+ SearchResultPage searchResultPage = mAppSearchImpl.query(mPackageName, mDatabaseName,
+ /*queryExpression=*/"",
+ new SearchSpec.Builder()
+ .addFilterSchemas(migrators.keySet())
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build(),
+ /*logger=*/ null);
+ while (!searchResultPage.getResults().isEmpty()) {
+ for (int i = 0; i < searchResultPage.getResults().size(); i++) {
+ GenericDocument document =
+ searchResultPage.getResults().get(i).getGenericDocument();
+ Migrator migrator = migrators.get(document.getSchemaType());
+ GenericDocument newDocument;
+ if (currentVersion < finalVersion) {
+ newDocument = migrator.onUpgrade(currentVersion, finalVersion, document);
+ } else {
+ // if current version = final version. we will return empty active
+ // migrators at SchemaMigrationUtils.getActivityMigrators and won't reach
+ // here.
+ newDocument = migrator.onDowngrade(currentVersion, finalVersion, document);
+ }
+ if (!mDestinationTypes.contains(newDocument.getSchemaType())) {
+ // we exit before the new schema has been set to AppSearch. So no
+ // observable changes will be applied to stored schemas and documents.
+ // And the temp file will be deleted at close(), which will be triggered at
+ // the end of try-with-resources when using AppSearchMigrationHelper.
+ throw new AppSearchException(RESULT_INVALID_SCHEMA,
+ "Receive a migrated document with schema type: "
+ + newDocument.getSchemaType()
+ + ". But the schema types doesn't exist in the request");
+ }
+ Bundle bundle = newDocument.getBundle();
+ byte[] serializedMessage;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeBundle(bundle);
+ serializedMessage = parcel.marshall();
+ } finally {
+ parcel.recycle();
+ }
+ codedOutputStream.writeByteArrayNoTag(serializedMessage);
+ }
+ codedOutputStream.flush();
+ migratedDocsCount += searchResultPage.getResults().size();
+ searchResultPage = mAppSearchImpl.getNextPage(mPackageName,
+ searchResultPage.getNextPageToken(), /*statsBuilder=*/ null);
+ outputStream.flush();
+ }
+ }
+ mAreDocumentsMigrated = true;
+ if (schemaMigrationStatsBuilder != null) {
+ schemaMigrationStatsBuilder.setMigratedDocumentCount(migratedDocsCount);
+ }
+ }
+
+ /**
+ * Reads {@link GenericDocument} from the temperate file and saves them to AppSearch.
+ *
+ * <p> This method should be only called once.
+ *
+ * @param responseBuilder a SetSchemaResponse builder whose result will be returned by this
+ * function with any
+ * {@link androidx.appsearch.app.SetSchemaResponse.MigrationFailure}
+ * added in.
+ * @return the {@link SetSchemaResponse} for this
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema} call.
+ *
+ * @throws IOException on i/o problem
+ * @throws AppSearchException on AppSearch problem
+ */
+ @NonNull
+ @WorkerThread
+ public SetSchemaResponse readAndPutDocuments(@NonNull SetSchemaResponse.Builder responseBuilder,
+ SchemaMigrationStats.Builder schemaMigrationStatsBuilder)
+ throws IOException, AppSearchException {
+ Preconditions.checkState(mFile.exists(), "Internal temp file does not exist.");
+ if (!mAreDocumentsMigrated) {
+ return responseBuilder.build();
+ }
+ try (InputStream inputStream = new FileInputStream(mFile)) {
+ CodedInputStream codedInputStream = CodedInputStream.newInstance(inputStream);
+ int savedDocsCount = 0;
+ while (!codedInputStream.isAtEnd()) {
+ GenericDocument document = readDocumentFromInputStream(codedInputStream);
+ try {
+ mAppSearchImpl.putDocument(mPackageName, mDatabaseName, document,
+ /*logger=*/ null);
+ savedDocsCount++;
+ } catch (Throwable t) {
+ responseBuilder.addMigrationFailure(
+ new SetSchemaResponse.MigrationFailure(
+ document.getNamespace(),
+ document.getId(),
+ document.getSchemaType(),
+ throwableToFailedResult(t)));
+ }
+ }
+ mAppSearchImpl.persistToDisk(PersistType.Code.FULL);
+ if (schemaMigrationStatsBuilder != null) {
+ schemaMigrationStatsBuilder.setSavedDocumentCount(savedDocsCount);
+ }
+ }
+ return responseBuilder.build();
+ }
+
+ /**
+ * Reads {@link GenericDocument} from given {@link CodedInputStream}.
+ *
+ * @param codedInputStream The codedInputStream to read from
+ *
+ * @throws IOException on File operation error.
+ */
+ @NonNull
+ private static GenericDocument readDocumentFromInputStream(
+ @NonNull CodedInputStream codedInputStream) throws IOException {
+ byte[] serializedMessage = codedInputStream.readByteArray();
+
+ Bundle bundle;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.unmarshall(serializedMessage, 0, serializedMessage.length);
+ parcel.setDataPosition(0);
+ bundle = parcel.readBundle();
+ } finally {
+ parcel.recycle();
+ }
+
+ return new GenericDocument(bundle);
+ }
+
+ @Override
+ public void close() {
+ mFile.delete();
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/GlobalSearchSessionImpl.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/GlobalSearchSessionImpl.java
index ac8fec2..23c07925 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/GlobalSearchSessionImpl.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/GlobalSearchSessionImpl.java
@@ -16,17 +16,25 @@
// @exportToFramework:skipFile()
package androidx.appsearch.localstorage;
+import android.content.Context;
+
import androidx.annotation.NonNull;
-import androidx.appsearch.app.AppSearchSession;
+import androidx.annotation.Nullable;
+import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.app.GlobalSearchSession;
+import androidx.appsearch.app.ReportSystemUsageRequest;
import androidx.appsearch.app.SearchResults;
import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.util.FutureUtil;
import androidx.core.util.Preconditions;
-import java.util.concurrent.ExecutorService;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.Executor;
/**
- * An implementation of {@link AppSearchSession} which stores data locally
+ * An implementation of {@link GlobalSearchSession} which stores data locally
* in the app's storage space using a bundled version of the search native library.
*
* <p>Queries are executed multi-threaded, but a single thread is used for mutate requests (put,
@@ -34,27 +42,62 @@
*/
class GlobalSearchSessionImpl implements GlobalSearchSession {
private final AppSearchImpl mAppSearchImpl;
- private final ExecutorService mExecutorService;
+ private final Executor mExecutor;
+ private final Context mContext;
+
+ private boolean mIsClosed = false;
+
+ @Nullable
+ private final AppSearchLogger mLogger;
GlobalSearchSessionImpl(
@NonNull AppSearchImpl appSearchImpl,
- @NonNull ExecutorService executorService) {
+ @NonNull Executor executor,
+ @NonNull Context context,
+ @Nullable AppSearchLogger logger) {
mAppSearchImpl = Preconditions.checkNotNull(appSearchImpl);
- mExecutorService = Preconditions.checkNotNull(executorService);
+ mExecutor = Preconditions.checkNotNull(executor);
+ mContext = Preconditions.checkNotNull(context);
+ mLogger = logger;
}
@NonNull
@Override
- public SearchResults query(
+ public SearchResults search(
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpec);
+ Preconditions.checkState(!mIsClosed, "GlobalSearchSession has already been closed");
return new SearchResultsImpl(
mAppSearchImpl,
- mExecutorService,
- /*packageName=*/ null,
+ mExecutor,
+ mContext.getPackageName(),
/*databaseName=*/ null,
queryExpression,
- searchSpec);
+ searchSpec,
+ mLogger);
+ }
+
+ /**
+ * Reporting system usage is not supported in the local backend, so this method does nothing
+ * and always completes the return value with an
+ * {@link androidx.appsearch.exceptions.AppSearchException} having a result code of
+ * {@link AppSearchResult#RESULT_SECURITY_ERROR}.
+ */
+ @NonNull
+ @Override
+ public ListenableFuture<Void> reportSystemUsage(@NonNull ReportSystemUsageRequest request) {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkState(!mIsClosed, "GlobalSearchSession has already been closed");
+ return FutureUtil.execute(mExecutor, () -> {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_SECURITY_ERROR,
+ mContext.getPackageName() + " does not have access to report system usage");
+ });
+ }
+
+ @Override
+ public void close() {
+ mIsClosed = true;
}
}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/JetpackOptimizeStrategy.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/JetpackOptimizeStrategy.java
new file mode 100644
index 0000000..6c0ee68
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/JetpackOptimizeStrategy.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.localstorage;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
+
+import com.google.android.icing.proto.GetOptimizeInfoResultProto;
+
+/**
+ * An implementation of {@link androidx.appsearch.localstorage.OptimizeStrategy} will
+ * determine when to trigger {@link androidx.appsearch.localstorage.AppSearchImpl#optimize()} in
+ * Jetpack environment.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class JetpackOptimizeStrategy implements OptimizeStrategy{
+
+ @VisibleForTesting
+ static final int DOC_COUNT_OPTIMIZE_THRESHOLD = 1000;
+ @VisibleForTesting
+ static final int BYTES_OPTIMIZE_THRESHOLD = 1 * 1024 * 1024; // 1MB
+
+ @Override
+ public boolean shouldOptimize(@NonNull GetOptimizeInfoResultProto optimizeInfo) {
+ return optimizeInfo.getOptimizableDocs() >= DOC_COUNT_OPTIMIZE_THRESHOLD
+ || optimizeInfo.getEstimatedOptimizableBytes() >= BYTES_OPTIMIZE_THRESHOLD;
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/LimitConfig.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/LimitConfig.java
new file mode 100644
index 0000000..dded201
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/LimitConfig.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage;
+
+import androidx.annotation.RestrictTo;
+
+/**
+ * Defines limits placed on users of AppSearch and enforced by {@link AppSearchImpl}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface LimitConfig {
+ /**
+ * The maximum number of bytes a single document is allowed to be.
+ *
+ * <p>Enforced at the time of serializing the document into a proto.
+ *
+ * <p>This limit has two purposes:
+ * <ol>
+ * <li>Prevent the system service from using too much memory during indexing or querying
+ * by capping the size of the data structures it needs to buffer
+ * <li>Prevent apps from using a very large amount of data by storing exceptionally large
+ * documents.
+ * </ol>
+ */
+ int getMaxDocumentSizeBytes();
+
+ /**
+ * The maximum number of documents a single app is allowed to index.
+ *
+ * <p>Enforced at indexing time.
+ *
+ * <p>This limit has two purposes:
+ * <ol>
+ * <li>Protect icing lib's docid space from being overwhelmed by a single app. The
+ * overall docid limit is currently 2^20 (~1 million)
+ * <li>Prevent apps from using a very large amount of data on the system by storing too many
+ * documents.
+ * </ol>
+ */
+ int getMaxDocumentCount();
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/LocalStorage.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/LocalStorage.java
index 8f6cfde..b09aba0 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/LocalStorage.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/LocalStorage.java
@@ -17,20 +17,27 @@
package androidx.appsearch.localstorage;
import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
+import androidx.appsearch.annotation.Document;
import androidx.appsearch.app.AppSearchSession;
import androidx.appsearch.app.GlobalSearchSession;
import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.stats.InitializeStats;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
import androidx.appsearch.localstorage.util.FutureUtil;
import androidx.core.util.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.File;
+import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -40,20 +47,14 @@
*
* <p>The search native library is an on-device searching library that allows apps to define
* {@link androidx.appsearch.app.AppSearchSchema}s, save and query a variety of
- * {@link androidx.appsearch.annotation.AppSearchDocument}s. The library needs to be initialized
+ * {@link Document}s. The library needs to be initialized
* before using, which will create a folder to save data in the app's storage space.
*
* <p>Queries are executed multi-threaded, but a single thread is used for mutate requests (put,
* delete, etc..).
*/
public class LocalStorage {
- /**
- * The default empty database name.
- * @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- @VisibleForTesting
- public static final String DEFAULT_DATABASE_NAME = "";
+ private static final String TAG = "AppSearchLocalStorage";
private static final String ICING_LIB_ROOT_DIR = "appsearch";
@@ -61,109 +62,206 @@
public static final class SearchContext {
final Context mContext;
final String mDatabaseName;
+ final Executor mExecutor;
+ @Nullable
+ final AppSearchLogger mLogger;
- SearchContext(@NonNull Context context, @NonNull String databaseName) {
+ SearchContext(@NonNull Context context, @NonNull String databaseName,
+ @NonNull Executor executor, @Nullable AppSearchLogger logger) {
mContext = Preconditions.checkNotNull(context);
mDatabaseName = Preconditions.checkNotNull(databaseName);
+ mExecutor = Preconditions.checkNotNull(executor);
+ mLogger = logger;
}
/**
* Returns the name of the database to create or open.
- *
- * <p>Databases with different names are fully separate with distinct types, namespaces,
- * and data.
*/
@NonNull
public String getDatabaseName() {
return mDatabaseName;
}
+ /**
+ * Returns the worker executor associated with {@link AppSearchSession}.
+ *
+ * <p>If an executor is not provided to {@link Builder}, the AppSearch default executor will
+ * be returned. You should never cast the executor to
+ * {@link java.util.concurrent.ExecutorService} and call
+ * {@link ExecutorService#shutdownNow()}. It will cancel the futures it's returned. And
+ * since {@link Executor#execute} won't return anything, we will hang forever waiting for
+ * the execution.
+ */
+ @NonNull
+ public Executor getWorkerExecutor() {
+ return mExecutor;
+ }
+
/** Builder for {@link SearchContext} objects. */
public static final class Builder {
private final Context mContext;
- private String mDatabaseName = DEFAULT_DATABASE_NAME;
- private boolean mBuilt = false;
-
- public Builder(@NonNull Context context) {
- mContext = Preconditions.checkNotNull(context);
- }
+ private final String mDatabaseName;
+ private Executor mExecutor;
+ @Nullable
+ private AppSearchLogger mLogger;
/**
- * Sets the name of the database associated with {@link AppSearchSession}.
+ * Creates a {@link SearchContext.Builder} instance.
*
* <p>{@link AppSearchSession} will create or open a database under the given name.
*
- * <p>Databases with different names are fully separate with distinct types, namespaces,
- * and data.
+ * <p>Databases with different names are fully separate with distinct schema types,
+ * namespaces, and documents.
*
- * <p>Database name cannot contain {@code '/'}.
- *
- * <p>If not specified, defaults to the empty string.
+ * <p>The database name cannot contain {@code '/'}.
*
* @param databaseName The name of the database.
* @throws IllegalArgumentException if the databaseName contains {@code '/'}.
*/
- @NonNull
- public Builder setDatabaseName(@NonNull String databaseName) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
+ public Builder(@NonNull Context context, @NonNull String databaseName) {
+ mContext = Preconditions.checkNotNull(context);
Preconditions.checkNotNull(databaseName);
if (databaseName.contains("/")) {
throw new IllegalArgumentException("Database name cannot contain '/'");
}
mDatabaseName = databaseName;
+ }
+
+ /**
+ * Sets the worker executor associated with {@link AppSearchSession}.
+ *
+ * <p>If an executor is not provided, the AppSearch default executor will be used.
+ *
+ * @param executor the worker executor used to run heavy background tasks.
+ */
+ @NonNull
+ public Builder setWorkerExecutor(@NonNull Executor executor) {
+ mExecutor = Preconditions.checkNotNull(executor);
+ return this;
+ }
+
+
+ /**
+ * Sets the custom logger used to get the details stats from AppSearch.
+ *
+ * <p>If no logger is provided, nothing would be returned/logged. There is no default
+ * logger implementation in AppSearch.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ public Builder setLogger(@NonNull AppSearchLogger logger) {
+ mLogger = Preconditions.checkNotNull(logger);
return this;
}
/** Builds a {@link SearchContext} instance. */
@NonNull
public SearchContext build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBuilt = true;
- return new SearchContext(mContext, mDatabaseName);
+ if (mExecutor == null) {
+ mExecutor = EXECUTOR;
+ }
+ return new SearchContext(mContext, mDatabaseName, mExecutor, mLogger);
}
}
}
/**
* Contains information relevant to creating a global search session.
+ *
+ * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final class GlobalSearchContext {
final Context mContext;
+ final Executor mExecutor;
+ @Nullable
+ final AppSearchLogger mLogger;
- GlobalSearchContext(@NonNull Context context) {
+ GlobalSearchContext(@NonNull Context context, @NonNull Executor executor,
+ @Nullable AppSearchLogger logger) {
mContext = Preconditions.checkNotNull(context);
+ mExecutor = Preconditions.checkNotNull(executor);
+ mLogger = logger;
+ }
+
+ /**
+ * Returns the worker executor associated with {@link GlobalSearchSession}.
+ *
+ * <p>If an executor is not provided to {@link Builder}, the AppSearch default executor will
+ * be returned. You should never cast the executor to
+ * {@link java.util.concurrent.ExecutorService} and call
+ * {@link ExecutorService#shutdownNow()}. It will cancel the futures it's returned. And
+ * since {@link Executor#execute} won't return anything, we will hang forever waiting for
+ * the execution.
+ */
+ @NonNull
+ public Executor getWorkerExecutor() {
+ return mExecutor;
}
/** Builder for {@link GlobalSearchContext} objects. */
public static final class Builder {
private final Context mContext;
- private boolean mBuilt = false;
+ private Executor mExecutor;
+ @Nullable
+ private AppSearchLogger mLogger;
public Builder(@NonNull Context context) {
mContext = Preconditions.checkNotNull(context);
}
+ /**
+ * Sets the worker executor associated with {@link GlobalSearchSession}.
+ *
+ * <p>If an executor is not provided, the AppSearch default executor will be used.
+ *
+ * @param executor the worker executor used to run heavy background tasks.
+ */
+ @NonNull
+ public Builder setWorkerExecutor(@NonNull Executor executor) {
+ Preconditions.checkNotNull(executor);
+ mExecutor = executor;
+ return this;
+ }
+
+ /**
+ * Sets the custom logger used to get the details stats from AppSearch.
+ *
+ * <p>If no logger is provided, nothing would be returned/logged. There is no default
+ * logger implementation in AppSearch.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ public Builder setLogger(@NonNull AppSearchLogger logger) {
+ mLogger = Preconditions.checkNotNull(logger);
+ return this;
+ }
+
/** Builds a {@link GlobalSearchContext} instance. */
@NonNull
public GlobalSearchContext build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBuilt = true;
- return new GlobalSearchContext(mContext);
+ if (mExecutor == null) {
+ mExecutor = EXECUTOR;
+ }
+ return new GlobalSearchContext(mContext, mExecutor, mLogger);
}
}
}
- // Never call Executor.shutdownNow(), it will cancel the futures it's returned. And since
- // execute() won't return anything, we will hang forever waiting for the execution.
// AppSearch multi-thread execution is guarded by Read & Write Lock in AppSearchImpl, all
// mutate requests will need to gain write lock and query requests need to gain read lock.
- private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();
+ static final Executor EXECUTOR = Executors.newCachedThreadPool();
+
private static volatile LocalStorage sInstance;
private final AppSearchImpl mAppSearchImpl;
/**
- * Opens a new {@link AppSearchSession} on this storage.
+ * Opens a new {@link AppSearchSession} on this storage with executor.
*
* <p>This process requires a native search library. If it's not created, the initialization
* process will create one.
@@ -175,30 +273,10 @@
public static ListenableFuture<AppSearchSession> createSearchSession(
@NonNull SearchContext context) {
Preconditions.checkNotNull(context);
- return createSearchSession(context, EXECUTOR_SERVICE);
- }
-
- /**
- * Opens a new {@link AppSearchSession} on this storage with executor.
- *
- * <p>This process requires a native search library. If it's not created, the initialization
- * process will create one.
- *
- * @param context The {@link SearchContext} contains all information to create a new
- * {@link AppSearchSession}
- * @param executor The executor of where tasks will execute.
- * @hide
- */
- @NonNull
- @VisibleForTesting
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public static ListenableFuture<AppSearchSession> createSearchSession(
- @NonNull SearchContext context, @NonNull ExecutorService executor) {
- Preconditions.checkNotNull(context);
- Preconditions.checkNotNull(executor);
- return FutureUtil.execute(executor, () -> {
- LocalStorage instance = getOrCreateInstance(context.mContext);
- return instance.doCreateSearchSession(context, executor);
+ return FutureUtil.execute(context.mExecutor, () -> {
+ LocalStorage instance = getOrCreateInstance(context.mContext, context.mExecutor,
+ context.mLogger);
+ return instance.doCreateSearchSession(context);
});
}
@@ -208,17 +286,17 @@
* <p>This process requires a native search library. If it's not created, the initialization
* process will create one.
*
- * @param context The {@link GlobalSearchContext} contains all information to create a new
- * {@link GlobalSearchSession}
* @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
public static ListenableFuture<GlobalSearchSession> createGlobalSearchSession(
@NonNull GlobalSearchContext context) {
Preconditions.checkNotNull(context);
- return FutureUtil.execute(EXECUTOR_SERVICE, () -> {
- LocalStorage instance = getOrCreateInstance(context.mContext);
- return instance.doCreateGlobalSearchSession(EXECUTOR_SERVICE);
+ return FutureUtil.execute(context.mExecutor, () -> {
+ LocalStorage instance = getOrCreateInstance(context.mContext, context.mExecutor,
+ context.mLogger);
+ return instance.doCreateGlobalSearchSession(context);
});
}
@@ -231,12 +309,14 @@
@NonNull
@WorkerThread
@VisibleForTesting
- static LocalStorage getOrCreateInstance(@NonNull Context context) throws AppSearchException {
+ static LocalStorage getOrCreateInstance(@NonNull Context context, @NonNull Executor executor,
+ @Nullable AppSearchLogger logger)
+ throws AppSearchException {
Preconditions.checkNotNull(context);
if (sInstance == null) {
synchronized (LocalStorage.class) {
if (sInstance == null) {
- sInstance = new LocalStorage(context);
+ sInstance = new LocalStorage(context, executor, logger);
}
}
}
@@ -244,21 +324,72 @@
}
@WorkerThread
- private LocalStorage(@NonNull Context context) throws AppSearchException {
+ private LocalStorage(
+ @NonNull Context context,
+ @NonNull Executor executor,
+ @Nullable AppSearchLogger logger)
+ throws AppSearchException {
Preconditions.checkNotNull(context);
File icingDir = new File(context.getFilesDir(), ICING_LIB_ROOT_DIR);
- mAppSearchImpl = AppSearchImpl.create(icingDir);
+
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ InitializeStats.Builder initStatsBuilder = null;
+ if (logger != null) {
+ initStatsBuilder = new InitializeStats.Builder();
+ }
+
+ mAppSearchImpl = AppSearchImpl.create(
+ icingDir,
+ new UnlimitedLimitConfig(),
+ initStatsBuilder,
+ new JetpackOptimizeStrategy());
+
+ if (logger != null) {
+ initStatsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis));
+ logger.logStats(initStatsBuilder.build());
+ }
+
+ executor.execute(() -> {
+ long totalOptimizeLatencyStartMillis = SystemClock.elapsedRealtime();
+ OptimizeStats.Builder builder = null;
+ try {
+ if (logger != null) {
+ builder = new OptimizeStats.Builder();
+ }
+ mAppSearchImpl.checkForOptimize(builder);
+ } catch (AppSearchException e) {
+ Log.w(TAG, "Error occurred when check for optimize", e);
+ } finally {
+ if (builder != null) {
+ OptimizeStats oStats = builder
+ .setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime()
+ - totalOptimizeLatencyStartMillis))
+ .build();
+ if (logger != null && oStats.getOriginalDocumentCount() > 0) {
+ // see if optimize has been run by checking originalDocumentCount
+ logger.logStats(builder.build());
+ }
+ }
+ }
+ });
}
@NonNull
- private AppSearchSession doCreateSearchSession(@NonNull SearchContext context,
- @NonNull ExecutorService executor) {
- return new SearchSessionImpl(mAppSearchImpl, executor,
- context.mContext.getPackageName(), context.mDatabaseName);
+ private AppSearchSession doCreateSearchSession(@NonNull SearchContext context) {
+ return new SearchSessionImpl(
+ mAppSearchImpl,
+ context.mExecutor,
+ context.mContext.getPackageName(),
+ context.mDatabaseName,
+ context.mLogger);
}
@NonNull
- private GlobalSearchSession doCreateGlobalSearchSession(@NonNull ExecutorService executor) {
- return new GlobalSearchSessionImpl(mAppSearchImpl, executor);
+ private GlobalSearchSession doCreateGlobalSearchSession(
+ @NonNull GlobalSearchContext context) {
+ return new GlobalSearchSessionImpl(mAppSearchImpl, context.mExecutor, context.mContext,
+ context.mLogger);
}
}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/OptimizeStrategy.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/OptimizeStrategy.java
new file mode 100644
index 0000000..962dc6b
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/OptimizeStrategy.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+import com.google.android.icing.proto.GetOptimizeInfoResultProto;
+
+/**
+ * An interface class for implementing a strategy to determine when to trigger
+ * {@link AppSearchImpl#optimize()}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface OptimizeStrategy {
+
+ /**
+ * Determines whether {@link AppSearchImpl#optimize()} need to be triggered to release garbage
+ * resources in AppSearch base on the given information.
+ *
+ * @param optimizeInfo The proto object indicates the number of garbage resources in AppSearch.
+ * @return {@code true} if {@link AppSearchImpl#optimize()} need to be triggered.
+ */
+ boolean shouldOptimize(@NonNull GetOptimizeInfoResultProto optimizeInfo);
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchResultsImpl.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchResultsImpl.java
index e11f1f0..761ebfd 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchResultsImpl.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchResultsImpl.java
@@ -16,6 +16,8 @@
// @exportToFramework:skipFile()
package androidx.appsearch.localstorage;
+import android.os.Process;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appsearch.app.AppSearchResult;
@@ -24,18 +26,19 @@
import androidx.appsearch.app.SearchResults;
import androidx.appsearch.app.SearchSpec;
import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.stats.SearchStats;
import androidx.appsearch.localstorage.util.FutureUtil;
import androidx.core.util.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executor;
class SearchResultsImpl implements SearchResults {
private final AppSearchImpl mAppSearchImpl;
- private final ExecutorService mExecutorService;
+ private final Executor mExecutor;
// The package name to search over. If null, this will search over all package names.
@Nullable
@@ -55,47 +58,74 @@
private boolean mIsClosed = false;
+ @Nullable
+ private final AppSearchLogger mLogger;
+
+ // Visibility Scope(local vs global) for 1st query, so it can be used for the visibility
+ // scope for getNextPage().
+ @SearchStats.VisibilityScope
+ private int mVisibilityScope = SearchStats.VISIBILITY_SCOPE_UNKNOWN;
+
SearchResultsImpl(
@NonNull AppSearchImpl appSearchImpl,
- @NonNull ExecutorService executorService,
+ @NonNull Executor executor,
@Nullable String packageName,
@Nullable String databaseName,
@NonNull String queryExpression,
- @NonNull SearchSpec searchSpec) {
+ @NonNull SearchSpec searchSpec,
+ @Nullable AppSearchLogger logger) {
mAppSearchImpl = Preconditions.checkNotNull(appSearchImpl);
- mExecutorService = Preconditions.checkNotNull(executorService);
+ mExecutor = Preconditions.checkNotNull(executor);
mPackageName = packageName;
mDatabaseName = databaseName;
mQueryExpression = Preconditions.checkNotNull(queryExpression);
mSearchSpec = Preconditions.checkNotNull(searchSpec);
+ mLogger = logger;
}
@Override
@NonNull
public ListenableFuture<List<SearchResult>> getNextPage() {
Preconditions.checkState(!mIsClosed, "SearchResults has already been closed");
- return FutureUtil.execute(mExecutorService, () -> {
+ return FutureUtil.execute(mExecutor, () -> {
SearchResultPage searchResultPage;
if (mIsFirstLoad) {
mIsFirstLoad = false;
- if (mDatabaseName == null && mPackageName == null) {
- // Global query, there's no one package-database combination to check.
- searchResultPage = mAppSearchImpl.globalQuery(mQueryExpression, mSearchSpec);
- } else if (mPackageName == null) {
+ if (mPackageName == null) {
throw new AppSearchException(
AppSearchResult.RESULT_INVALID_ARGUMENT,
"Invalid null package name for query");
} else if (mDatabaseName == null) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INVALID_ARGUMENT,
- "Invalid null database name for query");
+ mVisibilityScope = SearchStats.VISIBILITY_SCOPE_GLOBAL;
+ // Global queries aren't restricted to a single database
+ searchResultPage = mAppSearchImpl.globalQuery(
+ mQueryExpression,
+ mSearchSpec,
+ mPackageName,
+ /*visibilityStore=*/ null,
+ Process.myUid(),
+ /*callerHasSystemAccess=*/ false,
+ mLogger);
} else {
+ mVisibilityScope = SearchStats.VISIBILITY_SCOPE_LOCAL;
// Normal local query, pass in specified database.
searchResultPage = mAppSearchImpl.query(
- mPackageName, mDatabaseName, mQueryExpression, mSearchSpec);
+ mPackageName, mDatabaseName, mQueryExpression, mSearchSpec, mLogger);
}
} else {
- searchResultPage = mAppSearchImpl.getNextPage(mNextPageToken);
+ SearchStats.Builder sStatsBuilder = null;
+ if (mLogger != null) {
+ sStatsBuilder =
+ new SearchStats.Builder(mVisibilityScope, mPackageName);
+ if (mDatabaseName != null) {
+ sStatsBuilder.setDatabase(mDatabaseName);
+ }
+ }
+ searchResultPage = mAppSearchImpl.getNextPage(mPackageName, mNextPageToken,
+ sStatsBuilder);
+ if (mLogger != null && sStatsBuilder != null) {
+ mLogger.logStats(sStatsBuilder.build());
+ }
}
mNextPageToken = searchResultPage.getNextPageToken();
return searchResultPage.getResults();
@@ -108,8 +138,8 @@
// Checking the future result is not needed here since this is a cleanup step which is not
// critical to the correct functioning of the system; also, the return value is void.
if (!mIsClosed) {
- FutureUtil.execute(mExecutorService, () -> {
- mAppSearchImpl.invalidateNextPageToken(mNextPageToken);
+ FutureUtil.execute(mExecutor, () -> {
+ mAppSearchImpl.invalidateNextPageToken(mPackageName, mNextPageToken);
mIsClosed = true;
return null;
});
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchSessionImpl.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchSessionImpl.java
index 973b724..f2b98e5 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchSessionImpl.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/SearchSessionImpl.java
@@ -18,123 +18,298 @@
import static androidx.appsearch.app.AppSearchResult.throwableToFailedResult;
+import android.os.SystemClock;
+import android.util.Log;
+
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appsearch.app.AppSearchBatchResult;
-import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.AppSearchSession;
import androidx.appsearch.app.GenericDocument;
-import androidx.appsearch.app.GetByUriRequest;
+import androidx.appsearch.app.GetByDocumentIdRequest;
+import androidx.appsearch.app.GetSchemaResponse;
+import androidx.appsearch.app.Migrator;
+import androidx.appsearch.app.PackageIdentifier;
import androidx.appsearch.app.PutDocumentsRequest;
-import androidx.appsearch.app.RemoveByUriRequest;
+import androidx.appsearch.app.RemoveByDocumentIdRequest;
+import androidx.appsearch.app.ReportUsageRequest;
import androidx.appsearch.app.SearchResults;
import androidx.appsearch.app.SearchSpec;
import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.appsearch.app.StorageInfo;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.localstorage.stats.OptimizeStats;
+import androidx.appsearch.localstorage.stats.RemoveStats;
+import androidx.appsearch.localstorage.stats.SchemaMigrationStats;
+import androidx.appsearch.localstorage.stats.SetSchemaStats;
import androidx.appsearch.localstorage.util.FutureUtil;
+import androidx.appsearch.util.SchemaMigrationUtil;
+import androidx.collection.ArrayMap;
import androidx.collection.ArraySet;
import androidx.core.util.Preconditions;
+import com.google.android.icing.proto.PersistType;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executor;
/**
- * An implementation of {@link AppSearchSession} which stores data locally
- * in the app's storage space using a bundled version of the search native library.
+ * An implementation of {@link AppSearchSession} which stores data locally in the app's storage
+ * space using a bundled version of the search native library.
*
* <p>Queries are executed multi-threaded, but a single thread is used for mutate requests (put,
* delete, etc..).
*/
class SearchSessionImpl implements AppSearchSession {
+ private static final String TAG = "AppSearchSessionImpl";
private final AppSearchImpl mAppSearchImpl;
- private final ExecutorService mExecutorService;
+ private final Executor mExecutor;
private final String mPackageName;
private final String mDatabaseName;
- private boolean mIsMutated = false;
- private boolean mIsClosed = false;
+ private volatile boolean mIsMutated = false;
+ private volatile boolean mIsClosed = false;
+ @Nullable private final AppSearchLogger mLogger;
SearchSessionImpl(
@NonNull AppSearchImpl appSearchImpl,
- @NonNull ExecutorService executorService,
+ @NonNull Executor executor,
@NonNull String packageName,
- @NonNull String databaseName) {
+ @NonNull String databaseName,
+ @Nullable AppSearchLogger logger) {
mAppSearchImpl = Preconditions.checkNotNull(appSearchImpl);
- mExecutorService = Preconditions.checkNotNull(executorService);
+ mExecutor = Preconditions.checkNotNull(executor);
mPackageName = packageName;
mDatabaseName = Preconditions.checkNotNull(databaseName);
+ mLogger = logger;
}
@Override
@NonNull
- public ListenableFuture<Void> setSchema(@NonNull SetSchemaRequest request) {
+ public ListenableFuture<SetSchemaResponse> setSchema(
+ @NonNull SetSchemaRequest request) {
Preconditions.checkNotNull(request);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
- return execute(() -> {
- mAppSearchImpl.setSchema(
+
+ ListenableFuture<SetSchemaResponse> future = execute(() -> {
+ long startMillis = SystemClock.elapsedRealtime();
+
+ // Convert the inner set into a List since Binder can't handle Set.
+ Map<String, Set<PackageIdentifier>> schemasVisibleToPackages =
+ request.getSchemasVisibleToPackagesInternal();
+ Map<String, List<PackageIdentifier>> copySchemasVisibleToPackages = new ArrayMap<>();
+ for (Map.Entry<String, Set<PackageIdentifier>> entry :
+ schemasVisibleToPackages.entrySet()) {
+ copySchemasVisibleToPackages.put(entry.getKey(),
+ new ArrayList<>(entry.getValue()));
+ }
+
+ SetSchemaStats.Builder setSchemaStatsBuilder = null;
+ if (mLogger != null) {
+ setSchemaStatsBuilder = new SetSchemaStats.Builder(mPackageName, mDatabaseName);
+ }
+
+ Map<String, Migrator> migrators = request.getMigrators();
+ // No need to trigger migration if user never set migrator.
+ if (migrators.size() == 0) {
+ SetSchemaResponse setSchemaResponse =
+ setSchemaNoMigrations(request, copySchemasVisibleToPackages,
+ setSchemaStatsBuilder);
+ if (setSchemaStatsBuilder != null) {
+ setSchemaStatsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - startMillis));
+ mLogger.logStats(setSchemaStatsBuilder.build());
+ }
+ return setSchemaResponse;
+ }
+
+ // Migration process
+ // 1. Validate and retrieve all active migrators.
+ GetSchemaResponse getSchemaResponse =
+ mAppSearchImpl.getSchema(mPackageName, mDatabaseName);
+ int currentVersion = getSchemaResponse.getVersion();
+ int finalVersion = request.getVersion();
+ Map<String, Migrator> activeMigrators = SchemaMigrationUtil.getActiveMigrators(
+ getSchemaResponse.getSchemas(), migrators, currentVersion, finalVersion);
+ // No need to trigger migration if no migrator is active.
+ if (activeMigrators.size() == 0) {
+ SetSchemaResponse setSchemaResponse =
+ setSchemaNoMigrations(request, copySchemasVisibleToPackages,
+ setSchemaStatsBuilder);
+ if (setSchemaStatsBuilder != null) {
+ setSchemaStatsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - startMillis));
+ mLogger.logStats(setSchemaStatsBuilder.build());
+ }
+ return setSchemaResponse;
+ }
+
+ // 2. SetSchema with forceOverride=false, to retrieve the list of incompatible/deleted
+ // types.
+ long firstSetSchemaLatencyStartMillis = SystemClock.elapsedRealtime();
+ SetSchemaResponse setSchemaResponse = mAppSearchImpl.setSchema(
mPackageName,
mDatabaseName,
new ArrayList<>(request.getSchemas()),
- new ArrayList<>(request.getSchemasNotVisibleToSystemUi()),
- request.isForceOverride());
- mIsMutated = true;
- return null;
+ /*visibilityStore=*/ null,
+ new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
+ copySchemasVisibleToPackages,
+ /*forceOverride=*/false,
+ request.getVersion(),
+ setSchemaStatsBuilder);
+
+ // 3. If forceOverride is false, check that all incompatible types will be migrated.
+ // If some aren't we must throw an error, rather than proceeding and deleting those
+ // types.
+ long queryAndTransformLatencyStartMillis = SystemClock.elapsedRealtime();
+ if (!request.isForceOverride()) {
+ SchemaMigrationUtil.checkDeletedAndIncompatibleAfterMigration(setSchemaResponse,
+ activeMigrators.keySet());
+ }
+
+ SchemaMigrationStats.Builder schemaMigrationStatsBuilder = null;
+ if (setSchemaStatsBuilder != null) {
+ schemaMigrationStatsBuilder = new SchemaMigrationStats.Builder();
+ }
+
+ try (AppSearchMigrationHelper migrationHelper = new AppSearchMigrationHelper(
+ mAppSearchImpl, mPackageName, mDatabaseName, request.getSchemas())) {
+ // 4. Trigger migration for all activity migrators.
+ migrationHelper.queryAndTransform(activeMigrators, currentVersion, finalVersion,
+ schemaMigrationStatsBuilder);
+
+ // 5. SetSchema a second time with forceOverride=true if the first attempted failed
+ // due to backward incompatible changes.
+ long secondSetSchemaLatencyStartMillis = SystemClock.elapsedRealtime();
+ if (!setSchemaResponse.getIncompatibleTypes().isEmpty()
+ || !setSchemaResponse.getDeletedTypes().isEmpty()) {
+ setSchemaResponse = mAppSearchImpl.setSchema(
+ mPackageName,
+ mDatabaseName,
+ new ArrayList<>(request.getSchemas()),
+ /*visibilityStore=*/ null,
+ new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
+ copySchemasVisibleToPackages,
+ /*forceOverride=*/ true,
+ request.getVersion(),
+ setSchemaStatsBuilder);
+ }
+ SetSchemaResponse.Builder responseBuilder = setSchemaResponse.toBuilder()
+ .addMigratedTypes(activeMigrators.keySet());
+ mIsMutated = true;
+
+ // 6. Put all the migrated documents into the index, now that the new schema is set.
+ long saveDocumentLatencyStartMillis = SystemClock.elapsedRealtime();
+ SetSchemaResponse finalSetSchemaResponse =
+ migrationHelper.readAndPutDocuments(responseBuilder,
+ schemaMigrationStatsBuilder);
+
+ if (schemaMigrationStatsBuilder != null) {
+ long endMillis = SystemClock.elapsedRealtime();
+ schemaMigrationStatsBuilder
+ .setSaveDocumentLatencyMillis(
+ (int) (endMillis - saveDocumentLatencyStartMillis))
+ .setGetSchemaLatencyMillis(
+ (int) (firstSetSchemaLatencyStartMillis - startMillis))
+ .setFirstSetSchemaLatencyMillis(
+ (int) (queryAndTransformLatencyStartMillis
+ - firstSetSchemaLatencyStartMillis))
+ .setQueryAndTransformLatencyMillis(
+ (int) (secondSetSchemaLatencyStartMillis
+ - queryAndTransformLatencyStartMillis))
+ .setSecondSetSchemaLatencyMillis(
+ (int) (saveDocumentLatencyStartMillis
+ - secondSetSchemaLatencyStartMillis));
+ setSchemaStatsBuilder
+ .setSchemaMigrationStats(
+ schemaMigrationStatsBuilder.build())
+ .setTotalLatencyMillis((int) (endMillis - startMillis));
+ mLogger.logStats(setSchemaStatsBuilder.build());
+ }
+
+ return finalSetSchemaResponse;
+ }
});
+
+ // setSchema will sync the schemas in the request to AppSearch, any existing schemas which
+ // is not included in the request will be delete if we force override incompatible schemas.
+ // And all documents of these types will be deleted as well. We should checkForOptimize for
+ // these deletion.
+ checkForOptimize();
+ return future;
}
@Override
@NonNull
- public ListenableFuture<Set<AppSearchSchema>> getSchema() {
+ public ListenableFuture<GetSchemaResponse> getSchema() {
+ Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
+ return execute(() -> mAppSearchImpl.getSchema(mPackageName, mDatabaseName));
+ }
+
+ @NonNull
+ @Override
+ public ListenableFuture<Set<String>> getNamespaces() {
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
return execute(() -> {
- List<AppSearchSchema> schemas = mAppSearchImpl.getSchema(mPackageName, mDatabaseName);
- return new ArraySet<>(schemas);
+ List<String> namespaces = mAppSearchImpl.getNamespaces(mPackageName, mDatabaseName);
+ return new ArraySet<>(namespaces);
});
}
@Override
@NonNull
- public ListenableFuture<AppSearchBatchResult<String, Void>> putDocuments(
+ public ListenableFuture<AppSearchBatchResult<String, Void>> put(
@NonNull PutDocumentsRequest request) {
Preconditions.checkNotNull(request);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
- return execute(() -> {
+ ListenableFuture<AppSearchBatchResult<String, Void>> future = execute(() -> {
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
- for (int i = 0; i < request.getDocuments().size(); i++) {
- GenericDocument document = request.getDocuments().get(i);
+ for (int i = 0; i < request.getGenericDocuments().size(); i++) {
+ GenericDocument document = request.getGenericDocuments().get(i);
try {
- mAppSearchImpl.putDocument(mPackageName, mDatabaseName, document);
- resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
+ mAppSearchImpl.putDocument(mPackageName, mDatabaseName, document, mLogger);
+ resultBuilder.setSuccess(document.getId(), /*value=*/ null);
} catch (Throwable t) {
- resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
+ resultBuilder.setResult(document.getId(), throwableToFailedResult(t));
}
}
+ // Now that the batch has been written. Persist the newly written data.
+ mAppSearchImpl.persistToDisk(PersistType.Code.LITE);
mIsMutated = true;
return resultBuilder.build();
});
+
+ // The existing documents with same ID will be deleted, so there may be some resources that
+ // could be released after optimize().
+ checkForOptimize(/*mutateBatchSize=*/ request.getGenericDocuments().size());
+ return future;
}
@Override
@NonNull
- public ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByUri(
- @NonNull GetByUriRequest request) {
+ public ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentId(
+ @NonNull GetByDocumentIdRequest request) {
Preconditions.checkNotNull(request);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
return execute(() -> {
AppSearchBatchResult.Builder<String, GenericDocument> resultBuilder =
new AppSearchBatchResult.Builder<>();
- for (String uri : request.getUris()) {
+ Map<String, List<String>> typePropertyPaths = request.getProjectionsInternal();
+ for (String id : request.getIds()) {
try {
GenericDocument document =
mAppSearchImpl.getDocument(mPackageName, mDatabaseName,
- request.getNamespace(), uri);
- resultBuilder.setSuccess(uri, document);
+ request.getNamespace(), id, typePropertyPaths);
+ resultBuilder.setSuccess(id, document);
} catch (Throwable t) {
- resultBuilder.setResult(uri, throwableToFailedResult(t));
+ resultBuilder.setResult(id, throwableToFailedResult(t));
}
}
return resultBuilder.build();
@@ -143,7 +318,7 @@
@Override
@NonNull
- public SearchResults query(
+ public SearchResults search(
@NonNull String queryExpression,
@NonNull SearchSpec searchSpec) {
Preconditions.checkNotNull(queryExpression);
@@ -151,45 +326,109 @@
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
return new SearchResultsImpl(
mAppSearchImpl,
- mExecutorService,
+ mExecutor,
mPackageName,
mDatabaseName,
queryExpression,
- searchSpec);
+ searchSpec,
+ mLogger);
}
@Override
@NonNull
- public ListenableFuture<AppSearchBatchResult<String, Void>> removeByUri(
- @NonNull RemoveByUriRequest request) {
+ public ListenableFuture<Void> reportUsage(@NonNull ReportUsageRequest request) {
Preconditions.checkNotNull(request);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
return execute(() -> {
- AppSearchBatchResult.Builder<String, Void> resultBuilder =
- new AppSearchBatchResult.Builder<>();
- for (String uri : request.getUris()) {
- try {
- mAppSearchImpl.remove(mPackageName, mDatabaseName, request.getNamespace(), uri);
- resultBuilder.setSuccess(uri, /*result=*/null);
- } catch (Throwable t) {
- resultBuilder.setResult(uri, throwableToFailedResult(t));
- }
- }
+ mAppSearchImpl.reportUsage(
+ mPackageName,
+ mDatabaseName,
+ request.getNamespace(),
+ request.getDocumentId(),
+ request.getUsageTimestampMillis(),
+ /*systemUsage=*/ false);
mIsMutated = true;
- return resultBuilder.build();
+ return null;
});
}
@Override
@NonNull
- public ListenableFuture<Void> removeByQuery(
+ public ListenableFuture<AppSearchBatchResult<String, Void>> remove(
+ @NonNull RemoveByDocumentIdRequest request) {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
+ ListenableFuture<AppSearchBatchResult<String, Void>> future = execute(() -> {
+ AppSearchBatchResult.Builder<String, Void> resultBuilder =
+ new AppSearchBatchResult.Builder<>();
+ for (String id : request.getIds()) {
+ RemoveStats.Builder removeStatsBuilder = null;
+ if (mLogger != null) {
+ removeStatsBuilder = new RemoveStats.Builder(mPackageName, mDatabaseName);
+ }
+
+ try {
+ mAppSearchImpl.remove(mPackageName, mDatabaseName, request.getNamespace(), id,
+ removeStatsBuilder);
+ resultBuilder.setSuccess(id, /*value=*/null);
+ } catch (Throwable t) {
+ resultBuilder.setResult(id, throwableToFailedResult(t));
+ } finally {
+ if (mLogger != null) {
+ mLogger.logStats(removeStatsBuilder.build());
+ }
+ }
+ }
+ // Now that the batch has been written. Persist the newly written data.
+ mAppSearchImpl.persistToDisk(PersistType.Code.LITE);
+ mIsMutated = true;
+ return resultBuilder.build();
+ });
+ checkForOptimize(/*mutateBatchSize=*/ request.getIds().size());
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<Void> remove(
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpec);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
- return execute(() -> {
- mAppSearchImpl.removeByQuery(mPackageName, mDatabaseName, queryExpression, searchSpec);
+ ListenableFuture<Void> future = execute(() -> {
+ RemoveStats.Builder removeStatsBuilder = null;
+ if (mLogger != null) {
+ removeStatsBuilder = new RemoveStats.Builder(mPackageName, mDatabaseName);
+ }
+
+ mAppSearchImpl.removeByQuery(mPackageName, mDatabaseName, queryExpression,
+ searchSpec, removeStatsBuilder);
+ // Now that the batch has been written. Persist the newly written data.
+ mAppSearchImpl.persistToDisk(PersistType.Code.LITE);
mIsMutated = true;
+
+ if (mLogger != null) {
+ mLogger.logStats(removeStatsBuilder.build());
+ }
+
+ return null;
+ });
+ checkForOptimize();
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<StorageInfo> getStorageInfo() {
+ Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
+ return execute(() -> mAppSearchImpl.getStorageInfoForDatabase(mPackageName, mDatabaseName));
+ }
+
+ @NonNull
+ @Override
+ public ListenableFuture<Void> requestFlush() {
+ return execute(() -> {
+ mAppSearchImpl.persistToDisk(PersistType.Code.FULL);
return null;
});
}
@@ -199,8 +438,8 @@
public void close() {
if (mIsMutated && !mIsClosed) {
// No future is needed here since the method is void.
- FutureUtil.execute(mExecutorService, () -> {
- mAppSearchImpl.persistToDisk();
+ FutureUtil.execute(mExecutor, () -> {
+ mAppSearchImpl.persistToDisk(PersistType.Code.FULL);
mIsClosed = true;
return null;
});
@@ -208,6 +447,88 @@
}
private <T> ListenableFuture<T> execute(Callable<T> callable) {
- return FutureUtil.execute(mExecutorService, callable);
+ return FutureUtil.execute(mExecutor, callable);
+ }
+
+ /**
+ * Set schema to Icing for no-migration scenario.
+ *
+ * <p>We only need one time {@link #setSchema} call for no-migration scenario by using the
+ * forceoverride in the request.
+ */
+ private SetSchemaResponse setSchemaNoMigrations(@NonNull SetSchemaRequest request,
+ @NonNull Map<String, List<PackageIdentifier>> copySchemasVisibleToPackages,
+ SetSchemaStats.Builder setSchemaStatsBuilder)
+ throws AppSearchException {
+ SetSchemaResponse setSchemaResponse = mAppSearchImpl.setSchema(
+ mPackageName,
+ mDatabaseName,
+ new ArrayList<>(request.getSchemas()),
+ /*visibilityStore=*/ null,
+ new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
+ copySchemasVisibleToPackages,
+ request.isForceOverride(),
+ request.getVersion(),
+ setSchemaStatsBuilder);
+ if (!request.isForceOverride()) {
+ // check both deleted types and incompatible types are empty. That's the only case we
+ // swallowed in the AppSearchImpl#setSchema().
+ SchemaMigrationUtil.checkDeletedAndIncompatible(setSchemaResponse.getDeletedTypes(),
+ setSchemaResponse.getIncompatibleTypes());
+ }
+ mIsMutated = true;
+ return setSchemaResponse;
+ }
+
+ private void checkForOptimize(int mutateBatchSize) {
+ mExecutor.execute(() -> {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ OptimizeStats.Builder builder = null;
+ try {
+ if (mLogger != null) {
+ builder = new OptimizeStats.Builder();
+ }
+ mAppSearchImpl.checkForOptimize(mutateBatchSize, builder);
+ } catch (AppSearchException e) {
+ Log.w(TAG, "Error occurred when check for optimize", e);
+ } finally {
+ if (builder != null) {
+ OptimizeStats oStats = builder
+ .setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
+ .build();
+ if (mLogger != null && oStats.getOriginalDocumentCount() > 0) {
+ // see if optimize has been run by checking originalDocumentCount
+ mLogger.logStats(oStats);
+ }
+ }
+ }
+ });
+ }
+
+ private void checkForOptimize() {
+ mExecutor.execute(() -> {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ OptimizeStats.Builder builder = null;
+ try {
+ if (mLogger != null) {
+ builder = new OptimizeStats.Builder();
+ }
+ mAppSearchImpl.checkForOptimize(builder);
+ } catch (AppSearchException e) {
+ Log.w(TAG, "Error occurred when check for optimize", e);
+ } finally {
+ if (builder != null) {
+ OptimizeStats oStats = builder
+ .setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
+ .build();
+ if (mLogger != null && oStats.getOriginalDocumentCount() > 0) {
+ // see if optimize has been run by checking originalDocumentCount
+ mLogger.logStats(oStats);
+ }
+ }
+ }
+ });
}
}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/UnlimitedLimitConfig.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/UnlimitedLimitConfig.java
new file mode 100644
index 0000000..f1e99cb
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/UnlimitedLimitConfig.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage;
+
+import androidx.annotation.RestrictTo;
+
+/**
+ * In Jetpack, AppSearch doesn't enforce artificial limits on number of documents or size of
+ * documents, since the app is the only user of the Icing instance. Icing still enforces a docid
+ * limit of 1M docs.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class UnlimitedLimitConfig implements LimitConfig {
+ @Override
+ public int getMaxDocumentSizeBytes() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getMaxDocumentCount() {
+ return Integer.MAX_VALUE;
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/VisibilityStore.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/VisibilityStore.java
deleted file mode 100644
index 186cf93..0000000
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/VisibilityStore.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appsearch.localstorage;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.appsearch.app.AppSearchResult;
-import androidx.appsearch.app.AppSearchSchema;
-import androidx.appsearch.app.GenericDocument;
-import androidx.appsearch.exceptions.AppSearchException;
-import androidx.collection.ArrayMap;
-import androidx.collection.ArraySet;
-import androidx.core.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Manages any visibility settings for all the databases that AppSearchImpl knows about. Persists
- * the visibility settings and reloads them on initialization.
- *
- * <p>The VisibilityStore creates a document for each database. This document holds the visibility
- * settings that apply to that database. The VisibilityStore also creates a schema for these
- * documents and has its own database so that its data doesn't interfere with any clients' data.
- * It persists the document and schema through AppSearchImpl.
- *
- * <p>These visibility settings are used to ensure AppSearch queries respect the clients'
- * settings on who their data is visible to.
- *
- * <p>This class doesn't handle any locking itself. Its callers should handle the locking at a
- * higher level.
- *
- * <p>NOTE: This class holds an instance of AppSearchImpl and AppSearchImpl holds an instance of
- * this class. Take care to not cause any circular dependencies.
- */
-class VisibilityStore {
- /** Schema type for documents that hold AppSearch's metadata, e.g. visibility settings */
- @VisibleForTesting
- static final String SCHEMA_TYPE = "Visibility";
-
- /**
- * Property that holds the list of platform-hidden schemas, as part of the visibility settings.
- */
- @VisibleForTesting
- static final String NOT_PLATFORM_SURFACEABLE_PROPERTY = "notPlatformSurfaceable";
-
- /** Schema for the VisibilityStore's docuemnts. */
- @VisibleForTesting
- static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder(
- NOT_PLATFORM_SURFACEABLE_PROPERTY)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(
- AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .build())
- .build();
-
- /**
- * These cannot have any of the special characters used by AppSearchImpl (e.g.
- * {@link AppSearchImpl#PACKAGE_DELIMITER} or {@link AppSearchImpl#DATABASE_DELIMITER}.
- */
- static final String PACKAGE_NAME = "VS#Pkg";
- static final String DATABASE_NAME = "VS#Db";
-
- /**
- * Prefix that AppSearchImpl creates for the VisibilityStore based on our package name and
- * database name. Tracked here to tell when we're looking at our own prefix when looking
- * through AppSearchImpl.
- */
- private static final String VISIBILITY_STORE_PREFIX = AppSearchImpl.createPrefix(PACKAGE_NAME,
- DATABASE_NAME);
-
- /** Namespace of documents that contain visibility settings */
- private static final String NAMESPACE = GenericDocument.DEFAULT_NAMESPACE;
-
- /**
- * Prefix to add to all visibility document uri's. IcingSearchEngine doesn't allow empty
- * uri's.
- */
- private static final String URI_PREFIX = "uri:";
-
- private final AppSearchImpl mAppSearchImpl;
-
- /**
- * Maps prefixes to the set of schemas that are platform-hidden within that prefix. All schemas
- * in the map are prefixed.
- */
- private final Map<String, Set<String>> mNotPlatformSurfaceableMap = new ArrayMap<>();
-
- /**
- * Creates an uninitialized VisibilityStore object. Callers must also call {@link #initialize()}
- * before using the object.
- *
- * @param appSearchImpl AppSearchImpl instance
- */
- VisibilityStore(@NonNull AppSearchImpl appSearchImpl) {
- mAppSearchImpl = appSearchImpl;
- }
-
- /**
- * Initializes schemas and member variables to track visibility settings.
- *
- * <p>This is kept separate from the constructor because this will call methods on
- * AppSearchImpl. Some may even then recursively call back into VisibilityStore (for example,
- * {@link AppSearchImpl#setSchema} will call {@link #setVisibility(String, Set)}. We need to
- * have both
- * AppSearchImpl and VisibilityStore fully initialized for this call flow to work.
- *
- * @throws AppSearchException AppSearchException on AppSearchImpl error.
- */
- public void initialize() throws AppSearchException {
- if (!mAppSearchImpl.hasSchemaTypeLocked(PACKAGE_NAME, DATABASE_NAME, SCHEMA_TYPE)) {
- // Schema type doesn't exist yet. Add it.
- mAppSearchImpl.setSchema(PACKAGE_NAME, DATABASE_NAME,
- Collections.singletonList(SCHEMA),
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*forceOverride=*/ false);
- }
-
- // Populate visibility settings set
- mNotPlatformSurfaceableMap.clear();
- for (String prefix : mAppSearchImpl.getPrefixesLocked()) {
- if (prefix.equals(VISIBILITY_STORE_PREFIX)) {
- // Our own prefix. Skip
- continue;
- }
-
- try {
- // Note: We use the other clients' prefixed names as uris
- GenericDocument document = mAppSearchImpl.getDocument(
- PACKAGE_NAME, DATABASE_NAME, NAMESPACE, /*uri=*/ addUriPrefix(prefix));
-
- String[] schemas = document.getPropertyStringArray(
- NOT_PLATFORM_SURFACEABLE_PROPERTY);
- mNotPlatformSurfaceableMap.put(prefix,
- new ArraySet<>(Arrays.asList(schemas)));
- } catch (AppSearchException e) {
- if (e.getResultCode() == AppSearchResult.RESULT_NOT_FOUND) {
- // TODO(b/172068212): This indicates some desync error. We were expecting a
- // document, but didn't find one. Should probably reset AppSearch instead of
- // ignoring it.
- continue;
- }
- // Otherwise, this is some other error we should pass up.
- throw e;
- }
- }
- }
-
- /**
- * Sets visibility settings for {@code prefix}. Any previous visibility settings will be
- * overwritten.
- *
- * @param prefix Prefix that identifies who owns the {@code
- * schemasNotPlatformSurfaceable}.
- * @param schemasNotPlatformSurfaceable Set of prefixed schemas that should be
- * hidden from the platform.
- * @throws AppSearchException on AppSearchImpl error.
- */
- public void setVisibility(@NonNull String prefix,
- @NonNull Set<String> schemasNotPlatformSurfaceable) throws AppSearchException {
- Preconditions.checkNotNull(prefix);
- Preconditions.checkNotNull(schemasNotPlatformSurfaceable);
-
- // Persist the document
- GenericDocument.Builder visibilityDocument = new GenericDocument.Builder(
- /*uri=*/ addUriPrefix(prefix), SCHEMA_TYPE)
- .setNamespace(NAMESPACE);
- if (!schemasNotPlatformSurfaceable.isEmpty()) {
- visibilityDocument.setPropertyString(NOT_PLATFORM_SURFACEABLE_PROPERTY,
- schemasNotPlatformSurfaceable.toArray(new String[0]));
- }
- mAppSearchImpl.putDocument(PACKAGE_NAME, DATABASE_NAME, visibilityDocument.build());
-
- // Update derived data structures.
- mNotPlatformSurfaceableMap.put(prefix, schemasNotPlatformSurfaceable);
- }
-
- /** Returns if the schema is surfaceable by the platform. */
- @NonNull
- public boolean isSchemaPlatformSurfaceable(@NonNull String prefix,
- @NonNull String prefixedSchema) {
- Preconditions.checkNotNull(prefix);
- Preconditions.checkNotNull(prefixedSchema);
- Set<String> notPlatformSurfaceableSchemas = mNotPlatformSurfaceableMap.get(prefix);
- if (notPlatformSurfaceableSchemas == null) {
- return true;
- }
- return !notPlatformSurfaceableSchemas.contains(prefixedSchema);
- }
-
- /**
- * Handles an {@code AppSearchImpl#reset()} by clearing any cached state.
- *
- * <p> {@link #initialize()} must be called after this.
- */
- void handleReset() {
- mNotPlatformSurfaceableMap.clear();
- }
-
- /**
- * Adds a uri prefix to create a visibility store document's uri.
- *
- * @param uri Non-prefixed uri
- * @return Prefixed uri
- */
- private static String addUriPrefix(String uri) {
- return URI_PREFIX + uri;
- }
-}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverter.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverter.java
index c598045..eb5a117 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverter.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/GenericDocumentToProtoConverter.java
@@ -18,15 +18,18 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.GenericDocument;
import androidx.core.util.Preconditions;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.protobuf.ByteString;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Map;
/**
* Translates a {@link GenericDocument} into a {@link DocumentProto}.
@@ -35,15 +38,25 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final class GenericDocumentToProtoConverter {
- private GenericDocumentToProtoConverter() {}
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final long[] EMPTY_LONG_ARRAY = new long[0];
+ private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+ private static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
+ private static final byte[][] EMPTY_BYTES_ARRAY = new byte[0][0];
+ private static final GenericDocument[] EMPTY_DOCUMENT_ARRAY = new GenericDocument[0];
- /** Converts a {@link GenericDocument} into a {@link DocumentProto}. */
+ private GenericDocumentToProtoConverter() {
+ }
+
+ /**
+ * Converts a {@link GenericDocument} into a {@link DocumentProto}.
+ */
@NonNull
@SuppressWarnings("unchecked")
public static DocumentProto toDocumentProto(@NonNull GenericDocument document) {
Preconditions.checkNotNull(document);
DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
- mProtoBuilder.setUri(document.getUri())
+ mProtoBuilder.setUri(document.getId())
.setSchema(document.getSchemaType())
.setNamespace(document.getNamespace())
.setScore(document.getScore())
@@ -96,16 +109,34 @@
return mProtoBuilder.build();
}
- /** Converts a {@link DocumentProto} into a {@link GenericDocument}. */
+ /**
+ * Converts a {@link DocumentProto} into a {@link GenericDocument}.
+ *
+ * <p>In the case that the {@link DocumentProto} object proto has no values set, the
+ * converter searches for the matching property name in the {@link SchemaTypeConfigProto}
+ * object for the document, and infers the correct default value to set for the empty
+ * property based on the data type of the property defined by the schema type.
+ *
+ * @param proto the document to convert to a {@link GenericDocument} instance. The
+ * document proto should have its package + database prefix stripped
+ * from its fields.
+ * @param prefix the package + database prefix used searching the {@code schemaTypeMap}.
+ * @param schemaTypeMap map of prefixed schema type to {@link SchemaTypeConfigProto}, used
+ * for looking up the default empty value to set for a document property
+ * that has all empty values.
+ */
@NonNull
- public static GenericDocument toGenericDocument(@NonNull DocumentProto proto) {
+ public static GenericDocument toGenericDocument(@NonNull DocumentProto proto,
+ @NonNull String prefix,
+ @NonNull Map<String, SchemaTypeConfigProto> schemaTypeMap) {
Preconditions.checkNotNull(proto);
GenericDocument.Builder<?> documentBuilder =
- new GenericDocument.Builder<>(proto.getUri(), proto.getSchema())
- .setNamespace(proto.getNamespace())
+ new GenericDocument.Builder<>(proto.getNamespace(), proto.getUri(),
+ proto.getSchema())
.setScore(proto.getScore())
.setTtlMillis(proto.getTtlMs())
.setCreationTimestampMillis(proto.getCreationTimestampMs());
+ String prefixedSchemaType = prefix + proto.getSchema();
for (int i = 0; i < proto.getPropertiesCount(); i++) {
PropertyProto property = proto.getProperties(i);
@@ -143,13 +174,51 @@
} else if (property.getDocumentValuesCount() > 0) {
GenericDocument[] values = new GenericDocument[property.getDocumentValuesCount()];
for (int j = 0; j < values.length; j++) {
- values[j] = toGenericDocument(property.getDocumentValues(j));
+ values[j] = toGenericDocument(property.getDocumentValues(j), prefix,
+ schemaTypeMap);
}
documentBuilder.setPropertyDocument(name, values);
} else {
- throw new IllegalStateException("Unknown type of value: " + name);
+ // TODO(b/184966497): Optimize by caching PropertyConfigProto
+ setEmptyProperty(name, documentBuilder,
+ schemaTypeMap.get(prefixedSchemaType));
}
}
return documentBuilder.build();
}
+
+ private static void setEmptyProperty(@NonNull String propertyName,
+ @NonNull GenericDocument.Builder<?> documentBuilder,
+ @NonNull SchemaTypeConfigProto schema) {
+ @AppSearchSchema.PropertyConfig.DataType int dataType = 0;
+ for (int i = 0; i < schema.getPropertiesCount(); ++i) {
+ if (propertyName.equals(schema.getProperties(i).getPropertyName())) {
+ dataType = schema.getProperties(i).getDataType().getNumber();
+ break;
+ }
+ }
+
+ switch (dataType) {
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
+ documentBuilder.setPropertyString(propertyName, EMPTY_STRING_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_LONG:
+ documentBuilder.setPropertyLong(propertyName, EMPTY_LONG_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
+ documentBuilder.setPropertyDouble(propertyName, EMPTY_DOUBLE_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
+ documentBuilder.setPropertyBoolean(propertyName, EMPTY_BOOLEAN_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
+ documentBuilder.setPropertyBytes(propertyName, EMPTY_BYTES_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
+ documentBuilder.setPropertyDocument(propertyName, EMPTY_DOCUMENT_ARRAY);
+ break;
+ default:
+ throw new IllegalStateException("Unknown type of value: " + propertyName);
+ }
+ }
}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/ResultCodeToProtoConverter.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/ResultCodeToProtoConverter.java
new file mode 100644
index 0000000..e04d756
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/ResultCodeToProtoConverter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.converter;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+
+import com.google.android.icing.proto.StatusProto;
+
+/**
+ * Translates an {@link StatusProto.Code} into a {@link AppSearchResult.ResultCode}
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class ResultCodeToProtoConverter {
+
+ private static final String TAG = "AppSearchResultCodeToPr";
+ private ResultCodeToProtoConverter() {}
+
+ /** Converts an {@link StatusProto.Code} into a {@link AppSearchResult.ResultCode}. */
+ public static @AppSearchResult.ResultCode int toResultCode(
+ @NonNull StatusProto.Code statusCode) {
+ switch (statusCode) {
+ case OK:
+ return AppSearchResult.RESULT_OK;
+ case OUT_OF_SPACE:
+ return AppSearchResult.RESULT_OUT_OF_SPACE;
+ case INTERNAL:
+ return AppSearchResult.RESULT_INTERNAL_ERROR;
+ case UNKNOWN:
+ return AppSearchResult.RESULT_UNKNOWN_ERROR;
+ case NOT_FOUND:
+ return AppSearchResult.RESULT_NOT_FOUND;
+ case INVALID_ARGUMENT:
+ return AppSearchResult.RESULT_INVALID_ARGUMENT;
+ default:
+ // Some unknown/unsupported error
+ Log.e(TAG, "Cannot convert IcingSearchEngine status code: "
+ + statusCode + " to AppSearchResultCode.");
+ return AppSearchResult.RESULT_INTERNAL_ERROR;
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverter.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverter.java
index f52c220..4e3e3a9 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverter.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SchemaToProtoConverter.java
@@ -23,6 +23,7 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.core.util.Preconditions;
+import com.google.android.icing.proto.DocumentIndexingConfig;
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProtoOrBuilder;
@@ -46,10 +47,12 @@
* {@link SchemaTypeConfigProto}.
*/
@NonNull
- public static SchemaTypeConfigProto toSchemaTypeConfigProto(@NonNull AppSearchSchema schema) {
+ public static SchemaTypeConfigProto toSchemaTypeConfigProto(@NonNull AppSearchSchema schema,
+ int version) {
Preconditions.checkNotNull(schema);
- SchemaTypeConfigProto.Builder protoBuilder =
- SchemaTypeConfigProto.newBuilder().setSchemaType(schema.getSchemaType());
+ SchemaTypeConfigProto.Builder protoBuilder = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(schema.getSchemaType())
+ .setVersion(version);
List<AppSearchSchema.PropertyConfig> properties = schema.getProperties();
for (int i = 0; i < properties.size(); i++) {
PropertyConfigProto propertyProto = toPropertyConfigProto(properties.get(i));
@@ -64,7 +67,6 @@
Preconditions.checkNotNull(property);
PropertyConfigProto.Builder builder = PropertyConfigProto.newBuilder()
.setPropertyName(property.getName());
- StringIndexingConfig.Builder indexingConfig = StringIndexingConfig.newBuilder();
// Set dataType
@AppSearchSchema.PropertyConfig.DataType int dataType = property.getDataType();
@@ -75,12 +77,6 @@
}
builder.setDataType(dataTypeProto);
- // Set schemaType
- String schemaType = property.getSchemaType();
- if (schemaType != null) {
- builder.setSchemaType(schemaType);
- }
-
// Set cardinality
@AppSearchSchema.PropertyConfig.Cardinality int cardinality = property.getCardinality();
PropertyConfigProto.Cardinality.Code cardinalityProto =
@@ -90,36 +86,25 @@
}
builder.setCardinality(cardinalityProto);
- // Set indexingType
- @AppSearchSchema.PropertyConfig.IndexingType int indexingType = property.getIndexingType();
- TermMatchType.Code termMatchTypeProto;
- switch (indexingType) {
- case AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE:
- termMatchTypeProto = TermMatchType.Code.UNKNOWN;
- break;
- case AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS:
- termMatchTypeProto = TermMatchType.Code.EXACT_ONLY;
- break;
- case AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES:
- termMatchTypeProto = TermMatchType.Code.PREFIX;
- break;
- default:
- throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
- }
- indexingConfig.setTermMatchType(termMatchTypeProto);
+ if (property instanceof AppSearchSchema.StringPropertyConfig) {
+ AppSearchSchema.StringPropertyConfig stringProperty =
+ (AppSearchSchema.StringPropertyConfig) property;
+ StringIndexingConfig stringIndexingConfig = StringIndexingConfig.newBuilder()
+ .setTermMatchType(convertTermMatchTypeToProto(stringProperty.getIndexingType()))
+ .setTokenizerType(
+ convertTokenizerTypeToProto(stringProperty.getTokenizerType()))
+ .build();
+ builder.setStringIndexingConfig(stringIndexingConfig);
- // Set tokenizerType
- @AppSearchSchema.PropertyConfig.TokenizerType int tokenizerType =
- property.getTokenizerType();
- StringIndexingConfig.TokenizerType.Code tokenizerTypeProto =
- StringIndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
- if (tokenizerTypeProto == null) {
- throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
+ } else if (property instanceof AppSearchSchema.DocumentPropertyConfig) {
+ AppSearchSchema.DocumentPropertyConfig documentProperty =
+ (AppSearchSchema.DocumentPropertyConfig) property;
+ builder
+ .setSchemaType(documentProperty.getSchemaType())
+ .setDocumentIndexingConfig(
+ DocumentIndexingConfig.newBuilder().setIndexNestedProperties(
+ documentProperty.shouldIndexNestedProperties()));
}
- indexingConfig.setTokenizerType(tokenizerTypeProto);
-
- // Build!
- builder.setStringIndexingConfig(indexingConfig);
return builder.build();
}
@@ -130,7 +115,8 @@
@NonNull
public static AppSearchSchema toAppSearchSchema(@NonNull SchemaTypeConfigProtoOrBuilder proto) {
Preconditions.checkNotNull(proto);
- AppSearchSchema.Builder builder = new AppSearchSchema.Builder(proto.getSchemaType());
+ AppSearchSchema.Builder builder =
+ new AppSearchSchema.Builder(proto.getSchemaType());
List<PropertyConfigProto> properties = proto.getPropertiesList();
for (int i = 0; i < properties.size(); i++) {
AppSearchSchema.PropertyConfig propertyConfig = toPropertyConfig(properties.get(i));
@@ -143,39 +129,99 @@
private static AppSearchSchema.PropertyConfig toPropertyConfig(
@NonNull PropertyConfigProto proto) {
Preconditions.checkNotNull(proto);
- AppSearchSchema.PropertyConfig.Builder builder =
- new AppSearchSchema.PropertyConfig.Builder(proto.getPropertyName())
- .setDataType(proto.getDataType().getNumber())
+ switch (proto.getDataType()) {
+ case STRING:
+ return toStringPropertyConfig(proto);
+ case INT64:
+ return new AppSearchSchema.LongPropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case DOUBLE:
+ return new AppSearchSchema.DoublePropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case BOOLEAN:
+ return new AppSearchSchema.BooleanPropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case BYTES:
+ return new AppSearchSchema.BytesPropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case DOCUMENT:
+ return toDocumentPropertyConfig(proto);
+ default:
+ throw new IllegalArgumentException("Invalid dataType: " + proto.getDataType());
+ }
+ }
+
+ @NonNull
+ private static AppSearchSchema.StringPropertyConfig toStringPropertyConfig(
+ @NonNull PropertyConfigProto proto) {
+ AppSearchSchema.StringPropertyConfig.Builder builder =
+ new AppSearchSchema.StringPropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.setTokenizerType(
proto.getStringIndexingConfig().getTokenizerType().getNumber());
- // Set schema
- if (!proto.getSchemaType().isEmpty()) {
- builder.setSchemaType(proto.getSchemaType());
- }
-
// Set indexingType
- @AppSearchSchema.PropertyConfig.IndexingType int indexingType;
TermMatchType.Code termMatchTypeProto = proto.getStringIndexingConfig().getTermMatchType();
- switch (termMatchTypeProto) {
+ builder.setIndexingType(convertTermMatchTypeFromProto(termMatchTypeProto));
+
+ return builder.build();
+ }
+
+ @NonNull
+ private static AppSearchSchema.DocumentPropertyConfig toDocumentPropertyConfig(
+ @NonNull PropertyConfigProto proto) {
+ return new AppSearchSchema.DocumentPropertyConfig.Builder(
+ proto.getPropertyName(), proto.getSchemaType())
+ .setCardinality(proto.getCardinality().getNumber())
+ .setShouldIndexNestedProperties(
+ proto.getDocumentIndexingConfig().getIndexNestedProperties())
+ .build();
+ }
+
+ @NonNull
+ private static TermMatchType.Code convertTermMatchTypeToProto(
+ @AppSearchSchema.StringPropertyConfig.IndexingType int indexingType) {
+ switch (indexingType) {
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
+ return TermMatchType.Code.UNKNOWN;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
+ return TermMatchType.Code.EXACT_ONLY;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
+ return TermMatchType.Code.PREFIX;
+ default:
+ throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
+ }
+ }
+
+ @AppSearchSchema.StringPropertyConfig.IndexingType
+ private static int convertTermMatchTypeFromProto(@NonNull TermMatchType.Code termMatchType) {
+ switch (termMatchType) {
case UNKNOWN:
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
- break;
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
case EXACT_ONLY:
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS;
- break;
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS;
case PREFIX:
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
- break;
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
default:
// Avoid crashing in the 'read' path; we should try to interpret the document to the
// extent possible.
- Log.w(TAG, "Invalid indexingType: " + termMatchTypeProto.getNumber());
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
+ Log.w(TAG, "Invalid indexingType: " + termMatchType.getNumber());
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
}
- builder.setIndexingType(indexingType);
+ }
- return builder.build();
+ @NonNull
+ private static StringIndexingConfig.TokenizerType.Code convertTokenizerTypeToProto(
+ @AppSearchSchema.StringPropertyConfig.TokenizerType int tokenizerType) {
+ StringIndexingConfig.TokenizerType.Code tokenizerTypeProto =
+ StringIndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
+ if (tokenizerTypeProto == null) {
+ throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
+ }
+ return tokenizerTypeProto;
}
}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchResultToProtoConverter.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchResultToProtoConverter.java
index d53492e..b3da971 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchResultToProtoConverter.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchResultToProtoConverter.java
@@ -16,6 +16,8 @@
package androidx.appsearch.localstorage.converter;
+import static androidx.appsearch.localstorage.util.PrefixUtil.createPrefix;
+
import android.os.Bundle;
import androidx.annotation.NonNull;
@@ -25,6 +27,7 @@
import androidx.appsearch.app.SearchResultPage;
import androidx.core.util.Preconditions;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchResultProtoOrBuilder;
import com.google.android.icing.proto.SnippetMatchProto;
@@ -32,6 +35,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Translates a {@link SearchResultProto} into {@link SearchResult}s.
@@ -46,23 +50,34 @@
/**
* Translate a {@link SearchResultProto} into {@link SearchResultPage}.
*
- * @param proto The {@link SearchResultProto} containing results.
- * @param packageNames A parallel array of package names. The package name at index 'i' of
- * this list should be the package that indexed the document at index 'i'
- * of proto.getResults(i).
+ * @param proto The {@link SearchResultProto} containing results.
+ * @param packageNames A parallel array of package names. The package name at index 'i' of
+ * this list should be the package that indexed the document at index 'i'
+ * of proto.getResults(i).
+ * @param databaseNames A parallel array of database names. The database name at index 'i' of
+ * this list shold be the database that indexed the document at index 'i'
+ * of proto.getResults(i).
+ * @param schemaMap A map of prefixes to an inner-map of prefixed schema type to
+ * SchemaTypeConfigProtos, used for setting a default value for results
+ * with DocumentProtos that have empty values.
* @return {@link SearchResultPage} of results.
*/
@NonNull
public static SearchResultPage toSearchResultPage(@NonNull SearchResultProtoOrBuilder proto,
- @NonNull List<String> packageNames) {
- Preconditions.checkArgument(proto.getResultsCount() == packageNames.size(), "Size of "
- + "results does not match the number of package names.");
+ @NonNull List<String> packageNames, @NonNull List<String> databaseNames,
+ @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap) {
+ Preconditions.checkArgument(
+ proto.getResultsCount() == packageNames.size(),
+ "Size of results does not match the number of package names.");
Bundle bundle = new Bundle();
bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
for (int i = 0; i < proto.getResultsCount(); i++) {
- resultBundles.add(toSearchResultBundle(proto.getResults(i),
- packageNames.get(i)));
+ String prefix = createPrefix(packageNames.get(i), databaseNames.get(i));
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = schemaMap.get(prefix);
+ SearchResult result = toSearchResult(
+ proto.getResults(i), packageNames.get(i), databaseNames.get(i), schemaTypeMap);
+ resultBundles.add(result.getBundle());
}
bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
return new SearchResultPage(bundle);
@@ -71,53 +86,53 @@
/**
* Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}.
*
- * @param proto The proto to be converted.
- * @param packageName The package name associated with the document in {@code proto}.
+ * @param proto The proto to be converted.
+ * @param packageName The package name associated with the document in {@code proto}.
+ * @param databaseName The database name associated with the document in {@code proto}.
+ * @param schemaTypeToProtoMap A map of prefixed schema types to their corresponding
+ * SchemaTypeConfigProto, used for setting a default value for
+ * results with DocumentProtos that have empty values.
* @return A {@link SearchResult} bundle.
*/
@NonNull
- private static Bundle toSearchResultBundle(
- @NonNull SearchResultProto.ResultProtoOrBuilder proto, @NonNull String packageName) {
- Bundle bundle = new Bundle();
+ private static SearchResult toSearchResult(
+ @NonNull SearchResultProto.ResultProtoOrBuilder proto,
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull Map<String, SchemaTypeConfigProto> schemaTypeToProtoMap) {
+ String prefix = createPrefix(packageName, databaseName);
GenericDocument document =
- GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
- bundle.putBundle(SearchResult.DOCUMENT_FIELD, document.getBundle());
- bundle.putString(SearchResult.PACKAGE_NAME_FIELD, packageName);
-
- ArrayList<Bundle> matchList = new ArrayList<>();
+ GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument(), prefix,
+ schemaTypeToProtoMap);
+ SearchResult.Builder builder =
+ new SearchResult.Builder(packageName, databaseName)
+ .setGenericDocument(document).setRankingSignal(proto.getScore());
if (proto.hasSnippet()) {
for (int i = 0; i < proto.getSnippet().getEntriesCount(); i++) {
SnippetProto.EntryProto entry = proto.getSnippet().getEntries(i);
for (int j = 0; j < entry.getSnippetMatchesCount(); j++) {
- Bundle matchInfoBundle = convertToMatchInfoBundle(
+ SearchResult.MatchInfo matchInfo = toMatchInfo(
entry.getSnippetMatches(j), entry.getPropertyName());
- matchList.add(matchInfoBundle);
+ builder.addMatchInfo(matchInfo);
}
}
}
- bundle.putParcelableArrayList(SearchResult.MATCHES_FIELD, matchList);
-
- return bundle;
+ return builder.build();
}
- private static Bundle convertToMatchInfoBundle(
- SnippetMatchProto snippetMatchProto, String propertyPath) {
- Bundle bundle = new Bundle();
- bundle.putString(SearchResult.MatchInfo.PROPERTY_PATH_FIELD, propertyPath);
- bundle.putInt(
- SearchResult.MatchInfo.VALUES_INDEX_FIELD, snippetMatchProto.getValuesIndex());
- bundle.putInt(
- SearchResult.MatchInfo.EXACT_MATCH_POSITION_LOWER_FIELD,
- snippetMatchProto.getExactMatchPosition());
- bundle.putInt(
- SearchResult.MatchInfo.EXACT_MATCH_POSITION_UPPER_FIELD,
- snippetMatchProto.getExactMatchPosition() + snippetMatchProto.getExactMatchBytes());
- bundle.putInt(
- SearchResult.MatchInfo.WINDOW_POSITION_LOWER_FIELD,
- snippetMatchProto.getWindowPosition());
- bundle.putInt(
- SearchResult.MatchInfo.WINDOW_POSITION_UPPER_FIELD,
- snippetMatchProto.getWindowPosition() + snippetMatchProto.getWindowBytes());
- return bundle;
+ private static SearchResult.MatchInfo toMatchInfo(
+ @NonNull SnippetMatchProto snippetMatchProto, @NonNull String propertyPath) {
+ return new SearchResult.MatchInfo.Builder(propertyPath)
+ .setExactMatchRange(
+ new SearchResult.MatchRange(
+ snippetMatchProto.getExactMatchUtf16Position(),
+ snippetMatchProto.getExactMatchUtf16Position()
+ + snippetMatchProto.getExactMatchUtf16Length()))
+ .setSnippetRange(
+ new SearchResult.MatchRange(
+ snippetMatchProto.getWindowUtf16Position(),
+ snippetMatchProto.getWindowUtf16Position()
+ + snippetMatchProto.getWindowUtf16Length()))
+ .build();
}
}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java
index 485d361..abc97f3 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java
@@ -25,10 +25,6 @@
import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.TermMatchType;
-import com.google.android.icing.proto.TypePropertyMask;
-
-import java.util.List;
-import java.util.Map;
/**
* Translates a {@link SearchSpec} into icing search protos.
@@ -45,8 +41,8 @@
public static SearchSpecProto toSearchSpecProto(@NonNull SearchSpec spec) {
Preconditions.checkNotNull(spec);
SearchSpecProto.Builder protoBuilder = SearchSpecProto.newBuilder()
- .addAllSchemaTypeFilters(spec.getSchemaTypes())
- .addAllNamespaceFilters(spec.getNamespaces());
+ .addAllSchemaTypeFilters(spec.getFilterSchemas())
+ .addAllNamespaceFilters(spec.getFilterNamespaces());
@SearchSpec.TermMatch int termMatchCode = spec.getTermMatch();
TermMatchType.Code termMatchCodeProto = TermMatchType.Code.forNumber(termMatchCode);
@@ -62,20 +58,15 @@
@NonNull
public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
Preconditions.checkNotNull(spec);
- ResultSpecProto.Builder builder = ResultSpecProto.newBuilder()
+ return ResultSpecProto.newBuilder()
.setNumPerPage(spec.getResultCountPerPage())
.setSnippetSpec(
ResultSpecProto.SnippetSpecProto.newBuilder()
.setNumToSnippet(spec.getSnippetCount())
.setNumMatchesPerProperty(spec.getSnippetCountPerProperty())
- .setMaxWindowBytes(spec.getMaxSnippetSize()));
- Map<String, List<String>> projectionTypePropertyPaths = spec.getProjections();
- for (Map.Entry<String, List<String>> e : projectionTypePropertyPaths.entrySet()) {
- builder.addTypePropertyMasks(
- TypePropertyMask.newBuilder().setSchemaType(
- e.getKey()).addAllPaths(e.getValue()));
- }
- return builder.build();
+ .setMaxWindowBytes(spec.getMaxSnippetSize()))
+ .addAllTypePropertyMasks(TypePropertyPathToProtoConverter.toTypePropertyMaskList(
+ spec.getProjections())).build();
}
/** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */
@@ -107,6 +98,14 @@
return ScoringSpecProto.RankingStrategy.Code.CREATION_TIMESTAMP;
case SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE:
return ScoringSpecProto.RankingStrategy.Code.RELEVANCE_SCORE;
+ case SearchSpec.RANKING_STRATEGY_USAGE_COUNT:
+ return ScoringSpecProto.RankingStrategy.Code.USAGE_TYPE1_COUNT;
+ case SearchSpec.RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP:
+ return ScoringSpecProto.RankingStrategy.Code.USAGE_TYPE1_LAST_USED_TIMESTAMP;
+ case SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_COUNT:
+ return ScoringSpecProto.RankingStrategy.Code.USAGE_TYPE2_COUNT;
+ case SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP:
+ return ScoringSpecProto.RankingStrategy.Code.USAGE_TYPE2_LAST_USED_TIMESTAMP;
default:
throw new IllegalArgumentException("Invalid result ranking strategy: "
+ rankingStrategyCode);
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SetSchemaResponseToProtoConverter.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SetSchemaResponseToProtoConverter.java
new file mode 100644
index 0000000..62d788c
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/SetSchemaResponseToProtoConverter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.converter;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.core.util.Preconditions;
+
+import com.google.android.icing.proto.SetSchemaResultProto;
+
+/**
+ * Translates a {@link SetSchemaResultProto} into {@link SetSchemaResponse}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class SetSchemaResponseToProtoConverter {
+
+ private SetSchemaResponseToProtoConverter() {}
+
+ /**
+ * Translate a {@link SetSchemaResultProto} into {@link SetSchemaResponse}.
+ *
+ * @param proto The {@link SetSchemaResultProto} containing results.
+ * @param prefix The prefix need to removed from schemaTypes
+ * @return The {@link SetSchemaResponse} object.
+ */
+ @NonNull
+ public static SetSchemaResponse toSetSchemaResponse(@NonNull SetSchemaResultProto proto,
+ @NonNull String prefix) {
+ Preconditions.checkNotNull(proto);
+ Preconditions.checkNotNull(prefix);
+ SetSchemaResponse.Builder builder = new SetSchemaResponse.Builder();
+
+ for (int i = 0; i < proto.getDeletedSchemaTypesCount(); i++) {
+ builder.addDeletedType(
+ proto.getDeletedSchemaTypes(i).substring(prefix.length()));
+ }
+
+ for (int i = 0; i < proto.getIncompatibleSchemaTypesCount(); i++) {
+ builder.addIncompatibleType(
+ proto.getIncompatibleSchemaTypes(i).substring(prefix.length()));
+ }
+
+ return builder.build();
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/TypePropertyPathToProtoConverter.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/TypePropertyPathToProtoConverter.java
new file mode 100644
index 0000000..98f5642
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/converter/TypePropertyPathToProtoConverter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.converter;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.util.Preconditions;
+
+import com.google.android.icing.proto.TypePropertyMask;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Translates a <code>Map<String, List<String>></code> into <code>List<TypePropertyMask></code>.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class TypePropertyPathToProtoConverter {
+ private TypePropertyPathToProtoConverter() {}
+
+ /** Extracts {@link TypePropertyMask} information from a {@link Map}. */
+ @NonNull
+ public static List<TypePropertyMask> toTypePropertyMaskList(@NonNull Map<String,
+ List<String>> typePropertyPaths) {
+ Preconditions.checkNotNull(typePropertyPaths);
+ List<TypePropertyMask> typePropertyMasks = new ArrayList<>(typePropertyPaths.size());
+ for (Map.Entry<String, List<String>> e : typePropertyPaths.entrySet()) {
+ typePropertyMasks.add(
+ TypePropertyMask.newBuilder().setSchemaType(
+ e.getKey()).addAllPaths(e.getValue()).build());
+ }
+ return typePropertyMasks;
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/CallStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/CallStats.java
new file mode 100644
index 0000000..e3abf90
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/CallStats.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.core.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A class for setting basic information to log for all function calls.
+ *
+ * <p>This class can set which stats to log for both batch and non-batch
+ * {@link androidx.appsearch.app.AppSearchSession} calls.
+ *
+ * <p>Some function calls may have their own detailed stats class like {@link PutDocumentStats}.
+ * However, {@link CallStats} can still be used along with the detailed stats class for easy
+ * aggregation/analysis with other function calls.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class CallStats {
+ @IntDef(value = {
+ CALL_TYPE_UNKNOWN,
+ CALL_TYPE_INITIALIZE,
+ CALL_TYPE_SET_SCHEMA,
+ CALL_TYPE_PUT_DOCUMENTS,
+ CALL_TYPE_GET_DOCUMENTS,
+ CALL_TYPE_REMOVE_DOCUMENTS_BY_ID,
+ CALL_TYPE_PUT_DOCUMENT,
+ CALL_TYPE_GET_DOCUMENT,
+ CALL_TYPE_REMOVE_DOCUMENT_BY_ID,
+ CALL_TYPE_SEARCH,
+ CALL_TYPE_OPTIMIZE,
+ CALL_TYPE_FLUSH,
+ CALL_TYPE_GLOBAL_SEARCH,
+ CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH,
+ CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CallType {
+ }
+
+ public static final int CALL_TYPE_UNKNOWN = 0;
+ public static final int CALL_TYPE_INITIALIZE = 1;
+ public static final int CALL_TYPE_SET_SCHEMA = 2;
+ public static final int CALL_TYPE_PUT_DOCUMENTS = 3;
+ public static final int CALL_TYPE_GET_DOCUMENTS = 4;
+ public static final int CALL_TYPE_REMOVE_DOCUMENTS_BY_ID = 5;
+ public static final int CALL_TYPE_PUT_DOCUMENT = 6;
+ public static final int CALL_TYPE_GET_DOCUMENT = 7;
+ public static final int CALL_TYPE_REMOVE_DOCUMENT_BY_ID = 8;
+ public static final int CALL_TYPE_SEARCH = 9;
+ public static final int CALL_TYPE_OPTIMIZE = 10;
+ public static final int CALL_TYPE_FLUSH = 11;
+ public static final int CALL_TYPE_GLOBAL_SEARCH = 12;
+ public static final int CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH = 13;
+ public static final int CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH = 14;
+
+ @Nullable
+ private final String mPackageName;
+ @Nullable
+ private final String mDatabase;
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode
+ private final int mStatusCode;
+ private final int mTotalLatencyMillis;
+
+ @CallType
+ private final int mCallType;
+ private final int mEstimatedBinderLatencyMillis;
+ private final int mNumOperationsSucceeded;
+ private final int mNumOperationsFailed;
+
+ CallStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mPackageName = builder.mPackageName;
+ mDatabase = builder.mDatabase;
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mCallType = builder.mCallType;
+ mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis;
+ mNumOperationsSucceeded = builder.mNumOperationsSucceeded;
+ mNumOperationsFailed = builder.mNumOperationsFailed;
+ }
+
+ /** Returns calling package name. */
+ @Nullable
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns calling database name. */
+ @Nullable
+ public String getDatabase() {
+ return mDatabase;
+ }
+
+ /** Returns status code for this api call. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency of this api call in millis. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns type of the call. */
+ @CallType
+ public int getCallType() {
+ return mCallType;
+ }
+
+ /** Returns estimated binder latency, in milliseconds */
+ public int getEstimatedBinderLatencyMillis() {
+ return mEstimatedBinderLatencyMillis;
+ }
+
+ /**
+ * Returns number of operations succeeded.
+ *
+ * <p>For example, for
+ * {@link androidx.appsearch.app.AppSearchSession#put}, it is the total number of individual
+ * successful put operations. In this case, how many documents are successfully indexed.
+ *
+ * <p>For non-batch calls such as
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema}, the sum of
+ * {@link CallStats#getNumOperationsSucceeded()} and
+ * {@link CallStats#getNumOperationsFailed()} is always 1 since there is only one
+ * operation.
+ */
+ public int getNumOperationsSucceeded() {
+ return mNumOperationsSucceeded;
+ }
+
+ /**
+ * Returns number of operations failed.
+ *
+ * <p>For example, for
+ * {@link androidx.appsearch.app.AppSearchSession#put}, it is the total number of individual
+ * failed put operations. In this case, how many documents are failed to be indexed.
+ *
+ * <p>For non-batch calls such as {@link androidx.appsearch.app.AppSearchSession#setSchema},
+ * the sum of {@link CallStats#getNumOperationsSucceeded()} and
+ * {@link CallStats#getNumOperationsFailed()} is always 1 since there is only one
+ * operation.
+ */
+ public int getNumOperationsFailed() {
+ return mNumOperationsFailed;
+ }
+
+ /** Builder for {@link CallStats}. */
+ public static class Builder {
+ @Nullable
+ String mPackageName;
+ @Nullable
+ String mDatabase;
+ @AppSearchResult.ResultCode
+ int mStatusCode;
+ int mTotalLatencyMillis;
+ @CallType
+ int mCallType;
+ int mEstimatedBinderLatencyMillis;
+ int mNumOperationsSucceeded;
+ int mNumOperationsFailed;
+
+ /** Sets the PackageName used by the session. */
+ @NonNull
+ public Builder setPackageName(@NonNull String packageName) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ return this;
+ }
+
+ /** Sets the database used by the session. */
+ @NonNull
+ public Builder setDatabase(@NonNull String database) {
+ mDatabase = Preconditions.checkNotNull(database);
+ return this;
+ }
+
+ /** Sets the status code. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency in millis. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets type of the call. */
+ @NonNull
+ public Builder setCallType(@CallType int callType) {
+ mCallType = callType;
+ return this;
+ }
+
+ /** Sets estimated binder latency, in milliseconds. */
+ @NonNull
+ public Builder setEstimatedBinderLatencyMillis(int estimatedBinderLatencyMillis) {
+ mEstimatedBinderLatencyMillis = estimatedBinderLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets number of operations succeeded.
+ *
+ * <p>For example, for
+ * {@link androidx.appsearch.app.AppSearchSession#put}, it is the total number of
+ * individual successful put operations. In this case, how many documents are
+ * successfully indexed.
+ *
+ * <p>For non-batch calls such as
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema}, the sum of
+ * {@link CallStats#getNumOperationsSucceeded()} and
+ * {@link CallStats#getNumOperationsFailed()} is always 1 since there is only one
+ * operation.
+ */
+ @NonNull
+ public Builder setNumOperationsSucceeded(int numOperationsSucceeded) {
+ mNumOperationsSucceeded = numOperationsSucceeded;
+ return this;
+ }
+
+ /**
+ * Sets number of operations failed.
+ *
+ * <p>For example, for {@link androidx.appsearch.app.AppSearchSession#put}, it is the
+ * total number of individual failed put operations. In this case, how many documents
+ * are failed to be indexed.
+ *
+ * <p>For non-batch calls such as
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema}, the sum of
+ * {@link CallStats#getNumOperationsSucceeded()} and
+ * {@link CallStats#getNumOperationsFailed()} is always 1 since there is only one
+ * operation.
+ */
+ @NonNull
+ public Builder setNumOperationsFailed(int numOperationsFailed) {
+ mNumOperationsFailed = numOperationsFailed;
+ return this;
+ }
+
+ /** Creates {@link CallStats} object from {@link Builder} instance. */
+ @NonNull
+ public CallStats build() {
+ return new CallStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/InitializeStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/InitializeStats.java
new file mode 100644
index 0000000..f88d257
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/InitializeStats.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.core.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class holds detailed stats for initialization
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class InitializeStats {
+ /**
+ * The cause of IcingSearchEngine recovering from a previous bad state during initialization.
+ */
+ @IntDef(value = {
+ // It needs to be sync with RecoveryCause in
+ // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto
+ RECOVERY_CAUSE_NONE,
+ RECOVERY_CAUSE_DATA_LOSS,
+ RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH,
+ RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH,
+ RECOVERY_CAUSE_IO_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RecoveryCause {
+ }
+
+ // No recovery happened.
+ public static final int RECOVERY_CAUSE_NONE = 0;
+ // Data loss in ground truth.
+ public static final int RECOVERY_CAUSE_DATA_LOSS = 1;
+ // Data in index is inconsistent with ground truth.
+ public static final int RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH = 2;
+ // Total checksum of all the components does not match.
+ public static final int RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH = 3;
+ // Random I/O errors.
+ public static final int RECOVERY_CAUSE_IO_ERROR = 4;
+
+ /**
+ * Status regarding how much data is lost during the initialization.
+ */
+ @IntDef(value = {
+ // It needs to be sync with DocumentStoreDataStatus in
+ // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto
+
+ DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS,
+ DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS,
+ DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DocumentStoreDataStatus {
+ }
+
+ // Document store is successfully initialized or fully recovered.
+ public static final int DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS = 0;
+ // Ground truth data is partially lost.
+ public static final int DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS = 1;
+ // Ground truth data is completely lost.
+ public static final int DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS = 2;
+
+ @AppSearchResult.ResultCode
+ private final int mStatusCode;
+ private final int mTotalLatencyMillis;
+ /** Whether the initialize() detects deSync. */
+ private final boolean mHasDeSync;
+ /** Time used to read and process the schema and namespaces. */
+ private final int mPrepareSchemaAndNamespacesLatencyMillis;
+ /** Time used to read and process the visibility store. */
+ private final int mPrepareVisibilityStoreLatencyMillis;
+ /** Overall time used for the native function call. */
+ private final int mNativeLatencyMillis;
+ @RecoveryCause
+ private final int mNativeDocumentStoreRecoveryCause;
+ @RecoveryCause
+ private final int mNativeIndexRestorationCause;
+ @RecoveryCause
+ private final int mNativeSchemaStoreRecoveryCause;
+ /** Time used to recover the document store. */
+ private final int mNativeDocumentStoreRecoveryLatencyMillis;
+ /** Time used to restore the index. */
+ private final int mNativeIndexRestorationLatencyMillis;
+ /** Time used to recover the schema store. */
+ private final int mNativeSchemaStoreRecoveryLatencyMillis;
+ /** Status regarding how much data is lost during the initialization. */
+ private final int mNativeDocumentStoreDataStatus;
+ /**
+ * Returns number of documents currently in document store. Those may include alive, deleted,
+ * and expired documents.
+ */
+ private final int mNativeNumDocuments;
+ /** Returns number of schema types currently in the schema store. */
+ private final int mNativeNumSchemaTypes;
+ /** Whether we had to reset the index, losing all data, during initialization. */
+ private final boolean mHasReset;
+ /** If we had to reset, contains the status code of the reset operation. */
+ @AppSearchResult.ResultCode
+ private final int mResetStatusCode;
+
+ /** Returns the status of the initialization. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns the total latency in milliseconds for the initialization. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /**
+ * Returns whether the initialize() detects deSync.
+ *
+ * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent view
+ * of what data should exist.
+ */
+ public boolean hasDeSync() {
+ return mHasDeSync;
+ }
+
+ /** Returns time used to read and process the schema and namespaces. */
+ public int getPrepareSchemaAndNamespacesLatencyMillis() {
+ return mPrepareSchemaAndNamespacesLatencyMillis;
+ }
+
+ /** Returns time used to read and process the visibility file. */
+ public int getPrepareVisibilityStoreLatencyMillis() {
+ return mPrepareVisibilityStoreLatencyMillis;
+ }
+
+ /** Returns overall time used for the native function call. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns recovery cause for document store.
+ *
+ * <p> Possible recovery causes for document store:
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
+ */
+ @RecoveryCause
+ public int getDocumentStoreRecoveryCause() {
+ return mNativeDocumentStoreRecoveryCause;
+ }
+
+ /** Returns restoration cause for index store.
+ *
+ * <p> Possible causes:
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
+ */
+ @RecoveryCause
+ public int getIndexRestorationCause() {
+ return mNativeIndexRestorationCause;
+ }
+
+ /** Returns recovery cause for schema store.
+ *
+ * <p> Possible causes:
+ * <li> IO_ERROR
+ */
+ @RecoveryCause
+ public int getSchemaStoreRecoveryCause() {
+ return mNativeSchemaStoreRecoveryCause;
+ }
+
+ /** Returns time used to recover the document store. */
+ public int getDocumentStoreRecoveryLatencyMillis() {
+ return mNativeDocumentStoreRecoveryLatencyMillis;
+ }
+
+ /** Returns time used to restore the index. */
+ public int getIndexRestorationLatencyMillis() {
+ return mNativeIndexRestorationLatencyMillis;
+ }
+
+ /** Returns time used to recover the schema store. */
+ public int getSchemaStoreRecoveryLatencyMillis() {
+ return mNativeSchemaStoreRecoveryLatencyMillis;
+ }
+
+ /** Returns status about how much data is lost during the initialization. */
+ @DocumentStoreDataStatus
+ public int getDocumentStoreDataStatus() {
+ return mNativeDocumentStoreDataStatus;
+ }
+
+ /**
+ * Returns number of documents currently in document store. Those may include alive, deleted,
+ * and expired documents.
+ */
+ public int getDocumentCount() {
+ return mNativeNumDocuments;
+ }
+
+ /** Returns number of schema types currently in the schema store. */
+ public int getSchemaTypeCount() {
+ return mNativeNumSchemaTypes;
+ }
+
+ /** Returns whether we had to reset the index, losing all data, as part of initialization. */
+ public boolean hasReset() {
+ return mHasReset;
+ }
+
+ /**
+ * Returns the status of the reset, if one was performed according to {@link #hasReset}.
+ *
+ * <p>If no value has been set, the default value is {@link AppSearchResult#RESULT_OK}.
+ */
+ @AppSearchResult.ResultCode
+ public int getResetStatusCode() {
+ return mResetStatusCode;
+ }
+
+ InitializeStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mHasDeSync = builder.mHasDeSync;
+ mPrepareSchemaAndNamespacesLatencyMillis = builder.mPrepareSchemaAndNamespacesLatencyMillis;
+ mPrepareVisibilityStoreLatencyMillis = builder.mPrepareVisibilityStoreLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDocumentStoreRecoveryCause = builder.mNativeDocumentStoreRecoveryCause;
+ mNativeIndexRestorationCause = builder.mNativeIndexRestorationCause;
+ mNativeSchemaStoreRecoveryCause = builder.mNativeSchemaStoreRecoveryCause;
+ mNativeDocumentStoreRecoveryLatencyMillis =
+ builder.mNativeDocumentStoreRecoveryLatencyMillis;
+ mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis;
+ mNativeSchemaStoreRecoveryLatencyMillis = builder.mNativeSchemaStoreRecoveryLatencyMillis;
+ mNativeDocumentStoreDataStatus = builder.mNativeDocumentStoreDataStatus;
+ mNativeNumDocuments = builder.mNativeNumDocuments;
+ mNativeNumSchemaTypes = builder.mNativeNumSchemaTypes;
+ mHasReset = builder.mHasReset;
+ mResetStatusCode = builder.mResetStatusCode;
+ }
+
+ /** Builder for {@link InitializeStats}. */
+ public static class Builder {
+ @AppSearchResult.ResultCode
+ int mStatusCode;
+
+ int mTotalLatencyMillis;
+ boolean mHasDeSync;
+ int mPrepareSchemaAndNamespacesLatencyMillis;
+ int mPrepareVisibilityStoreLatencyMillis;
+ int mNativeLatencyMillis;
+ @RecoveryCause
+ int mNativeDocumentStoreRecoveryCause;
+ @RecoveryCause
+ int mNativeIndexRestorationCause;
+ @RecoveryCause
+ int mNativeSchemaStoreRecoveryCause;
+ int mNativeDocumentStoreRecoveryLatencyMillis;
+ int mNativeIndexRestorationLatencyMillis;
+ int mNativeSchemaStoreRecoveryLatencyMillis;
+ @DocumentStoreDataStatus
+ int mNativeDocumentStoreDataStatus;
+ int mNativeNumDocuments;
+ int mNativeNumSchemaTypes;
+ boolean mHasReset;
+ @AppSearchResult.ResultCode
+ int mResetStatusCode;
+
+ /** Sets the status of the initialization. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets the total latency of the initialization in milliseconds. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets whether the initialize() detects deSync.
+ *
+ * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent
+ * view of what data should exist.
+ */
+ @NonNull
+ public Builder setHasDeSync(boolean hasDeSync) {
+ mHasDeSync = hasDeSync;
+ return this;
+ }
+
+ /** Sets time used to read and process the schema and namespaces. */
+ @NonNull
+ public Builder setPrepareSchemaAndNamespacesLatencyMillis(
+ int prepareSchemaAndNamespacesLatencyMillis) {
+ mPrepareSchemaAndNamespacesLatencyMillis = prepareSchemaAndNamespacesLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to read and process the visibility file. */
+ @NonNull
+ public Builder setPrepareVisibilityStoreLatencyMillis(
+ int prepareVisibilityStoreLatencyMillis) {
+ mPrepareVisibilityStoreLatencyMillis = prepareVisibilityStoreLatencyMillis;
+ return this;
+ }
+
+ /** Sets overall time used for the native function call. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets recovery cause for document store.
+ *
+ * <p> Possible recovery causes for document store:
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
+ */
+ @NonNull
+ public Builder setDocumentStoreRecoveryCause(
+ @RecoveryCause int documentStoreRecoveryCause) {
+ mNativeDocumentStoreRecoveryCause = documentStoreRecoveryCause;
+ return this;
+ }
+
+ /** Sets restoration cause for index store.
+ *
+ * <p> Possible causes:
+ * <li> {@link InitializeStats#DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
+ */
+ @NonNull
+ public Builder setIndexRestorationCause(
+ @RecoveryCause int indexRestorationCause) {
+ mNativeIndexRestorationCause = indexRestorationCause;
+ return this;
+ }
+
+ /** Returns recovery cause for schema store.
+ *
+ * <p> Possible causes:
+ * <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
+ */
+ @NonNull
+ public Builder setSchemaStoreRecoveryCause(
+ @RecoveryCause int schemaStoreRecoveryCause) {
+ mNativeSchemaStoreRecoveryCause = schemaStoreRecoveryCause;
+ return this;
+ }
+
+ /** Sets time used to recover the document store. */
+ @NonNull
+ public Builder setDocumentStoreRecoveryLatencyMillis(
+ int documentStoreRecoveryLatencyMillis) {
+ mNativeDocumentStoreRecoveryLatencyMillis = documentStoreRecoveryLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to restore the index. */
+ @NonNull
+ public Builder setIndexRestorationLatencyMillis(
+ int indexRestorationLatencyMillis) {
+ mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to recover the schema store. */
+ @NonNull
+ public Builder setSchemaStoreRecoveryLatencyMillis(
+ int schemaStoreRecoveryLatencyMillis) {
+ mNativeSchemaStoreRecoveryLatencyMillis = schemaStoreRecoveryLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets Native Document Store Data status.
+ * status is defined in external/icing/proto/icing/proto/logging.proto
+ */
+ @NonNull
+ public Builder setDocumentStoreDataStatus(
+ @DocumentStoreDataStatus int documentStoreDataStatus) {
+ mNativeDocumentStoreDataStatus = documentStoreDataStatus;
+ return this;
+ }
+
+ /**
+ * Sets number of documents currently in document store. Those may include alive, deleted,
+ * and expired documents.
+ */
+ @NonNull
+ public Builder setDocumentCount(int numDocuments) {
+ mNativeNumDocuments = numDocuments;
+ return this;
+ }
+
+ /** Sets number of schema types currently in the schema store. */
+ @NonNull
+ public Builder setSchemaTypeCount(int numSchemaTypes) {
+ mNativeNumSchemaTypes = numSchemaTypes;
+ return this;
+ }
+
+ /** Sets whether we had to reset the index, losing all data, as part of initialization. */
+ @NonNull
+ public Builder setHasReset(boolean hasReset) {
+ mHasReset = hasReset;
+ return this;
+ }
+
+ /** Sets the status of the reset, if one was performed according to {@link #setHasReset}. */
+ @NonNull
+ public Builder setResetStatusCode(@AppSearchResult.ResultCode int resetStatusCode) {
+ mResetStatusCode = resetStatusCode;
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link InitializeStats} from the contents of this
+ * {@link InitializeStats.Builder}
+ */
+ @NonNull
+ public InitializeStats build() {
+ return new InitializeStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/OptimizeStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/OptimizeStats.java
new file mode 100644
index 0000000..b7dcae0
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/OptimizeStats.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.core.util.Preconditions;
+
+/**
+ * Class holds detailed stats for Optimize.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class OptimizeStats {
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode
+ private final int mStatusCode;
+ private final int mTotalLatencyMillis;
+ private final int mNativeLatencyMillis;
+
+ // Time used to optimize the document store in millis.
+ private final int mNativeDocumentStoreOptimizeLatencyMillis;
+
+ // Time used to restore the index in millis.
+ private final int mNativeIndexRestorationLatencyMillis;
+
+ // Number of documents before the optimization.
+ private final int mNativeOriginalDocumentCount;
+
+ // Number of documents deleted during the optimization.
+ private final int mNativeDeletedDocumentCount;
+
+ // Number of documents expired during the optimization.
+ private final int mNativeExpiredDocumentCount;
+
+ // Size of storage in bytes before the optimization.
+ private final long mNativeStorageSizeBeforeBytes;
+
+ // Size of storage in bytes after the optimization.
+ private final long mNativeStorageSizeAfterBytes;
+
+ // The amount of time in millis since the last optimization ran calculated using wall clock time
+ private final long mNativeTimeSinceLastOptimizeMillis;
+
+ OptimizeStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDocumentStoreOptimizeLatencyMillis =
+ builder.mNativeDocumentStoreOptimizeLatencyMillis;
+ mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis;
+ mNativeOriginalDocumentCount = builder.mNativeOriginalDocumentCount;
+ mNativeDeletedDocumentCount = builder.mNativeDeletedDocumentCount;
+ mNativeExpiredDocumentCount = builder.mNativeExpiredDocumentCount;
+ mNativeStorageSizeBeforeBytes = builder.mNativeStorageSizeBeforeBytes;
+ mNativeStorageSizeAfterBytes = builder.mNativeStorageSizeAfterBytes;
+ mNativeTimeSinceLastOptimizeMillis = builder.mNativeTimeSinceLastOptimizeMillis;
+ }
+
+ /** Returns status code for this optimization. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency of this optimization in millis. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns how much time in millis spent in the native code. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns time used to optimize the document store in millis. */
+ public int getDocumentStoreOptimizeLatencyMillis() {
+ return mNativeDocumentStoreOptimizeLatencyMillis;
+ }
+
+ /** Returns time used to restore the index in millis. */
+ public int getIndexRestorationLatencyMillis() {
+ return mNativeIndexRestorationLatencyMillis;
+ }
+
+ /** Returns number of documents before the optimization. */
+ public int getOriginalDocumentCount() {
+ return mNativeOriginalDocumentCount;
+ }
+
+ /** Returns number of documents deleted during the optimization. */
+ public int getDeletedDocumentCount() {
+ return mNativeDeletedDocumentCount;
+ }
+
+ /** Returns number of documents expired during the optimization. */
+ public int getExpiredDocumentCount() {
+ return mNativeExpiredDocumentCount;
+ }
+
+ /** Returns size of storage in bytes before the optimization. */
+ public long getStorageSizeBeforeBytes() {
+ return mNativeStorageSizeBeforeBytes;
+ }
+
+ /** Returns size of storage in bytes after the optimization. */
+ public long getStorageSizeAfterBytes() {
+ return mNativeStorageSizeAfterBytes;
+ }
+
+ /**
+ * Returns the amount of time in millis since the last optimization ran calculated using wall
+ * clock time.
+ */
+ public long getTimeSinceLastOptimizeMillis() {
+ return mNativeTimeSinceLastOptimizeMillis;
+ }
+
+ /** Builder for {@link RemoveStats}. */
+ public static class Builder {
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode
+ int mStatusCode;
+ int mTotalLatencyMillis;
+ int mNativeLatencyMillis;
+ int mNativeDocumentStoreOptimizeLatencyMillis;
+ int mNativeIndexRestorationLatencyMillis;
+ int mNativeOriginalDocumentCount;
+ int mNativeDeletedDocumentCount;
+ int mNativeExpiredDocumentCount;
+ long mNativeStorageSizeBeforeBytes;
+ long mNativeStorageSizeAfterBytes;
+ long mNativeTimeSinceLastOptimizeMillis;
+
+ /** Sets the status code. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency in millis. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets native latency in millis. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to optimize the document store. */
+ @NonNull
+ public Builder setDocumentStoreOptimizeLatencyMillis(
+ int documentStoreOptimizeLatencyMillis) {
+ mNativeDocumentStoreOptimizeLatencyMillis = documentStoreOptimizeLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to restore the index. */
+ @NonNull
+ public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) {
+ mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis;
+ return this;
+ }
+
+ /** Sets number of documents before the optimization. */
+ @NonNull
+ public Builder setOriginalDocumentCount(int originalDocumentCount) {
+ mNativeOriginalDocumentCount = originalDocumentCount;
+ return this;
+ }
+
+ /** Sets number of documents deleted during the optimization. */
+ @NonNull
+ public Builder setDeletedDocumentCount(int deletedDocumentCount) {
+ mNativeDeletedDocumentCount = deletedDocumentCount;
+ return this;
+ }
+
+ /** Sets number of documents expired during the optimization. */
+ @NonNull
+ public Builder setExpiredDocumentCount(int expiredDocumentCount) {
+ mNativeExpiredDocumentCount = expiredDocumentCount;
+ return this;
+ }
+
+ /** Sets Storage size in bytes before optimization. */
+ @NonNull
+ public Builder setStorageSizeBeforeBytes(long storageSizeBeforeBytes) {
+ mNativeStorageSizeBeforeBytes = storageSizeBeforeBytes;
+ return this;
+ }
+
+ /** Sets storage size in bytes after optimization. */
+ @NonNull
+ public Builder setStorageSizeAfterBytes(long storageSizeAfterBytes) {
+ mNativeStorageSizeAfterBytes = storageSizeAfterBytes;
+ return this;
+ }
+
+ /**
+ * Sets the amount the time since the last optimize ran calculated using wall clock time.
+ */
+ @NonNull
+ public Builder setTimeSinceLastOptimizeMillis(long timeSinceLastOptimizeMillis) {
+ mNativeTimeSinceLastOptimizeMillis = timeSinceLastOptimizeMillis;
+ return this;
+ }
+
+ /** Creates a {@link OptimizeStats}. */
+ @NonNull
+ public OptimizeStats build() {
+ return new OptimizeStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/PutDocumentStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/PutDocumentStats.java
new file mode 100644
index 0000000..3bcc5cb
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/PutDocumentStats.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.core.util.Preconditions;
+
+/**
+ * A class for holding detailed stats to log for each individual document put by a
+ * {@link androidx.appsearch.app.AppSearchSession#put} call.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class PutDocumentStats {
+ @NonNull
+ private final String mPackageName;
+ @NonNull
+ private final String mDatabase;
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode
+ private final int mStatusCode;
+ private final int mTotalLatencyMillis;
+
+ /** Time used to generate a document proto from a Bundle. */
+ private final int mGenerateDocumentProtoLatencyMillis;
+
+ /** Time used to rewrite types and namespaces in the document. */
+ private final int mRewriteDocumentTypesLatencyMillis;
+
+ /** Overall time used for the native function call. */
+ private final int mNativeLatencyMillis;
+
+ /** Time used to store the document. */
+ private final int mNativeDocumentStoreLatencyMillis;
+
+ /** Time used to index the document. It doesn't include the time to merge indices. */
+ private final int mNativeIndexLatencyMillis;
+
+ /** Time used to merge the indices. */
+ private final int mNativeIndexMergeLatencyMillis;
+
+ /** Document size in bytes. */
+ private final int mNativeDocumentSizeBytes;
+
+ /** Number of tokens added to the index. */
+ private final int mNativeNumTokensIndexed;
+
+ /**
+ * Whether the number of tokens to be indexed exceeded the max number of tokens per
+ * document.
+ */
+ private final boolean mNativeExceededMaxNumTokens;
+
+ PutDocumentStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mPackageName = builder.mPackageName;
+ mDatabase = builder.mDatabase;
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis;
+ mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDocumentStoreLatencyMillis = builder.mNativeDocumentStoreLatencyMillis;
+ mNativeIndexLatencyMillis = builder.mNativeIndexLatencyMillis;
+ mNativeIndexMergeLatencyMillis = builder.mNativeIndexMergeLatencyMillis;
+ mNativeDocumentSizeBytes = builder.mNativeDocumentSizeBytes;
+ mNativeNumTokensIndexed = builder.mNativeNumTokensIndexed;
+ mNativeExceededMaxNumTokens = builder.mNativeExceededMaxNumTokens;
+ }
+
+ /** Returns calling package name. */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns calling database name. */
+ @NonNull
+ public String getDatabase() {
+ return mDatabase;
+ }
+
+ /** Returns status code for this putDocument. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency of this putDocument in millis. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns time spent on generating document proto, in milliseconds. */
+ public int getGenerateDocumentProtoLatencyMillis() {
+ return mGenerateDocumentProtoLatencyMillis;
+ }
+
+ /** Returns time spent on rewriting types and namespaces in document, in milliseconds. */
+ public int getRewriteDocumentTypesLatencyMillis() {
+ return mRewriteDocumentTypesLatencyMillis;
+ }
+
+ /** Returns time spent in native, in milliseconds. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns time spent on document store, in milliseconds. */
+ public int getNativeDocumentStoreLatencyMillis() {
+ return mNativeDocumentStoreLatencyMillis;
+ }
+
+ /** Returns time spent on indexing, in milliseconds. */
+ public int getNativeIndexLatencyMillis() {
+ return mNativeIndexLatencyMillis;
+ }
+
+ /** Returns time spent on merging indices, in milliseconds. */
+ public int getNativeIndexMergeLatencyMillis() {
+ return mNativeIndexMergeLatencyMillis;
+ }
+
+ /** Returns document size, in bytes. */
+ public int getNativeDocumentSizeBytes() {
+ return mNativeDocumentSizeBytes;
+ }
+
+ /** Returns number of tokens indexed. */
+ public int getNativeNumTokensIndexed() {
+ return mNativeNumTokensIndexed;
+ }
+
+ /**
+ * Returns whether the number of tokens to be indexed exceeded the max number of tokens per
+ * document.
+ */
+ public boolean getNativeExceededMaxNumTokens() {
+ return mNativeExceededMaxNumTokens;
+ }
+
+ /** Builder for {@link PutDocumentStats}. */
+ public static class Builder {
+ @NonNull
+ final String mPackageName;
+ @NonNull
+ final String mDatabase;
+ @AppSearchResult.ResultCode
+ int mStatusCode;
+ int mTotalLatencyMillis;
+ int mGenerateDocumentProtoLatencyMillis;
+ int mRewriteDocumentTypesLatencyMillis;
+ int mNativeLatencyMillis;
+ int mNativeDocumentStoreLatencyMillis;
+ int mNativeIndexLatencyMillis;
+ int mNativeIndexMergeLatencyMillis;
+ int mNativeDocumentSizeBytes;
+ int mNativeNumTokensIndexed;
+ boolean mNativeExceededMaxNumTokens;
+
+ /** Builder for {@link PutDocumentStats} */
+ public Builder(@NonNull String packageName, @NonNull String database) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabase = Preconditions.checkNotNull(database);
+ }
+
+ /** Sets the status code. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency in millis. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets how much time we spend for generating document proto, in milliseconds. */
+ @NonNull
+ public Builder setGenerateDocumentProtoLatencyMillis(
+ int generateDocumentProtoLatencyMillis) {
+ mGenerateDocumentProtoLatencyMillis = generateDocumentProtoLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets how much time we spend for rewriting types and namespaces in document, in
+ * milliseconds.
+ */
+ @NonNull
+ public Builder setRewriteDocumentTypesLatencyMillis(int rewriteDocumentTypesLatencyMillis) {
+ mRewriteDocumentTypesLatencyMillis = rewriteDocumentTypesLatencyMillis;
+ return this;
+ }
+
+ /** Sets the native latency, in milliseconds. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets how much time we spend on document store, in milliseconds. */
+ @NonNull
+ public Builder setNativeDocumentStoreLatencyMillis(int nativeDocumentStoreLatencyMillis) {
+ mNativeDocumentStoreLatencyMillis = nativeDocumentStoreLatencyMillis;
+ return this;
+ }
+
+ /** Sets the native index latency, in milliseconds. */
+ @NonNull
+ public Builder setNativeIndexLatencyMillis(int nativeIndexLatencyMillis) {
+ mNativeIndexLatencyMillis = nativeIndexLatencyMillis;
+ return this;
+ }
+
+ /** Sets how much time we spend on merging indices, in milliseconds. */
+ @NonNull
+ public Builder setNativeIndexMergeLatencyMillis(int nativeIndexMergeLatencyMillis) {
+ mNativeIndexMergeLatencyMillis = nativeIndexMergeLatencyMillis;
+ return this;
+ }
+
+ /** Sets document size, in bytes. */
+ @NonNull
+ public Builder setNativeDocumentSizeBytes(int nativeDocumentSizeBytes) {
+ mNativeDocumentSizeBytes = nativeDocumentSizeBytes;
+ return this;
+ }
+
+ /** Sets number of tokens indexed in native. */
+ @NonNull
+ public Builder setNativeNumTokensIndexed(int nativeNumTokensIndexed) {
+ mNativeNumTokensIndexed = nativeNumTokensIndexed;
+ return this;
+ }
+
+ /**
+ * Sets whether the number of tokens to be indexed exceeded the max number of tokens per
+ * document.
+ */
+ @NonNull
+ public Builder setNativeExceededMaxNumTokens(boolean nativeExceededMaxNumTokens) {
+ mNativeExceededMaxNumTokens = nativeExceededMaxNumTokens;
+ return this;
+ }
+
+ /**
+ * Creates a new {@link PutDocumentStats} object from the contents of this
+ * {@link Builder} instance.
+ */
+ @NonNull
+ public PutDocumentStats build() {
+ return new PutDocumentStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/RemoveStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/RemoveStats.java
new file mode 100644
index 0000000..3a63aa0
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/RemoveStats.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.RemoveByDocumentIdRequest;
+import androidx.appsearch.app.SearchSpec;
+import androidx.core.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class holds detailed stats for
+ * {@link androidx.appsearch.app.AppSearchSession#remove(RemoveByDocumentIdRequest)} and
+ * {@link androidx.appsearch.app.AppSearchSession#remove(String, SearchSpec)}
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class RemoveStats {
+ @IntDef(value = {
+ // It needs to be sync with DeleteType.Code in
+ // external/icing/proto/icing/proto/logging.proto#DeleteStatsProto
+ UNKNOWN,
+ SINGLE,
+ QUERY,
+ NAMESPACE,
+ SCHEMA_TYPE,
+
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeleteType {
+ }
+
+ /** Default. Should never be used. */
+ public static final int UNKNOWN = 0;
+ /** Delete by namespace + id. */
+ public static final int SINGLE = 1;
+ /** Delete by query. */
+ public static final int QUERY = 2;
+ /** Delete by namespace. */
+ public static final int NAMESPACE = 3;
+ /** Delete by schema type. */
+ public static final int SCHEMA_TYPE = 4;
+
+ @NonNull
+ private final String mPackageName;
+ @NonNull
+ private final String mDatabase;
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode
+ private final int mStatusCode;
+ private final int mTotalLatencyMillis;
+ private final int mNativeLatencyMillis;
+ @DeleteType
+ private final int mNativeDeleteType;
+ private final int mNativeNumDocumentsDeleted;
+
+ RemoveStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mPackageName = builder.mPackageName;
+ mDatabase = builder.mDatabase;
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDeleteType = builder.mNativeDeleteType;
+ mNativeNumDocumentsDeleted = builder.mNativeNumDocumentsDeleted;
+ }
+
+ /** Returns calling package name. */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns calling database name. */
+ @NonNull
+ public String getDatabase() {
+ return mDatabase;
+ }
+
+ /** Returns status code for this remove. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency of this remove in millis. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns how much time in millis spent in the native code. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns what type of delete for this remove call. */
+ @DeleteType
+ public int getDeleteType() {
+ return mNativeDeleteType;
+ }
+
+ /** Returns how many documents get deleted in this call. */
+ public int getDeletedDocumentCount() {
+ return mNativeNumDocumentsDeleted;
+ }
+
+ /** Builder for {@link RemoveStats}. */
+ public static class Builder {
+ @NonNull
+ final String mPackageName;
+ @NonNull
+ final String mDatabase;
+ @AppSearchResult.ResultCode
+ int mStatusCode;
+ int mTotalLatencyMillis;
+ int mNativeLatencyMillis;
+ @DeleteType
+ int mNativeDeleteType;
+ int mNativeNumDocumentsDeleted;
+
+ /** Constructor for the {@link Builder}. */
+ public Builder(@NonNull String packageName, @NonNull String database) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabase = Preconditions.checkNotNull(database);
+ }
+
+ /** Sets the status code. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency in millis. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets native latency in millis. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets delete type for this call. */
+ @NonNull
+ public Builder setDeleteType(@DeleteType int nativeDeleteType) {
+ mNativeDeleteType = nativeDeleteType;
+ return this;
+ }
+
+ /** Sets how many documents get deleted for this call. */
+ @NonNull
+ public Builder setDeletedDocumentCount(int nativeNumDocumentsDeleted) {
+ mNativeNumDocumentsDeleted = nativeNumDocumentsDeleted;
+ return this;
+ }
+
+ /** Creates a {@link RemoveStats}. */
+ @NonNull
+ public RemoveStats build() {
+ return new RemoveStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SchemaMigrationStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SchemaMigrationStats.java
new file mode 100644
index 0000000..dc3f6f4
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SchemaMigrationStats.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.core.util.Preconditions;
+
+/**
+ * Class holds detailed stats for Schema migration.
+ *
+ * @hide
+ */
+// TODO(b/173532925): Hides getter and setter functions for accessing {@code
+// mFirstSetSchemaLatencyMillis} and {@code mSecondSetSchemaLatencyMillis} field.
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class SchemaMigrationStats {
+ /** GetSchema latency in milliseconds. */
+ private final int mGetSchemaLatencyMillis;
+
+ /**
+ * Latency of querying all documents that need to be migrated to new version and transforming
+ * documents to new version in milliseconds.
+ */
+ private final int mQueryAndTransformLatencyMillis;
+
+ private final int mFirstSetSchemaLatencyMillis;
+
+ private final int mSecondSetSchemaLatencyMillis;
+
+ /** Latency of putting migrated document to Icing lib in milliseconds. */
+ private final int mSaveDocumentLatencyMillis;
+
+ private final int mMigratedDocumentCount;
+
+ private final int mSavedDocumentCount;
+
+ SchemaMigrationStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mGetSchemaLatencyMillis = builder.mGetSchemaLatencyMillis;
+ mQueryAndTransformLatencyMillis = builder.mQueryAndTransformLatencyMillis;
+ mFirstSetSchemaLatencyMillis = builder.mFirstSetSchemaLatencyMillis;
+ mSecondSetSchemaLatencyMillis = builder.mSecondSetSchemaLatencyMillis;
+ mSaveDocumentLatencyMillis = builder.mSaveDocumentLatencyMillis;
+ mMigratedDocumentCount = builder.mMigratedDocumentCount;
+ mSavedDocumentCount = builder.mSavedDocumentCount;
+ }
+
+ /** Returns GetSchema latency in milliseconds. */
+ public int getGetSchemaLatencyMillis() {
+ return mGetSchemaLatencyMillis;
+ }
+
+ /**
+ * Returns latency of querying all documents that need to be migrated to new version and
+ * transforming documents to new version in milliseconds.
+ */
+ public int getQueryAndTransformLatencyMillis() {
+ return mQueryAndTransformLatencyMillis;
+ }
+
+ /**
+ * Returns latency of first SetSchema action in milliseconds.
+ *
+ * <p>If all schema fields are backward compatible, the schema will be successful set to Icing.
+ * Otherwise, we will retrieve incompatible types here.
+ *
+ * <p>Please see {@link SetSchemaRequest} for what is "incompatible".
+ */
+ public int getFirstSetSchemaLatencyMillis() {
+ return mFirstSetSchemaLatencyMillis;
+ }
+
+ /**
+ * Returns latency of second SetSchema action in milliseconds.
+ *
+ * <p>If all schema fields are backward compatible, the schema will be successful set to
+ * Icing in the first setSchema action and this value will be 0. Otherwise, schema types will
+ * be set to Icing by this action.
+ */
+ public int getSecondSetSchemaLatencyMillis() {
+ return mSecondSetSchemaLatencyMillis;
+ }
+
+ /** Returns latency of putting migrated document to Icing lib in milliseconds. */
+ public int getSaveDocumentLatencyMillis() {
+ return mSaveDocumentLatencyMillis;
+ }
+
+ /** Returns number of migrated documents. */
+ public int getMigratedDocumentCount() {
+ return mMigratedDocumentCount;
+ }
+
+ /** Returns number of updated documents which are saved in Icing lib. */
+ public int getSavedDocumentCount() {
+ return mSavedDocumentCount;
+ }
+
+ /** Builder for {@link SchemaMigrationStats}. */
+ public static class Builder {
+ int mGetSchemaLatencyMillis;
+ int mQueryAndTransformLatencyMillis;
+ int mFirstSetSchemaLatencyMillis;
+ int mSecondSetSchemaLatencyMillis;
+ int mSaveDocumentLatencyMillis;
+ int mMigratedDocumentCount;
+ int mSavedDocumentCount;
+
+ /** Sets latency for the GetSchema action in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setGetSchemaLatencyMillis(int getSchemaLatencyMillis) {
+ mGetSchemaLatencyMillis = getSchemaLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets latency for querying all documents that need to be migrated to new version and
+ * transforming documents to new version in milliseconds.
+ */
+ @NonNull
+ public SchemaMigrationStats.Builder setQueryAndTransformLatencyMillis(
+ int queryAndTransformLatencyMillis) {
+ mQueryAndTransformLatencyMillis = queryAndTransformLatencyMillis;
+ return this;
+ }
+
+ /** Sets latency of first SetSchema action in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setFirstSetSchemaLatencyMillis(
+ int firstSetSchemaLatencyMillis) {
+ mFirstSetSchemaLatencyMillis = firstSetSchemaLatencyMillis;
+ return this;
+ }
+
+ /** Sets latency of second SetSchema action in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setSecondSetSchemaLatencyMillis(
+ int secondSetSchemaLatencyMillis) {
+ mSecondSetSchemaLatencyMillis = secondSetSchemaLatencyMillis;
+ return this;
+ }
+
+ /** Sets latency for putting migrated document to Icing lib in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setSaveDocumentLatencyMillis(
+ int saveDocumentLatencyMillis) {
+ mSaveDocumentLatencyMillis = saveDocumentLatencyMillis;
+ return this;
+ }
+
+ /** Sets number of migrated documents. */
+ @NonNull
+ public SchemaMigrationStats.Builder setMigratedDocumentCount(int migratedDocumentCount) {
+ mMigratedDocumentCount = migratedDocumentCount;
+ return this;
+ }
+
+ /** Sets number of updated documents which are saved in Icing lib. */
+ @NonNull
+ public SchemaMigrationStats.Builder setSavedDocumentCount(int savedDocumentCount) {
+ mSavedDocumentCount = savedDocumentCount;
+ return this;
+ }
+
+ /**
+ * Builds a new {@link SchemaMigrationStats} from the {@link SchemaMigrationStats.Builder}.
+ */
+ @NonNull
+ public SchemaMigrationStats build() {
+ return new SchemaMigrationStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SearchStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SearchStats.java
new file mode 100644
index 0000000..727a813
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SearchStats.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.app.SearchSpec;
+import androidx.core.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class holds detailed stats for
+ * {@link androidx.appsearch.app.AppSearchSession#search(String, SearchSpec)}
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class SearchStats {
+ @IntDef(value = {
+ // Searches apps' own documents.
+ VISIBILITY_SCOPE_LOCAL,
+ // Searches the global documents. Including platform surfaceable and 3p-access.
+ VISIBILITY_SCOPE_GLOBAL,
+ VISIBILITY_SCOPE_UNKNOWN,
+ // TODO(b/173532925) Add THIRD_PARTY_ACCESS once we can distinguish platform
+ // surfaceable from 3p access(right both of them are categorized as
+ // VISIBILITY_SCOPE_GLOBAL)
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VisibilityScope {
+ }
+
+ // Searches apps' own documents.
+ public static final int VISIBILITY_SCOPE_LOCAL = 1;
+ // Searches the global documents. Including platform surfaceable and 3p-access.
+ public static final int VISIBILITY_SCOPE_GLOBAL = 2;
+ public static final int VISIBILITY_SCOPE_UNKNOWN = 3;
+
+ // TODO(b/173532925): Add a field searchType to indicate where the search is used(normal
+ // query vs in removeByQuery vs during migration)
+
+ @NonNull
+ private final String mPackageName;
+ @Nullable
+ private final String mDatabase;
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode
+ private final int mStatusCode;
+ private final int mTotalLatencyMillis;
+ /** Time used to rewrite the search spec. */
+ private final int mRewriteSearchSpecLatencyMillis;
+ /** Time used to rewrite the search results. */
+ private final int mRewriteSearchResultLatencyMillis;
+ /** Defines the scope the query is searching over */
+ @VisibilityScope
+ private final int mVisibilityScope;
+ /** Overall time used for the native function call. */
+ private final int mNativeLatencyMillis;
+ /** Number of terms in the query string. */
+ private final int mNativeNumTerms;
+ /** Length of the query string. */
+ private final int mNativeQueryLength;
+ /** Number of namespaces filtered. */
+ private final int mNativeNumNamespacesFiltered;
+ /** Number of schema types filtered. */
+ private final int mNativeNumSchemaTypesFiltered;
+ /** The requested number of results in one page. */
+ private final int mNativeRequestedPageSize;
+ /** The actual number of results returned in the current page. */
+ private final int mNativeNumResultsReturnedCurrentPage;
+ /**
+ * Whether the function call is querying the first page. If it's
+ * not, Icing will fetch the results from cache so that some steps
+ * may be skipped.
+ */
+ private final boolean mNativeIsFirstPage;
+ /**
+ * Time used to parse the query, including 2 parts: tokenizing and
+ * transforming tokens into an iterator tree.
+ */
+ private final int mNativeParseQueryLatencyMillis;
+ /** Strategy of scoring and ranking. */
+ @SearchSpec.RankingStrategy
+ private final int mNativeRankingStrategy;
+ /** Number of documents scored. */
+ private final int mNativeNumDocumentsScored;
+ /** Time used to score the raw results. */
+ private final int mNativeScoringLatencyMillis;
+ /** Time used to rank the scored results. */
+ private final int mNativeRankingLatencyMillis;
+ /**
+ * Time used to fetch the document protos. Note that it includes the
+ * time to snippet if {@link SearchStats#mNativeNumResultsWithSnippets} is greater than 0.
+ */
+ private final int mNativeDocumentRetrievingLatencyMillis;
+ /** How many snippets are calculated. */
+ private final int mNativeNumResultsWithSnippets;
+
+ SearchStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mPackageName = builder.mPackageName;
+ mDatabase = builder.mDatabase;
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mRewriteSearchSpecLatencyMillis = builder.mRewriteSearchSpecLatencyMillis;
+ mRewriteSearchResultLatencyMillis = builder.mRewriteSearchResultLatencyMillis;
+ mVisibilityScope = builder.mVisibilityScope;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeNumTerms = builder.mNativeNumTerms;
+ mNativeQueryLength = builder.mNativeQueryLength;
+ mNativeNumNamespacesFiltered = builder.mNativeNumNamespacesFiltered;
+ mNativeNumSchemaTypesFiltered = builder.mNativeNumSchemaTypesFiltered;
+ mNativeRequestedPageSize = builder.mNativeRequestedPageSize;
+ mNativeNumResultsReturnedCurrentPage = builder.mNativeNumResultsReturnedCurrentPage;
+ mNativeIsFirstPage = builder.mNativeIsFirstPage;
+ mNativeParseQueryLatencyMillis = builder.mNativeParseQueryLatencyMillis;
+ mNativeRankingStrategy = builder.mNativeRankingStrategy;
+ mNativeNumDocumentsScored = builder.mNativeNumDocumentsScored;
+ mNativeScoringLatencyMillis = builder.mNativeScoringLatencyMillis;
+ mNativeRankingLatencyMillis = builder.mNativeRankingLatencyMillis;
+ mNativeNumResultsWithSnippets = builder.mNativeNumResultsWithSnippets;
+ mNativeDocumentRetrievingLatencyMillis = builder.mNativeDocumentRetrievingLatencyMillis;
+ }
+
+ /** Returns the package name of the session. */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Returns the database name of the session.
+ *
+ * @return database name used by the session. {@code null} if and only if it is a
+ * global search(visibilityScope is {@link SearchStats#VISIBILITY_SCOPE_GLOBAL}).
+ */
+ @Nullable
+ public String getDatabase() {
+ return mDatabase;
+ }
+
+ /** Returns status of the search. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns the total latency of the search. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns how much time spent on rewriting the {@link SearchSpec}. */
+ public int getRewriteSearchSpecLatencyMillis() {
+ return mRewriteSearchSpecLatencyMillis;
+ }
+
+ /** Returns how much time spent on rewriting the {@link androidx.appsearch.app.SearchResult}. */
+ public int getRewriteSearchResultLatencyMillis() {
+ return mRewriteSearchResultLatencyMillis;
+ }
+
+ /** Returns the visibility scope of the search. */
+ @VisibilityScope
+ public int getVisibilityScope() {
+ return mVisibilityScope;
+ }
+
+ /** Returns how much time spent on the native calls. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns number of terms in the search string. */
+ public int getTermCount() {
+ return mNativeNumTerms;
+ }
+
+ /** Returns the length of the search string. */
+ public int getQueryLength() {
+ return mNativeQueryLength;
+ }
+
+ /** Returns number of namespaces filtered. */
+ public int getFilteredNamespaceCount() {
+ return mNativeNumNamespacesFiltered;
+ }
+
+ /** Returns number of schema types filtered. */
+ public int getFilteredSchemaTypeCount() {
+ return mNativeNumSchemaTypesFiltered;
+ }
+
+ /** Returns the requested number of results in one page. */
+ public int getRequestedPageSize() {
+ return mNativeRequestedPageSize;
+ }
+
+ /** Returns the actual number of results returned in the current page. */
+ public int getCurrentPageReturnedResultCount() {
+ return mNativeNumResultsReturnedCurrentPage;
+ }
+
+ // TODO(b/185184738) Make it an integer to show how many pages having been returned.
+ /** Returns whether the function call is querying the first page. */
+ public boolean isFirstPage() {
+ return mNativeIsFirstPage;
+ }
+
+ /**
+ * Returns time used to parse the query, including 2 parts: tokenizing and transforming
+ * tokens into an iterator tree.
+ */
+ public int getParseQueryLatencyMillis() {
+ return mNativeParseQueryLatencyMillis;
+ }
+
+ /** Returns strategy of scoring and ranking. */
+ @SearchSpec.RankingStrategy
+ public int getRankingStrategy() {
+ return mNativeRankingStrategy;
+ }
+
+ /** Returns number of documents scored. */
+ public int getScoredDocumentCount() {
+ return mNativeNumDocumentsScored;
+ }
+
+ /** Returns time used to score the raw results. */
+ public int getScoringLatencyMillis() {
+ return mNativeScoringLatencyMillis;
+ }
+
+ /** Returns time used to rank the scored results. */
+ public int getRankingLatencyMillis() {
+ return mNativeRankingLatencyMillis;
+ }
+
+ /**
+ * Returns time used to fetch the document protos. Note that it includes the
+ * time to snippet if {@link SearchStats#mNativeNumResultsWithSnippets} is not zero.
+ */
+ public int getDocumentRetrievingLatencyMillis() {
+ return mNativeDocumentRetrievingLatencyMillis;
+ }
+
+ /** Returns the number of the results in the page returned were snippeted. */
+ public int getResultWithSnippetsCount() {
+ return mNativeNumResultsWithSnippets;
+ }
+
+ /** Builder for {@link SearchStats} */
+ public static class Builder {
+ @NonNull
+ final String mPackageName;
+ @Nullable
+ String mDatabase;
+ @AppSearchResult.ResultCode
+ int mStatusCode;
+ int mTotalLatencyMillis;
+ int mRewriteSearchSpecLatencyMillis;
+ int mRewriteSearchResultLatencyMillis;
+ int mVisibilityScope;
+ int mNativeLatencyMillis;
+ int mNativeNumTerms;
+ int mNativeQueryLength;
+ int mNativeNumNamespacesFiltered;
+ int mNativeNumSchemaTypesFiltered;
+ int mNativeRequestedPageSize;
+ int mNativeNumResultsReturnedCurrentPage;
+ boolean mNativeIsFirstPage;
+ int mNativeParseQueryLatencyMillis;
+ int mNativeRankingStrategy;
+ int mNativeNumDocumentsScored;
+ int mNativeScoringLatencyMillis;
+ int mNativeRankingLatencyMillis;
+ int mNativeNumResultsWithSnippets;
+ int mNativeDocumentRetrievingLatencyMillis;
+
+ /**
+ * Constructor
+ *
+ * @param visibilityScope scope for the corresponding search.
+ * @param packageName name of the calling package.
+ */
+ public Builder(@VisibilityScope int visibilityScope, @NonNull String packageName) {
+ mVisibilityScope = visibilityScope;
+ mPackageName = Preconditions.checkNotNull(packageName);
+ }
+
+ /** Sets the database used by the session. */
+ @NonNull
+ public Builder setDatabase(@NonNull String database) {
+ mDatabase = Preconditions.checkNotNull(database);
+ return this;
+ }
+
+ /** Sets the status of the search. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency for the search. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to rewrite the search spec. */
+ @NonNull
+ public Builder setRewriteSearchSpecLatencyMillis(int rewriteSearchSpecLatencyMillis) {
+ mRewriteSearchSpecLatencyMillis = rewriteSearchSpecLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to rewrite the search results. */
+ @NonNull
+ public Builder setRewriteSearchResultLatencyMillis(int rewriteSearchResultLatencyMillis) {
+ mRewriteSearchResultLatencyMillis = rewriteSearchResultLatencyMillis;
+ return this;
+ }
+
+ /** Sets overall time used for the native function calls. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets number of terms in the search string. */
+ @NonNull
+ public Builder setTermCount(int termCount) {
+ mNativeNumTerms = termCount;
+ return this;
+ }
+
+ /** Sets length of the search string. */
+ @NonNull
+ public Builder setQueryLength(int queryLength) {
+ mNativeQueryLength = queryLength;
+ return this;
+ }
+
+ /** Sets number of namespaces filtered. */
+ @NonNull
+ public Builder setFilteredNamespaceCount(int filteredNamespaceCount) {
+ mNativeNumNamespacesFiltered = filteredNamespaceCount;
+ return this;
+ }
+
+ /** Sets number of schema types filtered. */
+ @NonNull
+ public Builder setFilteredSchemaTypeCount(int filteredSchemaTypeCount) {
+ mNativeNumSchemaTypesFiltered = filteredSchemaTypeCount;
+ return this;
+ }
+
+ /** Sets the requested number of results in one page. */
+ @NonNull
+ public Builder setRequestedPageSize(int requestedPageSize) {
+ mNativeRequestedPageSize = requestedPageSize;
+ return this;
+ }
+
+ /** Sets the actual number of results returned in the current page. */
+ @NonNull
+ public Builder setCurrentPageReturnedResultCount(
+ int currentPageReturnedResultCount) {
+ mNativeNumResultsReturnedCurrentPage = currentPageReturnedResultCount;
+ return this;
+ }
+
+ /**
+ * Sets whether the function call is querying the first page. If it's
+ * not, Icing will fetch the results from cache so that some steps
+ * may be skipped.
+ */
+ @NonNull
+ public Builder setIsFirstPage(boolean nativeIsFirstPage) {
+ mNativeIsFirstPage = nativeIsFirstPage;
+ return this;
+ }
+
+ /**
+ * Sets time used to parse the query, including 2 parts: tokenizing and
+ * transforming tokens into an iterator tree.
+ */
+ @NonNull
+ public Builder setParseQueryLatencyMillis(int parseQueryLatencyMillis) {
+ mNativeParseQueryLatencyMillis = parseQueryLatencyMillis;
+ return this;
+ }
+
+ /** Sets strategy of scoring and ranking. */
+ @NonNull
+ public Builder setRankingStrategy(
+ @SearchSpec.RankingStrategy int rankingStrategy) {
+ mNativeRankingStrategy = rankingStrategy;
+ return this;
+ }
+
+ /** Sets number of documents scored. */
+ @NonNull
+ public Builder setScoredDocumentCount(int scoredDocumentCount) {
+ mNativeNumDocumentsScored = scoredDocumentCount;
+ return this;
+ }
+
+ /** Sets time used to score the raw results. */
+ @NonNull
+ public Builder setScoringLatencyMillis(int scoringLatencyMillis) {
+ mNativeScoringLatencyMillis = scoringLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to rank the scored results. */
+ @NonNull
+ public Builder setRankingLatencyMillis(int rankingLatencyMillis) {
+ mNativeRankingLatencyMillis = rankingLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to fetch the document protos. */
+ @NonNull
+ public Builder setDocumentRetrievingLatencyMillis(
+ int documentRetrievingLatencyMillis) {
+ mNativeDocumentRetrievingLatencyMillis = documentRetrievingLatencyMillis;
+ return this;
+ }
+
+ /** Sets how many snippets are calculated. */
+ @NonNull
+ public Builder setResultWithSnippetsCount(int resultWithSnippetsCount) {
+ mNativeNumResultsWithSnippets = resultWithSnippetsCount;
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link SearchStats} from the contents of this
+ * {@link SearchStats.Builder}.
+ */
+ @NonNull
+ public SearchStats build() {
+ if (mDatabase == null) {
+ Preconditions.checkState(mVisibilityScope != SearchStats.VISIBILITY_SCOPE_LOCAL,
+ "database can not be null if visibilityScope is local.");
+ }
+
+ return new SearchStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SetSchemaStats.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SetSchemaStats.java
new file mode 100644
index 0000000..314f964
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/stats/SetSchemaStats.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.stats;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.core.util.Preconditions;
+
+/**
+ * Class holds detailed stats for
+ * {@link androidx.appsearch.app.AppSearchSession#setSchema(SetSchemaRequest)}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class SetSchemaStats {
+ @NonNull
+ private final String mPackageName;
+
+ @NonNull
+ private final String mDatabase;
+
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode
+ private final int mStatusCode;
+
+ /**
+ * Stores stats of SchemaMigration in SetSchema process. Is {@code null} if no schema migration
+ * is needed.
+ */
+ @Nullable
+ private final SchemaMigrationStats mSchemaMigrationStats;
+
+ private final int mTotalLatencyMillis;
+
+ /** Number of newly added schema types. */
+ private final int mNewTypeCount;
+
+ /** Number of deleted schema types. */
+ private final int mDeletedTypeCount;
+
+ /** Number of compatible schema type changes. */
+ private final int mCompatibleTypeChangeCount;
+
+ /** Number of index-incompatible schema type changes. */
+ private final int mIndexIncompatibleTypeChangeCount;
+
+ /** Number of backwards-incompatible schema type changes. */
+ private final int mBackwardsIncompatibleTypeChangeCount;
+
+ SetSchemaStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mPackageName = builder.mPackageName;
+ mDatabase = builder.mDatabase;
+ mStatusCode = builder.mStatusCode;
+ mSchemaMigrationStats = builder.mSchemaMigrationStats;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mNewTypeCount = builder.mNewTypeCount;
+ mDeletedTypeCount = builder.mDeletedTypeCount;
+ mCompatibleTypeChangeCount = builder.mCompatibleTypeChangeCount;
+ mIndexIncompatibleTypeChangeCount = builder.mIndexIncompatibleTypeChangeCount;
+ mBackwardsIncompatibleTypeChangeCount = builder.mBackwardsIncompatibleTypeChangeCount;
+ }
+
+ /** Returns calling package name. */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns calling database name. */
+ @NonNull
+ public String getDatabase() {
+ return mDatabase;
+ }
+
+ /** Returns status of the SetSchema action. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /**
+ * Returns the status of schema migration, if migration is executed during the SetSchema
+ * process. Otherwise, returns {@code null}.
+ */
+ @Nullable
+ public SchemaMigrationStats getSchemaMigrationStats() {
+ return mSchemaMigrationStats;
+ }
+
+ /** Returns the total latency of the SetSchema action. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns number of newly added schema types. */
+ public int getNewTypeCount() {
+ return mNewTypeCount;
+ }
+
+ /** Returns number of deleted schema types. */
+ public int getDeletedTypeCount() {
+ return mDeletedTypeCount;
+ }
+
+ /** Returns number of compatible type changes. */
+ public int getCompatibleTypeChangeCount() {
+ return mCompatibleTypeChangeCount;
+ }
+
+ /**
+ * Returns number of index-incompatible type change.
+ *
+ * <p>An index-incompatible type change is one that affects how pre-existing data should be
+ * searched over, such as modifying the {@code IndexingType} of an existing property.
+ */
+ public int getIndexIncompatibleTypeChangeCount() {
+ return mIndexIncompatibleTypeChangeCount;
+ }
+
+ /**
+ * Returns number of backwards-incompatible type change.
+ *
+ * <p>For details on what constitutes a backward-incompatible type change, please see
+ * {@link androidx.appsearch.app.SetSchemaRequest}.
+ */
+ public int getBackwardsIncompatibleTypeChangeCount() {
+ return mBackwardsIncompatibleTypeChangeCount;
+ }
+
+ /** Builder for {@link SetSchemaStats}. */
+ public static class Builder {
+ @NonNull
+ final String mPackageName;
+ @NonNull
+ final String mDatabase;
+ @AppSearchResult.ResultCode
+ int mStatusCode;
+ @Nullable
+ SchemaMigrationStats mSchemaMigrationStats;
+ int mTotalLatencyMillis;
+ int mNewTypeCount;
+ int mDeletedTypeCount;
+ int mCompatibleTypeChangeCount;
+ int mIndexIncompatibleTypeChangeCount;
+ int mBackwardsIncompatibleTypeChangeCount;
+
+ /** Constructor for the {@link Builder}. */
+ public Builder(@NonNull String packageName, @NonNull String database) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabase = Preconditions.checkNotNull(database);
+ }
+
+ /** Sets the status of the SetSchema action. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets the status of schema migration. */
+ @NonNull
+ public Builder setSchemaMigrationStats(@NonNull SchemaMigrationStats schemaMigrationStats) {
+ mSchemaMigrationStats = Preconditions.checkNotNull(schemaMigrationStats);
+ return this;
+ }
+
+ /** Sets total latency for the SetSchema action in milliseconds. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets number of new types. */
+ @NonNull
+ public Builder setNewTypeCount(int newTypeCount) {
+ mNewTypeCount = newTypeCount;
+ return this;
+ }
+
+ /** Sets number of deleted types. */
+ @NonNull
+ public Builder setDeletedTypeCount(int deletedTypeCount) {
+ mDeletedTypeCount = deletedTypeCount;
+ return this;
+ }
+
+ /** Sets number of compatible type changes. */
+ @NonNull
+ public Builder setCompatibleTypeChangeCount(int compatibleTypeChangeCount) {
+ mCompatibleTypeChangeCount = compatibleTypeChangeCount;
+ return this;
+ }
+
+ /** Sets number of index-incompatible type changes. */
+ @NonNull
+ public Builder setIndexIncompatibleTypeChangeCount(int indexIncompatibleTypeChangeCount) {
+ mIndexIncompatibleTypeChangeCount = indexIncompatibleTypeChangeCount;
+ return this;
+ }
+
+ /** Sets number of backwards-incompatible type changes. */
+ @NonNull
+ public Builder setBackwardsIncompatibleTypeChangeCount(
+ int backwardsIncompatibleTypeChangeCount) {
+ mBackwardsIncompatibleTypeChangeCount = backwardsIncompatibleTypeChangeCount;
+ return this;
+ }
+
+ /** Builds a new {@link SetSchemaStats} from the {@link Builder}. */
+ @NonNull
+ public SetSchemaStats build() {
+ return new SetSchemaStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/util/FutureUtil.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/util/FutureUtil.java
index 99f5ae1..f22ceb0 100644
--- a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/util/FutureUtil.java
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/util/FutureUtil.java
@@ -24,7 +24,7 @@
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executor;
/**
* Utilities for working with {@link com.google.common.util.concurrent.ListenableFuture}.
@@ -37,7 +37,7 @@
/** Executes the given lambda on the given executor and returns a {@link ListenableFuture}. */
@NonNull
public static <T> ListenableFuture<T> execute(
- @NonNull ExecutorService executor,
+ @NonNull Executor executor,
@NonNull Callable<T> callable) {
Preconditions.checkNotNull(executor);
Preconditions.checkNotNull(callable);
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/util/PrefixUtil.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/util/PrefixUtil.java
new file mode 100644
index 0000000..12d4587
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/util/PrefixUtil.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.localstorage.util;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.exceptions.AppSearchException;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
+/**
+ * Provides utility functions for working with package + database prefixes.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class PrefixUtil {
+ private static final String TAG = "AppSearchPrefixUtil";
+
+ @VisibleForTesting
+ public static final char DATABASE_DELIMITER = '/';
+
+ @VisibleForTesting
+ public static final char PACKAGE_DELIMITER = '$';
+
+ private PrefixUtil() {}
+
+ /**
+ * Creates prefix string for given package name and database name.
+ */
+ @NonNull
+ public static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
+ return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
+ }
+ /**
+ * Creates prefix string for given package name.
+ */
+ @NonNull
+ public static String createPackagePrefix(@NonNull String packageName) {
+ return packageName + PACKAGE_DELIMITER;
+ }
+
+ /**
+ * Returns the package name that's contained within the {@code prefix}.
+ *
+ * @param prefix Prefix string that contains the package name inside of it. The package name
+ * must be in the front of the string, and separated from the rest of the
+ * string by the {@link #PACKAGE_DELIMITER}.
+ * @return Valid package name.
+ */
+ @NonNull
+ public static String getPackageName(@NonNull String prefix) {
+ int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
+ if (delimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
+ return "";
+ }
+ return prefix.substring(0, delimiterIndex);
+ }
+
+ /**
+ * Returns the database name that's contained within the {@code prefix}.
+ *
+ * @param prefix Prefix string that contains the database name inside of it. The database name
+ * must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
+ * @return Valid database name.
+ */
+ @NonNull
+ public static String getDatabaseName(@NonNull String prefix) {
+ // TODO (b/184050178) Start database delimiter index search from after package delimiter
+ int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
+ int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
+ if (packageDelimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
+ return "";
+ }
+ if (databaseDelimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
+ return "";
+ }
+ return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
+ }
+
+ /**
+ * Creates a string with the package and database prefix removed from the input string.
+ *
+ * @param prefixedString a string containing a package and database prefix.
+ * @return a string with the package and database prefix removed.
+ * @throws AppSearchException if the prefixed value does not contain a valid database name.
+ */
+ @NonNull
+ public static String removePrefix(@NonNull String prefixedString)
+ throws AppSearchException {
+ // The prefix is made up of the package, then the database. So we only need to find the
+ // database cutoff.
+ int delimiterIndex;
+ if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ return prefixedString.substring(delimiterIndex + 1);
+ }
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "The prefixed value \"" + prefixedString + "\" doesn't contain a valid "
+ + "database name");
+ }
+
+ /**
+ * Creates a package and database prefix string from the input string.
+ *
+ * @param prefixedString a string containing a package and database prefix.
+ * @return a string with the package and database prefix
+ * @throws AppSearchException if the prefixed value does not contain a valid database name.
+ */
+ @NonNull
+ public static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
+ int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
+ if (databaseDelimiterIndex == -1) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "The prefixed value \"" + prefixedString + "\" doesn't contain a valid "
+ + "database name");
+ }
+
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ return prefixedString.substring(0, databaseDelimiterIndex + 1);
+ }
+
+ /**
+ * Prepends {@code prefix} to all types and namespaces mentioned anywhere in
+ * {@code documentBuilder}.
+ *
+ * @param documentBuilder The document to mutate
+ * @param prefix The prefix to add
+ */
+ public static void addPrefixToDocument(
+ @NonNull DocumentProto.Builder documentBuilder,
+ @NonNull String prefix) {
+ // Rewrite the type name to include/remove the prefix.
+ String newSchema = prefix + documentBuilder.getSchema();
+ documentBuilder.setSchema(newSchema);
+
+ // Rewrite the namespace to include/remove the prefix.
+ documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ addPrefixToDocument(derivedDocumentBuilder, prefix);
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+ }
+
+ /**
+ * Removes any prefixes from types and namespaces mentioned anywhere in
+ * {@code documentBuilder}.
+ *
+ * @param documentBuilder The document to mutate
+ * @return Prefix name that was removed from the document.
+ * @throws AppSearchException if there are unexpected database prefixing errors.
+ */
+ @NonNull
+ public static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
+ throws AppSearchException {
+ // Rewrite the type name and namespace to remove the prefix.
+ String schemaPrefix = getPrefix(documentBuilder.getSchema());
+ String namespacePrefix = getPrefix(documentBuilder.getNamespace());
+
+ if (!schemaPrefix.equals(namespacePrefix)) {
+ throw new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR, "Found unexpected"
+ + " multiple prefix names in document: " + schemaPrefix + ", "
+ + namespacePrefix);
+ }
+
+ documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
+ documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
+ if (!nestedPrefix.equals(schemaPrefix)) {
+ throw new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Found unexpected multiple prefix names in document: "
+ + schemaPrefix + ", " + nestedPrefix);
+ }
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+
+ return schemaPrefix;
+ }
+}
diff --git a/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/visibilitystore/VisibilityStore.java b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/visibilitystore/VisibilityStore.java
new file mode 100644
index 0000000..d3d754e
--- /dev/null
+++ b/appsearch/local-storage/src/main/java/androidx/appsearch/localstorage/visibilitystore/VisibilityStore.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.localstorage.visibilitystore;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
+import androidx.appsearch.app.PackageIdentifier;
+import androidx.appsearch.exceptions.AppSearchException;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An interface for classes that store and validate document visibility data.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface VisibilityStore {
+ /**
+ * These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
+ * AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
+ */
+ String PACKAGE_NAME = "VS#Pkg";
+
+ @VisibleForTesting
+ String DATABASE_NAME = "VS#Db";
+
+ /**
+ * Sets visibility settings for the given database. Any previous visibility settings will be
+ * overwritten.
+ *
+ * @param packageName Package of app that owns the schemas.
+ * @param databaseName Database that owns the schemas.
+ * @param schemasNotDisplayedBySystem Set of prefixed schemas that should be hidden from
+ * platform surfaces.
+ * @param schemasVisibleToPackages Map of prefixed schemas to a list of package identifiers that
+ * have access to the schema.
+ * @throws AppSearchException on AppSearchImpl error.
+ */
+ void setVisibility(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull Set<String> schemasNotDisplayedBySystem,
+ @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages)
+ throws AppSearchException;
+
+ /**
+ * Checks whether the given package has access to system-surfaceable schemas.
+ *
+ * @param callerUid UID of the app that wants to see the data.
+ */
+ boolean isSchemaSearchableByCaller(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull String prefixedSchema,
+ int callerUid,
+ boolean callerHasSystemAccess);
+}
diff --git a/appsearch/platform-storage/api/current.txt b/appsearch/platform-storage/api/current.txt
new file mode 100644
index 0000000..881789d
--- /dev/null
+++ b/appsearch/platform-storage/api/current.txt
@@ -0,0 +1,31 @@
+// Signature format: 4.0
+package androidx.appsearch.platformstorage {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.S) public final class PlatformStorage {
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.GlobalSearchSession!> createGlobalSearchSession(androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchSession!> createSearchSession(androidx.appsearch.platformstorage.PlatformStorage.SearchContext);
+ }
+
+ public static final class PlatformStorage.GlobalSearchContext {
+ method public java.util.concurrent.Executor getWorkerExecutor();
+ }
+
+ public static final class PlatformStorage.GlobalSearchContext.Builder {
+ ctor public PlatformStorage.GlobalSearchContext.Builder(android.content.Context);
+ method public androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext build();
+ method public androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
+ }
+
+ public static final class PlatformStorage.SearchContext {
+ method public String getDatabaseName();
+ method public java.util.concurrent.Executor getWorkerExecutor();
+ }
+
+ public static final class PlatformStorage.SearchContext.Builder {
+ ctor public PlatformStorage.SearchContext.Builder(android.content.Context, String);
+ method public androidx.appsearch.platformstorage.PlatformStorage.SearchContext build();
+ method public androidx.appsearch.platformstorage.PlatformStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
+ }
+
+}
+
diff --git a/appsearch/platform-storage/api/public_plus_experimental_current.txt b/appsearch/platform-storage/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..881789d
--- /dev/null
+++ b/appsearch/platform-storage/api/public_plus_experimental_current.txt
@@ -0,0 +1,31 @@
+// Signature format: 4.0
+package androidx.appsearch.platformstorage {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.S) public final class PlatformStorage {
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.GlobalSearchSession!> createGlobalSearchSession(androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchSession!> createSearchSession(androidx.appsearch.platformstorage.PlatformStorage.SearchContext);
+ }
+
+ public static final class PlatformStorage.GlobalSearchContext {
+ method public java.util.concurrent.Executor getWorkerExecutor();
+ }
+
+ public static final class PlatformStorage.GlobalSearchContext.Builder {
+ ctor public PlatformStorage.GlobalSearchContext.Builder(android.content.Context);
+ method public androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext build();
+ method public androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
+ }
+
+ public static final class PlatformStorage.SearchContext {
+ method public String getDatabaseName();
+ method public java.util.concurrent.Executor getWorkerExecutor();
+ }
+
+ public static final class PlatformStorage.SearchContext.Builder {
+ ctor public PlatformStorage.SearchContext.Builder(android.content.Context, String);
+ method public androidx.appsearch.platformstorage.PlatformStorage.SearchContext build();
+ method public androidx.appsearch.platformstorage.PlatformStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
+ }
+
+}
+
diff --git a/slice/slice-builders/ktx/api/res-current.txt b/appsearch/platform-storage/api/res-current.txt
similarity index 100%
copy from slice/slice-builders/ktx/api/res-current.txt
copy to appsearch/platform-storage/api/res-current.txt
diff --git a/appsearch/platform-storage/api/restricted_current.txt b/appsearch/platform-storage/api/restricted_current.txt
new file mode 100644
index 0000000..881789d
--- /dev/null
+++ b/appsearch/platform-storage/api/restricted_current.txt
@@ -0,0 +1,31 @@
+// Signature format: 4.0
+package androidx.appsearch.platformstorage {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.S) public final class PlatformStorage {
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.GlobalSearchSession!> createGlobalSearchSession(androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchSession!> createSearchSession(androidx.appsearch.platformstorage.PlatformStorage.SearchContext);
+ }
+
+ public static final class PlatformStorage.GlobalSearchContext {
+ method public java.util.concurrent.Executor getWorkerExecutor();
+ }
+
+ public static final class PlatformStorage.GlobalSearchContext.Builder {
+ ctor public PlatformStorage.GlobalSearchContext.Builder(android.content.Context);
+ method public androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext build();
+ method public androidx.appsearch.platformstorage.PlatformStorage.GlobalSearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
+ }
+
+ public static final class PlatformStorage.SearchContext {
+ method public String getDatabaseName();
+ method public java.util.concurrent.Executor getWorkerExecutor();
+ }
+
+ public static final class PlatformStorage.SearchContext.Builder {
+ ctor public PlatformStorage.SearchContext.Builder(android.content.Context, String);
+ method public androidx.appsearch.platformstorage.PlatformStorage.SearchContext build();
+ method public androidx.appsearch.platformstorage.PlatformStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
+ }
+
+}
+
diff --git a/appsearch/platform-storage/build.gradle b/appsearch/platform-storage/build.gradle
new file mode 100644
index 0000000..de527dd6
--- /dev/null
+++ b/appsearch/platform-storage/build.gradle
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+}
+
+dependencies {
+ api("androidx.annotation:annotation:1.1.0")
+
+ implementation project(":appsearch:appsearch")
+ implementation("androidx.concurrent:concurrent-futures:1.0.0")
+ implementation("androidx.core:core:1.2.0")
+
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
+ androidTestImplementation("junit:junit:4.13")
+}
+
+androidx {
+ name = "AppSearch Platform Storage"
+ publish = Publish.SNAPSHOT_AND_RELEASE
+ mavenGroup = LibraryGroups.APPSEARCH
+ mavenVersion = LibraryVersions.APPSEARCH
+ inceptionYear = "2021"
+ description =
+ "An implementation of AppSearchSession which uses the AppSearch service on Android S+"
+}
diff --git a/appsearch/platform-storage/lint-baseline.xml b/appsearch/platform-storage/lint-baseline.xml
new file mode 100644
index 0000000..f23e084
--- /dev/null
+++ b/appsearch/platform-storage/lint-baseline.xml
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-alpha03" type="baseline" client="gradle" name="AGP (7.1.0-alpha03)" variant="all" version="7.1.0-alpha03">
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: AppSearchResult.RESULT_OK, AppSearchResult.RESULT_UNKNOWN_ERROR, AppSearchResult.RESULT_INTERNAL_ERROR, AppSearchResult.RESULT_INVALID_ARGUMENT, AppSearchResult.RESULT_IO_ERROR, AppSearchResult.RESULT_OUT_OF_SPACE, AppSearchResult.RESULT_NOT_FOUND, AppSearchResult.RESULT_INVALID_SCHEMA, AppSearchResult.RESULT_SECURITY_ERROR"
+ errorLine1=" platformResult.getResultCode(), platformResult.getErrorMessage());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/AppSearchResultToPlatformConverter.java"
+ line="55"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: AppSearchResult.RESULT_OK, AppSearchResult.RESULT_UNKNOWN_ERROR, AppSearchResult.RESULT_INTERNAL_ERROR, AppSearchResult.RESULT_INVALID_ARGUMENT, AppSearchResult.RESULT_IO_ERROR, AppSearchResult.RESULT_OUT_OF_SPACE, AppSearchResult.RESULT_NOT_FOUND, AppSearchResult.RESULT_INVALID_SCHEMA, AppSearchResult.RESULT_SECURITY_ERROR"
+ errorLine1=" platformResult.getResultCode(), platformResult.getErrorMessage()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/AppSearchResultToPlatformConverter.java"
+ line="72"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: AppSearchResult.RESULT_OK, AppSearchResult.RESULT_UNKNOWN_ERROR, AppSearchResult.RESULT_INTERNAL_ERROR, AppSearchResult.RESULT_INVALID_ARGUMENT, AppSearchResult.RESULT_IO_ERROR, AppSearchResult.RESULT_OUT_OF_SPACE, AppSearchResult.RESULT_NOT_FOUND, AppSearchResult.RESULT_INVALID_SCHEMA, AppSearchResult.RESULT_SECURITY_ERROR"
+ errorLine1=" failure.getValue().getResultCode(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/AppSearchResultToPlatformConverter.java"
+ line="99"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: AppSearchResult.RESULT_OK, AppSearchResult.RESULT_UNKNOWN_ERROR, AppSearchResult.RESULT_INTERNAL_ERROR, AppSearchResult.RESULT_INVALID_ARGUMENT, AppSearchResult.RESULT_IO_ERROR, AppSearchResult.RESULT_OUT_OF_SPACE, AppSearchResult.RESULT_NOT_FOUND, AppSearchResult.RESULT_INVALID_SCHEMA, AppSearchResult.RESULT_SECURITY_ERROR"
+ errorLine1=" result.getResultCode(), result.getErrorMessage()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/PlatformStorage.java"
+ line="228"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: AppSearchResult.RESULT_OK, AppSearchResult.RESULT_UNKNOWN_ERROR, AppSearchResult.RESULT_INTERNAL_ERROR, AppSearchResult.RESULT_INVALID_ARGUMENT, AppSearchResult.RESULT_IO_ERROR, AppSearchResult.RESULT_OUT_OF_SPACE, AppSearchResult.RESULT_NOT_FOUND, AppSearchResult.RESULT_INVALID_SCHEMA, AppSearchResult.RESULT_SECURITY_ERROR"
+ errorLine1=" result.getResultCode(), result.getErrorMessage()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/PlatformStorage.java"
+ line="253"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(stringProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="86"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: StringPropertyConfig.INDEXING_TYPE_NONE, StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS, StringPropertyConfig.INDEXING_TYPE_PREFIXES"
+ errorLine1=" .setIndexingType(stringProperty.getIndexingType())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="87"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: StringPropertyConfig.TOKENIZER_TYPE_NONE, StringPropertyConfig.TOKENIZER_TYPE_PLAIN"
+ errorLine1=" .setTokenizerType(stringProperty.getTokenizerType())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="88"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(jetpackProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="93"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(jetpackProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="98"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(jetpackProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="103"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(jetpackProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="108"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(documentProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="115"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(stringProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="133"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: StringPropertyConfig.INDEXING_TYPE_NONE, StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS, StringPropertyConfig.INDEXING_TYPE_PREFIXES"
+ errorLine1=" .setIndexingType(stringProperty.getIndexingType())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="134"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: StringPropertyConfig.TOKENIZER_TYPE_NONE, StringPropertyConfig.TOKENIZER_TYPE_PLAIN"
+ errorLine1=" .setTokenizerType(stringProperty.getTokenizerType())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="135"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(platformProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="140"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(platformProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="145"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(platformProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="150"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(platformProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="155"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: PropertyConfig.CARDINALITY_REPEATED, PropertyConfig.CARDINALITY_OPTIONAL, PropertyConfig.CARDINALITY_REQUIRED"
+ errorLine1=" .setCardinality(documentProperty.getCardinality())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java"
+ line="164"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: AppSearchResult.RESULT_OK, AppSearchResult.RESULT_UNKNOWN_ERROR, AppSearchResult.RESULT_INTERNAL_ERROR, AppSearchResult.RESULT_INVALID_ARGUMENT, AppSearchResult.RESULT_IO_ERROR, AppSearchResult.RESULT_OUT_OF_SPACE, AppSearchResult.RESULT_NOT_FOUND, AppSearchResult.RESULT_INVALID_SCHEMA, AppSearchResult.RESULT_SECURITY_ERROR"
+ errorLine1=" new AppSearchException(result.getResultCode(), result.getErrorMessage()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java"
+ line="71"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: AppSearchResult.RESULT_OK, AppSearchResult.RESULT_UNKNOWN_ERROR, AppSearchResult.RESULT_INTERNAL_ERROR, AppSearchResult.RESULT_INVALID_ARGUMENT, AppSearchResult.RESULT_IO_ERROR, AppSearchResult.RESULT_OUT_OF_SPACE, AppSearchResult.RESULT_NOT_FOUND, AppSearchResult.RESULT_INVALID_SCHEMA, AppSearchResult.RESULT_SECURITY_ERROR"
+ errorLine1=" platformResult.getResultCode(), platformResult.getErrorMessage()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java"
+ line="258"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: SearchSpec.TERM_MATCH_EXACT_ONLY, SearchSpec.TERM_MATCH_PREFIX"
+ errorLine1=" .setTermMatch(jetpackSearchSpec.getTermMatch())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java"
+ line="49"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: SearchSpec.RANKING_STRATEGY_NONE, SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE, SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP, SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE, SearchSpec.RANKING_STRATEGY_USAGE_COUNT, SearchSpec.RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP, SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_COUNT, SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP"
+ errorLine1=" .setRankingStrategy(jetpackSearchSpec.getRankingStrategy())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java"
+ line="54"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: SearchSpec.ORDER_DESCENDING, SearchSpec.ORDER_ASCENDING"
+ errorLine1=" .setOrder(jetpackSearchSpec.getOrder())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java"
+ line="55"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="WrongConstant"
+ message="Must be one or more of: SearchSpec.GROUPING_TYPE_PER_PACKAGE, SearchSpec.GROUPING_TYPE_PER_NAMESPACE"
+ errorLine1=" jetpackSearchSpec.getResultGroupingTypeFlags(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java"
+ line="61"
+ column="21"/>
+ </issue>
+
+</issues>
diff --git a/appsearch/platform-storage/src/androidTest/AndroidManifest.xml b/appsearch/platform-storage/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..06cf077
--- /dev/null
+++ b/appsearch/platform-storage/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright (C) 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
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.appsearch.platformstorage.test">
+</manifest>
diff --git a/appsearch/platform-storage/src/androidTest/java/androidx/appsearch/platformstorage/PlatformStorageTest.java b/appsearch/platform-storage/src/androidTest/java/androidx/appsearch/platformstorage/PlatformStorageTest.java
new file mode 100644
index 0000000..3adaf9c
--- /dev/null
+++ b/appsearch/platform-storage/src/androidTest/java/androidx/appsearch/platformstorage/PlatformStorageTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.platformstorage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class PlatformStorageTest {
+ @Test
+ public void testSearchContext_databaseName() {
+ PlatformStorage.SearchContext searchContext =
+ new PlatformStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ /*databaseName=*/"dbName").build();
+
+ assertThat(searchContext.getDatabaseName()).isEqualTo("dbName");
+ }
+
+ @Test
+ public void testSearchContext_withClientExecutor() {
+ Executor executor = Executors.newSingleThreadExecutor();
+ PlatformStorage.SearchContext searchContext = new PlatformStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ /*databaseName=*/"dbName")
+ .setWorkerExecutor(executor)
+ .build();
+
+ assertThat(searchContext.getWorkerExecutor()).isEqualTo(executor);
+ assertThat(searchContext.getDatabaseName()).isEqualTo("dbName");
+ }
+
+ @Test
+ public void testSearchContext_withDefaultExecutor() {
+ PlatformStorage.SearchContext searchContext = new PlatformStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ /*databaseName=*/"dbName")
+ .build();
+
+ assertThat(searchContext.getWorkerExecutor()).isNotNull();
+ assertThat(searchContext.getDatabaseName()).isEqualTo("dbName");
+ }
+
+ @Test
+ public void testSearchContext_withInvalidDatabaseName() {
+ // Test special character can present in database name. When a special character is banned
+ // in database name, add checker in SearchContext.Builder and reflect it in java doc.
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> new PlatformStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ "testDatabaseNameEndWith/").build());
+ assertThat(e).hasMessageThat().isEqualTo("Database name cannot contain '/'");
+ e = assertThrows(IllegalArgumentException.class,
+ () -> new PlatformStorage.SearchContext.Builder(
+ ApplicationProvider.getApplicationContext(),
+ "/testDatabaseNameStartWith").build());
+ assertThat(e).hasMessageThat().isEqualTo("Database name cannot contain '/'");
+ }
+}
diff --git a/appsearch/platform-storage/src/main/AndroidManifest.xml b/appsearch/platform-storage/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3cd15c8
--- /dev/null
+++ b/appsearch/platform-storage/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest package="androidx.appsearch.platformstorage"/>
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
new file mode 100644
index 0000000..d5e9972
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.platformstorage;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GlobalSearchSession;
+import androidx.appsearch.app.ReportSystemUsageRequest;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.platformstorage.converter.AppSearchResultToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.RequestToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.SearchSpecToPlatformConverter;
+import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.util.Preconditions;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.Executor;
+
+/**
+ * An implementation of {@link androidx.appsearch.app.GlobalSearchSession} which proxies to a
+ * platform {@link android.app.appsearch.GlobalSearchSession}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+class GlobalSearchSessionImpl implements GlobalSearchSession {
+ private final android.app.appsearch.GlobalSearchSession mPlatformSession;
+ private final Executor mExecutor;
+
+ GlobalSearchSessionImpl(
+ @NonNull android.app.appsearch.GlobalSearchSession platformSession,
+ @NonNull Executor executor) {
+ mPlatformSession = Preconditions.checkNotNull(platformSession);
+ mExecutor = Preconditions.checkNotNull(executor);
+ }
+
+ @Override
+ @NonNull
+ public SearchResults search(
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec) {
+ Preconditions.checkNotNull(queryExpression);
+ Preconditions.checkNotNull(searchSpec);
+ android.app.appsearch.SearchResults platformSearchResults =
+ mPlatformSession.search(
+ queryExpression,
+ SearchSpecToPlatformConverter.toPlatformSearchSpec(searchSpec));
+ return new SearchResultsImpl(platformSearchResults, mExecutor);
+ }
+
+ @NonNull
+ @Override
+ public ListenableFuture<Void> reportSystemUsage(@NonNull ReportSystemUsageRequest request) {
+ Preconditions.checkNotNull(request);
+ ResolvableFuture<Void> future = ResolvableFuture.create();
+ mPlatformSession.reportSystemUsage(
+ RequestToPlatformConverter.toPlatformReportSystemUsageRequest(request),
+ mExecutor,
+ result -> AppSearchResultToPlatformConverter.platformAppSearchResultToFuture(
+ result, future));
+ return future;
+ }
+
+ @Override
+ public void close() {
+ mPlatformSession.close();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/PlatformStorage.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/PlatformStorage.java
new file mode 100644
index 0000000..b07782b
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/PlatformStorage.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.platformstorage;
+
+import android.app.appsearch.AppSearchManager;
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GlobalSearchSession;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.platformstorage.converter.SearchContextToPlatformConverter;
+import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.util.Preconditions;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * An AppSearch storage system which stores data in the central AppSearch service, available on
+ * Android S+.
+ */
+@RequiresApi(Build.VERSION_CODES.S)
+public final class PlatformStorage {
+
+ private PlatformStorage() {
+ }
+
+ /** Contains information about how to create the search session. */
+ public static final class SearchContext {
+ final Context mContext;
+ final String mDatabaseName;
+ final Executor mExecutor;
+
+ SearchContext(@NonNull Context context, @NonNull String databaseName,
+ @NonNull Executor executor) {
+ mContext = Preconditions.checkNotNull(context);
+ mDatabaseName = Preconditions.checkNotNull(databaseName);
+ mExecutor = Preconditions.checkNotNull(executor);
+ }
+
+ /**
+ * Returns the name of the database to create or open.
+ */
+ @NonNull
+ public String getDatabaseName() {
+ return mDatabaseName;
+ }
+
+ /**
+ * Returns the worker executor associated with {@link AppSearchSession}.
+ *
+ * <p>If an executor is not provided to {@link Builder}, the AppSearch default executor will
+ * be returned. You should never cast the executor to
+ * {@link java.util.concurrent.ExecutorService} and call
+ * {@link ExecutorService#shutdownNow()}. It will cancel the futures it's returned. And
+ * since {@link Executor#execute} won't return anything, we will hang forever waiting for
+ * the execution.
+ */
+ @NonNull
+ public Executor getWorkerExecutor() {
+ return mExecutor;
+ }
+
+ /** Builder for {@link SearchContext} objects. */
+ public static final class Builder {
+ private final Context mContext;
+ private final String mDatabaseName;
+ private Executor mExecutor;
+
+ /**
+ * Creates a {@link SearchContext.Builder} instance.
+ *
+ * <p>{@link AppSearchSession} will create or open a database under the given name.
+ *
+ * <p>Databases with different names are fully separate with distinct schema types,
+ * namespaces, and documents.
+ *
+ * <p>The database name cannot contain {@code '/'}.
+ *
+ * <p>The database name will be visible to all system UI or third-party applications
+ * that have been granted access to any of the database's documents (for example,
+ * using {@link
+ * androidx.appsearch.app.SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage}).
+ *
+ * @param databaseName The name of the database.
+ * @throws IllegalArgumentException if the databaseName contains {@code '/'}.
+ */
+ public Builder(@NonNull Context context, @NonNull String databaseName) {
+ mContext = Preconditions.checkNotNull(context);
+ Preconditions.checkNotNull(databaseName);
+ if (databaseName.contains("/")) {
+ throw new IllegalArgumentException("Database name cannot contain '/'");
+ }
+ mDatabaseName = databaseName;
+ }
+
+ /**
+ * Sets the worker executor associated with {@link AppSearchSession}.
+ *
+ * <p>If an executor is not provided, the AppSearch default executor will be used.
+ *
+ * @param executor the worker executor used to run heavy background tasks.
+ */
+ @NonNull
+ public Builder setWorkerExecutor(@NonNull Executor executor) {
+ mExecutor = Preconditions.checkNotNull(executor);
+ return this;
+ }
+
+ /** Builds a {@link SearchContext} instance. */
+ @NonNull
+ public SearchContext build() {
+ if (mExecutor == null) {
+ mExecutor = EXECUTOR;
+ }
+ return new SearchContext(mContext, mDatabaseName, mExecutor);
+ }
+ }
+ }
+
+ /** Contains information relevant to creating a global search session. */
+ public static final class GlobalSearchContext {
+ final Context mContext;
+ final Executor mExecutor;
+
+ GlobalSearchContext(@NonNull Context context, @NonNull Executor executor) {
+ mContext = Preconditions.checkNotNull(context);
+ mExecutor = Preconditions.checkNotNull(executor);
+ }
+
+ /**
+ * Returns the worker executor associated with {@link GlobalSearchSession}.
+ *
+ * <p>If an executor is not provided to {@link Builder}, the AppSearch default executor will
+ * be returned. You should never cast the executor to
+ * {@link java.util.concurrent.ExecutorService} and call
+ * {@link ExecutorService#shutdownNow()}. It will cancel the futures it's returned. And
+ * since {@link Executor#execute} won't return anything, we will hang forever waiting for
+ * the execution.
+ */
+ @NonNull
+ public Executor getWorkerExecutor() {
+ return mExecutor;
+ }
+
+ /** Builder for {@link GlobalSearchContext} objects. */
+ public static final class Builder {
+ private final Context mContext;
+ private Executor mExecutor;
+
+ public Builder(@NonNull Context context) {
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ /**
+ * Sets the worker executor associated with {@link GlobalSearchSession}.
+ *
+ * <p>If an executor is not provided, the AppSearch default executor will be used.
+ *
+ * @param executor the worker executor used to run heavy background tasks.
+ */
+ @NonNull
+ public Builder setWorkerExecutor(@NonNull Executor executor) {
+ Preconditions.checkNotNull(executor);
+ mExecutor = executor;
+ return this;
+ }
+
+ /** Builds a {@link GlobalSearchContext} instance. */
+ @NonNull
+ public GlobalSearchContext build() {
+ if (mExecutor == null) {
+ mExecutor = EXECUTOR;
+ }
+ return new GlobalSearchContext(mContext, mExecutor);
+ }
+ }
+ }
+
+ // Never call Executor.shutdownNow(), it will cancel the futures it's returned. And since
+ // execute() won't return anything, we will hang forever waiting for the execution.
+ // AppSearch multi-thread execution is guarded by Read & Write Lock in AppSearchImpl, all
+ // mutate requests will need to gain write lock and query requests need to gain read lock.
+ static final Executor EXECUTOR = Executors.newCachedThreadPool();
+
+ /**
+ * Opens a new {@link AppSearchSession} on this storage.
+ *
+ * @param context The {@link SearchContext} contains all information to create a new
+ * {@link AppSearchSession}
+ */
+ @NonNull
+ public static ListenableFuture<AppSearchSession> createSearchSession(
+ @NonNull SearchContext context) {
+ Preconditions.checkNotNull(context);
+ AppSearchManager appSearchManager =
+ context.mContext.getSystemService(AppSearchManager.class);
+ ResolvableFuture<AppSearchSession> future = ResolvableFuture.create();
+ appSearchManager.createSearchSession(
+ SearchContextToPlatformConverter.toPlatformSearchContext(context),
+ context.mExecutor,
+ result -> {
+ if (result.isSuccess()) {
+ future.set(
+ new SearchSessionImpl(result.getResultValue(), context.mExecutor));
+ } else {
+ future.setException(
+ new AppSearchException(
+ result.getResultCode(), result.getErrorMessage()));
+ }
+ });
+ return future;
+ }
+
+ /**
+ * Opens a new {@link GlobalSearchSession} on this storage.
+ */
+ @NonNull
+ public static ListenableFuture<GlobalSearchSession> createGlobalSearchSession(
+ @NonNull GlobalSearchContext context) {
+ Preconditions.checkNotNull(context);
+ AppSearchManager appSearchManager =
+ context.mContext.getSystemService(AppSearchManager.class);
+ ResolvableFuture<GlobalSearchSession> future = ResolvableFuture.create();
+ appSearchManager.createGlobalSearchSession(
+ context.mExecutor,
+ result -> {
+ if (result.isSuccess()) {
+ future.set(new GlobalSearchSessionImpl(
+ result.getResultValue(), context.mExecutor));
+ } else {
+ future.setException(
+ new AppSearchException(
+ result.getResultCode(), result.getErrorMessage()));
+ }
+ });
+ return future;
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java
new file mode 100644
index 0000000..52b15cf3
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.platformstorage;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.SearchResult;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.platformstorage.converter.SearchResultToPlatformConverter;
+import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.util.Preconditions;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Platform implementation of {@link SearchResults} which proxies to the platform's
+ * {@link android.app.appsearch.SearchResults}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+class SearchResultsImpl implements SearchResults {
+ private final android.app.appsearch.SearchResults mPlatformResults;
+ private final Executor mExecutor;
+
+ SearchResultsImpl(
+ @NonNull android.app.appsearch.SearchResults platformResults,
+ @NonNull Executor executor) {
+ mPlatformResults = Preconditions.checkNotNull(platformResults);
+ mExecutor = Preconditions.checkNotNull(executor);
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<List<SearchResult>> getNextPage() {
+ ResolvableFuture<List<SearchResult>> future = ResolvableFuture.create();
+ mPlatformResults.getNextPage(mExecutor, result -> {
+ if (result.isSuccess()) {
+ List<android.app.appsearch.SearchResult> frameworkResults = result.getResultValue();
+ List<SearchResult> jetpackResults = new ArrayList<>(frameworkResults.size());
+ for (int i = 0; i < frameworkResults.size(); i++) {
+ SearchResult jetpackResult =
+ SearchResultToPlatformConverter.toJetpackSearchResult(
+ frameworkResults.get(i));
+ jetpackResults.add(jetpackResult);
+ }
+ future.set(jetpackResults);
+ } else {
+ future.setException(
+ new AppSearchException(result.getResultCode(), result.getErrorMessage()));
+ }
+ });
+ return future;
+ }
+
+ @Override
+ public void close() {
+ mPlatformResults.close();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
new file mode 100644
index 0000000..8cbf935d
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.platformstorage;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.GetByDocumentIdRequest;
+import androidx.appsearch.app.GetSchemaResponse;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.RemoveByDocumentIdRequest;
+import androidx.appsearch.app.ReportUsageRequest;
+import androidx.appsearch.app.SearchResults;
+import androidx.appsearch.app.SearchSpec;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.appsearch.app.StorageInfo;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.appsearch.platformstorage.converter.AppSearchResultToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.GenericDocumentToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.RequestToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.ResponseToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.SchemaToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.SearchSpecToPlatformConverter;
+import androidx.appsearch.platformstorage.converter.SetSchemaRequestToPlatformConverter;
+import androidx.appsearch.platformstorage.util.BatchResultCallbackAdapter;
+import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.util.Preconditions;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+/**
+ * An implementation of {@link AppSearchSession} which proxies to a platform
+ * {@link android.app.appsearch.AppSearchSession}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+class SearchSessionImpl implements AppSearchSession {
+ private final android.app.appsearch.AppSearchSession mPlatformSession;
+ private final Executor mExecutor;
+
+ SearchSessionImpl(
+ @NonNull android.app.appsearch.AppSearchSession platformSession,
+ @NonNull Executor executor) {
+ mPlatformSession = Preconditions.checkNotNull(platformSession);
+ mExecutor = Preconditions.checkNotNull(executor);
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request) {
+ Preconditions.checkNotNull(request);
+ ResolvableFuture<SetSchemaResponse> future = ResolvableFuture.create();
+ mPlatformSession.setSchema(
+ SetSchemaRequestToPlatformConverter.toPlatformSetSchemaRequest(request),
+ mExecutor,
+ mExecutor,
+ result -> {
+ if (result.isSuccess()) {
+ SetSchemaResponse jetpackResponse =
+ SetSchemaRequestToPlatformConverter.toJetpackSetSchemaResponse(
+ result.getResultValue());
+ future.set(jetpackResponse);
+ } else {
+ handleFailedPlatformResult(result, future);
+ }
+ });
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<GetSchemaResponse> getSchema() {
+ ResolvableFuture<GetSchemaResponse> future = ResolvableFuture.create();
+ mPlatformSession.getSchema(
+ mExecutor,
+ result -> {
+ if (result.isSuccess()) {
+ android.app.appsearch.GetSchemaResponse platformGetResponse =
+ result.getResultValue();
+ GetSchemaResponse.Builder jetpackResponseBuilder =
+ new GetSchemaResponse.Builder();
+ for (android.app.appsearch.AppSearchSchema platformSchema :
+ platformGetResponse.getSchemas()) {
+ jetpackResponseBuilder.addSchema(
+ SchemaToPlatformConverter.toJetpackSchema(platformSchema));
+ }
+ jetpackResponseBuilder.setVersion(platformGetResponse.getVersion());
+ future.set(jetpackResponseBuilder.build());
+ } else {
+ handleFailedPlatformResult(result, future);
+ }
+ });
+ return future;
+ }
+
+ @NonNull
+ @Override
+ public ListenableFuture<Set<String>> getNamespaces() {
+ ResolvableFuture<Set<String>> future = ResolvableFuture.create();
+ mPlatformSession.getNamespaces(
+ mExecutor,
+ result -> {
+ if (result.isSuccess()) {
+ future.set(result.getResultValue());
+ } else {
+ handleFailedPlatformResult(result, future);
+ }
+ });
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<AppSearchBatchResult<String, Void>> put(
+ @NonNull PutDocumentsRequest request) {
+ Preconditions.checkNotNull(request);
+ ResolvableFuture<AppSearchBatchResult<String, Void>> future = ResolvableFuture.create();
+ mPlatformSession.put(
+ RequestToPlatformConverter.toPlatformPutDocumentsRequest(request),
+ mExecutor,
+ BatchResultCallbackAdapter.forSameValueType(future));
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentId(
+ @NonNull GetByDocumentIdRequest request) {
+ Preconditions.checkNotNull(request);
+ ResolvableFuture<AppSearchBatchResult<String, GenericDocument>> future =
+ ResolvableFuture.create();
+ mPlatformSession.getByDocumentId(
+ RequestToPlatformConverter.toPlatformGetByDocumentIdRequest(request),
+ mExecutor,
+ new BatchResultCallbackAdapter<>(
+ future, GenericDocumentToPlatformConverter::toJetpackGenericDocument));
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public SearchResults search(
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec) {
+ Preconditions.checkNotNull(queryExpression);
+ Preconditions.checkNotNull(searchSpec);
+ android.app.appsearch.SearchResults platformSearchResults =
+ mPlatformSession.search(
+ queryExpression,
+ SearchSpecToPlatformConverter.toPlatformSearchSpec(searchSpec));
+ return new SearchResultsImpl(platformSearchResults, mExecutor);
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<Void> reportUsage(@NonNull ReportUsageRequest request) {
+ Preconditions.checkNotNull(request);
+ ResolvableFuture<Void> future = ResolvableFuture.create();
+ mPlatformSession.reportUsage(
+ RequestToPlatformConverter.toPlatformReportUsageRequest(request),
+ mExecutor,
+ result -> AppSearchResultToPlatformConverter.platformAppSearchResultToFuture(
+ result, future));
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<AppSearchBatchResult<String, Void>> remove(
+ @NonNull RemoveByDocumentIdRequest request) {
+ Preconditions.checkNotNull(request);
+ ResolvableFuture<AppSearchBatchResult<String, Void>> future = ResolvableFuture.create();
+ mPlatformSession.remove(
+ RequestToPlatformConverter.toPlatformRemoveByDocumentIdRequest(request),
+ mExecutor,
+ BatchResultCallbackAdapter.forSameValueType(future));
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<Void> remove(
+ @NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
+ Preconditions.checkNotNull(queryExpression);
+ Preconditions.checkNotNull(searchSpec);
+ ResolvableFuture<Void> future = ResolvableFuture.create();
+ mPlatformSession.remove(
+ queryExpression,
+ SearchSpecToPlatformConverter.toPlatformSearchSpec(searchSpec),
+ mExecutor,
+ result -> AppSearchResultToPlatformConverter.platformAppSearchResultToFuture(
+ result, future));
+ return future;
+ }
+
+ @Override
+ @NonNull
+ public ListenableFuture<StorageInfo> getStorageInfo() {
+ ResolvableFuture<StorageInfo> future = ResolvableFuture.create();
+ mPlatformSession.getStorageInfo(
+ mExecutor,
+ result -> {
+ if (result.isSuccess()) {
+ StorageInfo jetpackStorageInfo =
+ ResponseToPlatformConverter.toJetpackStorageInfo(
+ result.getResultValue());
+ future.set(jetpackStorageInfo);
+ } else {
+ handleFailedPlatformResult(result, future);
+ }
+ });
+ return future;
+ }
+
+ @NonNull
+ @Override
+ public ListenableFuture<Void> requestFlush() {
+ ResolvableFuture<Void> future = ResolvableFuture.create();
+ // The data in platform will be flushed by scheduled task. This api won't do anything extra
+ // flush.
+ future.set(null);
+ return future;
+ }
+
+ @Override
+ public void close() {
+ mPlatformSession.close();
+ }
+
+ private void handleFailedPlatformResult(
+ @NonNull android.app.appsearch.AppSearchResult<?> platformResult,
+ @NonNull ResolvableFuture<?> future) {
+ future.setException(
+ new AppSearchException(
+ platformResult.getResultCode(), platformResult.getErrorMessage()));
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/AppSearchResultToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/AppSearchResultToPlatformConverter.java
new file mode 100644
index 0000000..1510626
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/AppSearchResultToPlatformConverter.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.app.AppSearchResult;
+import androidx.appsearch.exceptions.AppSearchException;
+import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.util.Preconditions;
+
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * Translates {@link androidx.appsearch.app.AppSearchResult} and
+ * {@link androidx.appsearch.app.AppSearchBatchResult} to platform versions.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class AppSearchResultToPlatformConverter {
+ private AppSearchResultToPlatformConverter() {}
+
+ /**
+ * Converts an {@link android.app.appsearch.AppSearchResult} into a jetpack
+ * {@link androidx.appsearch.app.AppSearchResult}.
+ */
+ @NonNull
+ public static <T> AppSearchResult<T> platformAppSearchResultToJetpack(
+ @NonNull android.app.appsearch.AppSearchResult<T> platformResult) {
+ Preconditions.checkNotNull(platformResult);
+ if (platformResult.isSuccess()) {
+ return AppSearchResult.newSuccessfulResult(platformResult.getResultValue());
+ }
+ return AppSearchResult.newFailedResult(
+ platformResult.getResultCode(), platformResult.getErrorMessage());
+ }
+
+ /**
+ * Uses the given {@link android.app.appsearch.AppSearchResult} to populate the given
+ * {@link ResolvableFuture}.
+ */
+ public static <T> void platformAppSearchResultToFuture(
+ @NonNull android.app.appsearch.AppSearchResult<T> platformResult,
+ @NonNull ResolvableFuture<T> future) {
+ Preconditions.checkNotNull(platformResult);
+ Preconditions.checkNotNull(future);
+ if (platformResult.isSuccess()) {
+ future.set(platformResult.getResultValue());
+ } else {
+ future.setException(
+ new AppSearchException(
+ platformResult.getResultCode(), platformResult.getErrorMessage()));
+ }
+ }
+
+ /**
+ * Converts the given platform {@link android.app.appsearch.AppSearchBatchResult} to a Jetpack
+ * {@link AppSearchBatchResult}.
+ *
+ * <p>Each value is translated using the provided {@code valueMapper} function.
+ */
+ @NonNull
+ public static <K, PlatformValue, JetpackValue> AppSearchBatchResult<K, JetpackValue>
+ platformAppSearchBatchResultToJetpack(
+ @NonNull android.app.appsearch.AppSearchBatchResult<K, PlatformValue> platformResult,
+ @NonNull Function<PlatformValue, JetpackValue> valueMapper) {
+ Preconditions.checkNotNull(platformResult);
+ Preconditions.checkNotNull(valueMapper);
+ AppSearchBatchResult.Builder<K, JetpackValue> jetpackResult =
+ new AppSearchBatchResult.Builder<>();
+ for (Map.Entry<K, PlatformValue> success : platformResult.getSuccesses().entrySet()) {
+ JetpackValue jetpackValue = valueMapper.apply(success.getValue());
+ jetpackResult.setSuccess(success.getKey(), jetpackValue);
+ }
+ for (Map.Entry<K, android.app.appsearch.AppSearchResult<PlatformValue>> failure :
+ platformResult.getFailures().entrySet()) {
+ jetpackResult.setFailure(
+ failure.getKey(),
+ failure.getValue().getResultCode(),
+ failure.getValue().getErrorMessage());
+ }
+ return jetpackResult.build();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GenericDocumentToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GenericDocumentToPlatformConverter.java
new file mode 100644
index 0000000..3838191
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GenericDocumentToPlatformConverter.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.core.util.Preconditions;
+
+/**
+ * Translates between Platform and Jetpack versions of {@link GenericDocument}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class GenericDocumentToPlatformConverter {
+ /**
+ * Translates a jetpack {@link androidx.appsearch.app.GenericDocument} into a platform
+ * {@link android.app.appsearch.GenericDocument}.
+ */
+ @NonNull
+ public static android.app.appsearch.GenericDocument toPlatformGenericDocument(
+ @NonNull GenericDocument jetpackDocument) {
+ Preconditions.checkNotNull(jetpackDocument);
+ android.app.appsearch.GenericDocument.Builder<
+ android.app.appsearch.GenericDocument.Builder<?>> platformBuilder =
+ new android.app.appsearch.GenericDocument.Builder<>(
+ jetpackDocument.getNamespace(),
+ jetpackDocument.getId(),
+ jetpackDocument.getSchemaType());
+ platformBuilder
+ .setScore(jetpackDocument.getScore())
+ .setTtlMillis(jetpackDocument.getTtlMillis())
+ .setCreationTimestampMillis(jetpackDocument.getCreationTimestampMillis());
+ for (String propertyName : jetpackDocument.getPropertyNames()) {
+ Object property = jetpackDocument.getProperty(propertyName);
+ if (property instanceof String[]) {
+ platformBuilder.setPropertyString(propertyName, (String[]) property);
+ } else if (property instanceof long[]) {
+ platformBuilder.setPropertyLong(propertyName, (long[]) property);
+ } else if (property instanceof double[]) {
+ platformBuilder.setPropertyDouble(propertyName, (double[]) property);
+ } else if (property instanceof boolean[]) {
+ platformBuilder.setPropertyBoolean(propertyName, (boolean[]) property);
+ } else if (property instanceof byte[][]) {
+ platformBuilder.setPropertyBytes(propertyName, (byte[][]) property);
+ } else if (property instanceof GenericDocument[]) {
+ GenericDocument[] documentValues = (GenericDocument[]) property;
+ android.app.appsearch.GenericDocument[] platformSubDocuments =
+ new android.app.appsearch.GenericDocument[documentValues.length];
+ for (int j = 0; j < documentValues.length; j++) {
+ platformSubDocuments[j] = toPlatformGenericDocument(documentValues[j]);
+ }
+ platformBuilder.setPropertyDocument(propertyName, platformSubDocuments);
+ } else {
+ throw new IllegalStateException(
+ String.format("Property \"%s\" has unsupported value type %s", propertyName,
+ property.getClass().toString()));
+ }
+ }
+ return platformBuilder.build();
+ }
+
+ /**
+ * Translates a platform {@link android.app.appsearch.GenericDocument} into a jetpack
+ * {@link androidx.appsearch.app.GenericDocument}.
+ */
+ @NonNull
+ public static GenericDocument toJetpackGenericDocument(
+ @NonNull android.app.appsearch.GenericDocument platformDocument) {
+ Preconditions.checkNotNull(platformDocument);
+ GenericDocument.Builder<GenericDocument.Builder<?>> jetpackBuilder =
+ new GenericDocument.Builder<>(
+ platformDocument.getNamespace(),
+ platformDocument.getId(),
+ platformDocument.getSchemaType());
+ jetpackBuilder
+ .setScore(platformDocument.getScore())
+ .setTtlMillis(platformDocument.getTtlMillis())
+ .setCreationTimestampMillis(platformDocument.getCreationTimestampMillis());
+ for (String propertyName : platformDocument.getPropertyNames()) {
+ Object property = platformDocument.getProperty(propertyName);
+ if (property instanceof String[]) {
+ jetpackBuilder.setPropertyString(propertyName, (String[]) property);
+ } else if (property instanceof long[]) {
+ jetpackBuilder.setPropertyLong(propertyName, (long[]) property);
+ } else if (property instanceof double[]) {
+ jetpackBuilder.setPropertyDouble(propertyName, (double[]) property);
+ } else if (property instanceof boolean[]) {
+ jetpackBuilder.setPropertyBoolean(propertyName, (boolean[]) property);
+ } else if (property instanceof byte[][]) {
+ jetpackBuilder.setPropertyBytes(propertyName, (byte[][]) property);
+ } else if (property instanceof android.app.appsearch.GenericDocument[]) {
+ android.app.appsearch.GenericDocument[] documentValues =
+ (android.app.appsearch.GenericDocument[]) property;
+ GenericDocument[] jetpackSubDocuments = new GenericDocument[documentValues.length];
+ for (int j = 0; j < documentValues.length; j++) {
+ jetpackSubDocuments[j] = toJetpackGenericDocument(documentValues[j]);
+ }
+ jetpackBuilder.setPropertyDocument(propertyName, jetpackSubDocuments);
+ } else {
+ throw new IllegalStateException(
+ String.format("Property \"%s\" has unsupported value type %s", propertyName,
+ property.getClass().toString()));
+ }
+ }
+ return jetpackBuilder.build();
+ }
+
+ private GenericDocumentToPlatformConverter() {}
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/RequestToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/RequestToPlatformConverter.java
new file mode 100644
index 0000000..d2c35bd
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/RequestToPlatformConverter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.GetByDocumentIdRequest;
+import androidx.appsearch.app.PutDocumentsRequest;
+import androidx.appsearch.app.RemoveByDocumentIdRequest;
+import androidx.appsearch.app.ReportSystemUsageRequest;
+import androidx.appsearch.app.ReportUsageRequest;
+import androidx.core.util.Preconditions;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Translates between Platform and Jetpack versions of requests.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class RequestToPlatformConverter {
+ private RequestToPlatformConverter() {}
+
+ /**
+ * Translates a jetpack {@link PutDocumentsRequest} into a platform
+ * {@link android.app.appsearch.PutDocumentsRequest}.
+ */
+ @NonNull
+ public static android.app.appsearch.PutDocumentsRequest toPlatformPutDocumentsRequest(
+ @NonNull PutDocumentsRequest jetpackRequest) {
+ Preconditions.checkNotNull(jetpackRequest);
+ android.app.appsearch.PutDocumentsRequest.Builder platformBuilder =
+ new android.app.appsearch.PutDocumentsRequest.Builder();
+ for (GenericDocument jetpackDocument : jetpackRequest.getGenericDocuments()) {
+ platformBuilder.addGenericDocuments(
+ GenericDocumentToPlatformConverter.toPlatformGenericDocument(jetpackDocument));
+ }
+ return platformBuilder.build();
+ }
+
+ /**
+ * Translates a jetpack {@link GetByDocumentIdRequest} into a platform
+ * {@link android.app.appsearch.GetByDocumentIdRequest}.
+ */
+ @NonNull
+ public static android.app.appsearch.GetByDocumentIdRequest toPlatformGetByDocumentIdRequest(
+ @NonNull GetByDocumentIdRequest jetpackRequest) {
+ Preconditions.checkNotNull(jetpackRequest);
+ android.app.appsearch.GetByDocumentIdRequest.Builder platformBuilder =
+ new android.app.appsearch.GetByDocumentIdRequest.Builder(
+ jetpackRequest.getNamespace())
+ .addIds(jetpackRequest.getIds());
+ for (Map.Entry<String, List<String>> projection :
+ jetpackRequest.getProjectionsInternal().entrySet()) {
+ platformBuilder.addProjection(projection.getKey(), projection.getValue());
+ }
+ return platformBuilder.build();
+ }
+
+ /**
+ * Translates a jetpack {@link RemoveByDocumentIdRequest} into a platform
+ * {@link android.app.appsearch.RemoveByDocumentIdRequest}.
+ */
+ @NonNull
+ public static android.app.appsearch.RemoveByDocumentIdRequest
+ toPlatformRemoveByDocumentIdRequest(
+ @NonNull RemoveByDocumentIdRequest jetpackRequest) {
+ Preconditions.checkNotNull(jetpackRequest);
+ return new android.app.appsearch.RemoveByDocumentIdRequest.Builder(
+ jetpackRequest.getNamespace())
+ .addIds(jetpackRequest.getIds())
+ .build();
+ }
+
+ /**
+ * Translates a jetpack {@link androidx.appsearch.app.ReportUsageRequest} into a platform
+ * {@link android.app.appsearch.ReportUsageRequest}.
+ */
+ @NonNull
+ public static android.app.appsearch.ReportUsageRequest toPlatformReportUsageRequest(
+ @NonNull ReportUsageRequest jetpackRequest) {
+ Preconditions.checkNotNull(jetpackRequest);
+ return new android.app.appsearch.ReportUsageRequest.Builder(
+ jetpackRequest.getNamespace(), jetpackRequest.getDocumentId())
+ .setUsageTimestampMillis(jetpackRequest.getUsageTimestampMillis())
+ .build();
+ }
+
+ /**
+ * Translates a jetpack {@link androidx.appsearch.app.ReportSystemUsageRequest} into a platform
+ * {@link android.app.appsearch.ReportSystemUsageRequest}.
+ */
+ @NonNull
+ public static android.app.appsearch.ReportSystemUsageRequest toPlatformReportSystemUsageRequest(
+ @NonNull ReportSystemUsageRequest jetpackRequest) {
+ Preconditions.checkNotNull(jetpackRequest);
+ return new android.app.appsearch.ReportSystemUsageRequest.Builder(
+ jetpackRequest.getPackageName(),
+ jetpackRequest.getDatabaseName(),
+ jetpackRequest.getNamespace(),
+ jetpackRequest.getDocumentId())
+ .setUsageTimestampMillis(jetpackRequest.getUsageTimestampMillis())
+ .build();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/ResponseToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/ResponseToPlatformConverter.java
new file mode 100644
index 0000000..e6f1218
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/ResponseToPlatformConverter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.StorageInfo;
+import androidx.core.util.Preconditions;
+
+/**
+ * Translates between Platform and Jetpack versions of responses.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class ResponseToPlatformConverter {
+ private ResponseToPlatformConverter() {}
+
+ /**
+ * Translates a platform {@link android.app.appsearch.StorageInfo} into a jetpack
+ * {@link StorageInfo}.
+ */
+ @NonNull
+ public static StorageInfo toJetpackStorageInfo(
+ @NonNull android.app.appsearch.StorageInfo platformStorageInfo) {
+ Preconditions.checkNotNull(platformStorageInfo);
+ return new StorageInfo.Builder()
+ .setAliveNamespacesCount(platformStorageInfo.getAliveNamespacesCount())
+ .setAliveDocumentsCount(platformStorageInfo.getAliveDocumentsCount())
+ .setSizeBytes(platformStorageInfo.getSizeBytes())
+ .build();
+
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java
new file mode 100644
index 0000000..d33c3f9
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.core.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Translates a jetpack {@link androidx.appsearch.app.AppSearchSchema} into a platform
+ * {@link android.app.appsearch.AppSearchSchema}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class SchemaToPlatformConverter {
+ private SchemaToPlatformConverter() {}
+
+ /**
+ * Translates a jetpack {@link androidx.appsearch.app.AppSearchSchema} into a platform
+ * {@link android.app.appsearch.AppSearchSchema}.
+ */
+ @NonNull
+ public static android.app.appsearch.AppSearchSchema toPlatformSchema(
+ @NonNull AppSearchSchema jetpackSchema) {
+ Preconditions.checkNotNull(jetpackSchema);
+ android.app.appsearch.AppSearchSchema.Builder platformBuilder =
+ new android.app.appsearch.AppSearchSchema.Builder(jetpackSchema.getSchemaType());
+ List<AppSearchSchema.PropertyConfig> properties = jetpackSchema.getProperties();
+ for (int i = 0; i < properties.size(); i++) {
+ android.app.appsearch.AppSearchSchema.PropertyConfig platformProperty =
+ toPlatformProperty(properties.get(i));
+ platformBuilder.addProperty(platformProperty);
+ }
+ return platformBuilder.build();
+ }
+
+ /**
+ * Translates a platform {@link android.app.appsearch.AppSearchSchema} to a jetpack
+ * {@link androidx.appsearch.app.AppSearchSchema}.
+ */
+ @NonNull
+ public static AppSearchSchema toJetpackSchema(
+ @NonNull android.app.appsearch.AppSearchSchema platformSchema) {
+ Preconditions.checkNotNull(platformSchema);
+ AppSearchSchema.Builder jetpackBuilder =
+ new AppSearchSchema.Builder(platformSchema.getSchemaType());
+ List<android.app.appsearch.AppSearchSchema.PropertyConfig> properties =
+ platformSchema.getProperties();
+ for (int i = 0; i < properties.size(); i++) {
+ AppSearchSchema.PropertyConfig jetpackProperty = toJetpackProperty(properties.get(i));
+ jetpackBuilder.addProperty(jetpackProperty);
+ }
+ return jetpackBuilder.build();
+ }
+
+ @NonNull
+ private static android.app.appsearch.AppSearchSchema.PropertyConfig toPlatformProperty(
+ @NonNull AppSearchSchema.PropertyConfig jetpackProperty) {
+ Preconditions.checkNotNull(jetpackProperty);
+ if (jetpackProperty instanceof AppSearchSchema.StringPropertyConfig) {
+ AppSearchSchema.StringPropertyConfig stringProperty =
+ (AppSearchSchema.StringPropertyConfig) jetpackProperty;
+ return new android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder(
+ stringProperty.getName())
+ .setCardinality(stringProperty.getCardinality())
+ .setIndexingType(stringProperty.getIndexingType())
+ .setTokenizerType(stringProperty.getTokenizerType())
+ .build();
+ } else if (jetpackProperty instanceof AppSearchSchema.LongPropertyConfig) {
+ return new android.app.appsearch.AppSearchSchema.LongPropertyConfig.Builder(
+ jetpackProperty.getName())
+ .setCardinality(jetpackProperty.getCardinality())
+ .build();
+ } else if (jetpackProperty instanceof AppSearchSchema.DoublePropertyConfig) {
+ return new android.app.appsearch.AppSearchSchema.DoublePropertyConfig.Builder(
+ jetpackProperty.getName())
+ .setCardinality(jetpackProperty.getCardinality())
+ .build();
+ } else if (jetpackProperty instanceof AppSearchSchema.BooleanPropertyConfig) {
+ return new android.app.appsearch.AppSearchSchema.BooleanPropertyConfig.Builder(
+ jetpackProperty.getName())
+ .setCardinality(jetpackProperty.getCardinality())
+ .build();
+ } else if (jetpackProperty instanceof AppSearchSchema.BytesPropertyConfig) {
+ return new android.app.appsearch.AppSearchSchema.BytesPropertyConfig.Builder(
+ jetpackProperty.getName())
+ .setCardinality(jetpackProperty.getCardinality())
+ .build();
+ } else if (jetpackProperty instanceof AppSearchSchema.DocumentPropertyConfig) {
+ AppSearchSchema.DocumentPropertyConfig documentProperty =
+ (AppSearchSchema.DocumentPropertyConfig) jetpackProperty;
+ return new android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder(
+ documentProperty.getName(), documentProperty.getSchemaType())
+ .setCardinality(documentProperty.getCardinality())
+ .setShouldIndexNestedProperties(documentProperty.shouldIndexNestedProperties())
+ .build();
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid dataType: " + jetpackProperty.getDataType());
+ }
+ }
+
+ @NonNull
+ private static AppSearchSchema.PropertyConfig toJetpackProperty(
+ @NonNull android.app.appsearch.AppSearchSchema.PropertyConfig platformProperty) {
+ Preconditions.checkNotNull(platformProperty);
+ if (platformProperty
+ instanceof android.app.appsearch.AppSearchSchema.StringPropertyConfig) {
+ android.app.appsearch.AppSearchSchema.StringPropertyConfig stringProperty =
+ (android.app.appsearch.AppSearchSchema.StringPropertyConfig) platformProperty;
+ return new AppSearchSchema.StringPropertyConfig.Builder(stringProperty.getName())
+ .setCardinality(stringProperty.getCardinality())
+ .setIndexingType(stringProperty.getIndexingType())
+ .setTokenizerType(stringProperty.getTokenizerType())
+ .build();
+ } else if (platformProperty
+ instanceof android.app.appsearch.AppSearchSchema.LongPropertyConfig) {
+ return new AppSearchSchema.LongPropertyConfig.Builder(platformProperty.getName())
+ .setCardinality(platformProperty.getCardinality())
+ .build();
+ } else if (platformProperty
+ instanceof android.app.appsearch.AppSearchSchema.DoublePropertyConfig) {
+ return new AppSearchSchema.DoublePropertyConfig.Builder(platformProperty.getName())
+ .setCardinality(platformProperty.getCardinality())
+ .build();
+ } else if (platformProperty
+ instanceof android.app.appsearch.AppSearchSchema.BooleanPropertyConfig) {
+ return new AppSearchSchema.BooleanPropertyConfig.Builder(platformProperty.getName())
+ .setCardinality(platformProperty.getCardinality())
+ .build();
+ } else if (platformProperty
+ instanceof android.app.appsearch.AppSearchSchema.BytesPropertyConfig) {
+ return new AppSearchSchema.BytesPropertyConfig.Builder(platformProperty.getName())
+ .setCardinality(platformProperty.getCardinality())
+ .build();
+ } else if (platformProperty
+ instanceof android.app.appsearch.AppSearchSchema.DocumentPropertyConfig) {
+ android.app.appsearch.AppSearchSchema.DocumentPropertyConfig documentProperty =
+ (android.app.appsearch.AppSearchSchema.DocumentPropertyConfig) platformProperty;
+ return new AppSearchSchema.DocumentPropertyConfig.Builder(
+ documentProperty.getName(),
+ documentProperty.getSchemaType())
+ .setCardinality(documentProperty.getCardinality())
+ .setShouldIndexNestedProperties(documentProperty.shouldIndexNestedProperties())
+ .build();
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid property type " + platformProperty.getClass()
+ + ": " + platformProperty);
+ }
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchContextToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchContextToPlatformConverter.java
new file mode 100644
index 0000000..49b0564
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchContextToPlatformConverter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.app.appsearch.AppSearchManager;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.platformstorage.PlatformStorage;
+import androidx.core.util.Preconditions;
+
+/**
+ * Translates a Jetpack {@link androidx.appsearch.platformstorage.PlatformStorage.SearchContext}
+ * into a platform {@link android.app.appsearch.AppSearchManager.SearchContext}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class SearchContextToPlatformConverter {
+ private SearchContextToPlatformConverter() {}
+
+ /**
+ * Translates a Jetpack {@link androidx.appsearch.platformstorage.PlatformStorage.SearchContext}
+ * into a platform {@link android.app.appsearch.AppSearchManager.SearchContext}.
+ */
+ @NonNull
+ public static AppSearchManager.SearchContext toPlatformSearchContext(
+ @NonNull PlatformStorage.SearchContext jetpackSearchContext) {
+ Preconditions.checkNotNull(jetpackSearchContext);
+ return new AppSearchManager.SearchContext.Builder(jetpackSearchContext.getDatabaseName())
+ .build();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java
new file mode 100644
index 0000000..fc7b70e
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.SearchResult;
+import androidx.core.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Translates between Platform and Jetpack versions of {@link SearchResult}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public class SearchResultToPlatformConverter {
+ private SearchResultToPlatformConverter() {}
+
+ /** Translates from Platform to Jetpack versions of {@link SearchResult}. */
+ @NonNull
+ public static SearchResult toJetpackSearchResult(
+ @NonNull android.app.appsearch.SearchResult platformResult) {
+ Preconditions.checkNotNull(platformResult);
+ GenericDocument document = GenericDocumentToPlatformConverter.toJetpackGenericDocument(
+ platformResult.getGenericDocument());
+ SearchResult.Builder builder = new SearchResult.Builder(
+ platformResult.getPackageName(), platformResult.getDatabaseName())
+ .setGenericDocument(document)
+ .setRankingSignal(platformResult.getRankingSignal());
+ List<android.app.appsearch.SearchResult.MatchInfo> platformMatches =
+ platformResult.getMatchInfos();
+ for (int i = 0; i < platformMatches.size(); i++) {
+ SearchResult.MatchInfo jetpackMatchInfo = toJetpackMatchInfo(platformMatches.get(i));
+ builder.addMatchInfo(jetpackMatchInfo);
+ }
+ return builder.build();
+ }
+
+ @NonNull
+ private static SearchResult.MatchInfo toJetpackMatchInfo(
+ @NonNull android.app.appsearch.SearchResult.MatchInfo platformMatchInfo) {
+ Preconditions.checkNotNull(platformMatchInfo);
+ return new SearchResult.MatchInfo.Builder(platformMatchInfo.getPropertyPath())
+ .setExactMatchRange(
+ new SearchResult.MatchRange(
+ platformMatchInfo.getExactMatchRange().getStart(),
+ platformMatchInfo.getExactMatchRange().getEnd()))
+ .setSnippetRange(
+ new SearchResult.MatchRange(
+ platformMatchInfo.getSnippetRange().getStart(),
+ platformMatchInfo.getSnippetRange().getEnd()))
+ .build();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java
new file mode 100644
index 0000000..eadc109
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.SearchSpec;
+import androidx.core.util.Preconditions;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Translates between Platform and Jetpack versions of {@link SearchSpec}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class SearchSpecToPlatformConverter {
+ private SearchSpecToPlatformConverter() {
+ }
+
+ /** Translates from Jetpack to Platform version of {@link SearchSpec}. */
+ @NonNull
+ public static android.app.appsearch.SearchSpec toPlatformSearchSpec(
+ @NonNull SearchSpec jetpackSearchSpec) {
+ Preconditions.checkNotNull(jetpackSearchSpec);
+ android.app.appsearch.SearchSpec.Builder platformBuilder =
+ new android.app.appsearch.SearchSpec.Builder();
+ platformBuilder
+ .setTermMatch(jetpackSearchSpec.getTermMatch())
+ .addFilterSchemas(jetpackSearchSpec.getFilterSchemas())
+ .addFilterNamespaces(jetpackSearchSpec.getFilterNamespaces())
+ .addFilterPackageNames(jetpackSearchSpec.getFilterPackageNames())
+ .setResultCountPerPage(jetpackSearchSpec.getResultCountPerPage())
+ .setRankingStrategy(jetpackSearchSpec.getRankingStrategy())
+ .setOrder(jetpackSearchSpec.getOrder())
+ .setSnippetCount(jetpackSearchSpec.getSnippetCount())
+ .setSnippetCountPerProperty(jetpackSearchSpec.getSnippetCountPerProperty())
+ .setMaxSnippetSize(jetpackSearchSpec.getMaxSnippetSize());
+ if (jetpackSearchSpec.getResultGroupingTypeFlags() != 0) {
+ platformBuilder.setResultGrouping(
+ jetpackSearchSpec.getResultGroupingTypeFlags(),
+ jetpackSearchSpec.getResultGroupingLimit());
+ }
+ for (Map.Entry<String, List<String>> projection :
+ jetpackSearchSpec.getProjections().entrySet()) {
+ platformBuilder.addProjection(projection.getKey(), projection.getValue());
+ }
+ return platformBuilder.build();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
new file mode 100644
index 0000000..ca52112
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.platformstorage.converter;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.Migrator;
+import androidx.appsearch.app.PackageIdentifier;
+import androidx.appsearch.app.SetSchemaRequest;
+import androidx.appsearch.app.SetSchemaResponse;
+import androidx.core.util.Preconditions;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Translates between Platform and Jetpack versions of {@link SetSchemaRequest}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class SetSchemaRequestToPlatformConverter {
+ private SetSchemaRequestToPlatformConverter() {}
+
+ /**
+ * Translates a jetpack {@link SetSchemaRequest} into a platform
+ * {@link android.app.appsearch.SetSchemaRequest}.
+ */
+ @NonNull
+ public static android.app.appsearch.SetSchemaRequest toPlatformSetSchemaRequest(
+ @NonNull SetSchemaRequest jetpackRequest) {
+ Preconditions.checkNotNull(jetpackRequest);
+ android.app.appsearch.SetSchemaRequest.Builder platformBuilder =
+ new android.app.appsearch.SetSchemaRequest.Builder();
+ for (AppSearchSchema jetpackSchema : jetpackRequest.getSchemas()) {
+ platformBuilder.addSchemas(SchemaToPlatformConverter.toPlatformSchema(jetpackSchema));
+ }
+ for (String schemaNotDisplayedBySystem : jetpackRequest.getSchemasNotDisplayedBySystem()) {
+ platformBuilder.setSchemaTypeDisplayedBySystem(
+ schemaNotDisplayedBySystem, /*displayed=*/ false);
+ }
+ for (Map.Entry<String, Set<PackageIdentifier>> jetpackSchemaVisibleToPackage :
+ jetpackRequest.getSchemasVisibleToPackagesInternal().entrySet()) {
+ for (PackageIdentifier jetpackPackageIdentifier :
+ jetpackSchemaVisibleToPackage.getValue()) {
+ platformBuilder.setSchemaTypeVisibilityForPackage(
+ jetpackSchemaVisibleToPackage.getKey(),
+ /*visible=*/ true,
+ new android.app.appsearch.PackageIdentifier(
+ jetpackPackageIdentifier.getPackageName(),
+ jetpackPackageIdentifier.getSha256Certificate()));
+ }
+ }
+ for (Map.Entry<String, Migrator> entry : jetpackRequest.getMigrators().entrySet()) {
+ Migrator jetpackMigrator = entry.getValue();
+ android.app.appsearch.Migrator platformMigrator = new android.app.appsearch.Migrator() {
+ @Override
+ public boolean shouldMigrate(int currentVersion, int finalVersion) {
+ return jetpackMigrator.shouldMigrate(currentVersion, finalVersion);
+ }
+
+ @NonNull
+ @Override
+ public android.app.appsearch.GenericDocument onUpgrade(
+ int currentVersion,
+ int finalVersion,
+ @NonNull android.app.appsearch.GenericDocument inPlatformDocument) {
+ GenericDocument inJetpackDocument =
+ GenericDocumentToPlatformConverter.toJetpackGenericDocument(
+ inPlatformDocument);
+ GenericDocument outJetpackDocument = jetpackMigrator.onUpgrade(
+ currentVersion, finalVersion, inJetpackDocument);
+ if (inJetpackDocument.equals(outJetpackDocument)) {
+ return inPlatformDocument; // Same object; no conversion occurred.
+ }
+ return GenericDocumentToPlatformConverter.toPlatformGenericDocument(
+ outJetpackDocument);
+ }
+
+ @NonNull
+ @Override
+ public android.app.appsearch.GenericDocument onDowngrade(
+ int currentVersion,
+ int finalVersion,
+ @NonNull android.app.appsearch.GenericDocument inPlatformDocument) {
+ GenericDocument inJetpackDocument =
+ GenericDocumentToPlatformConverter.toJetpackGenericDocument(
+ inPlatformDocument);
+ GenericDocument outJetpackDocument = jetpackMigrator.onDowngrade(
+ currentVersion, finalVersion, inJetpackDocument);
+ if (inJetpackDocument.equals(outJetpackDocument)) {
+ return inPlatformDocument; // Same object; no conversion occurred.
+ }
+ return GenericDocumentToPlatformConverter.toPlatformGenericDocument(
+ outJetpackDocument);
+ }
+ };
+ platformBuilder.setMigrator(entry.getKey(), platformMigrator);
+ }
+ return platformBuilder
+ .setForceOverride(jetpackRequest.isForceOverride())
+ .setVersion(jetpackRequest.getVersion())
+ .build();
+ }
+
+ /**
+ * Translates a platform {@link android.app.appsearch.SetSchemaResponse} into a jetpack
+ * {@link SetSchemaResponse}.
+ */
+ @NonNull
+ public static SetSchemaResponse toJetpackSetSchemaResponse(
+ @NonNull android.app.appsearch.SetSchemaResponse platformResponse) {
+ Preconditions.checkNotNull(platformResponse);
+ SetSchemaResponse.Builder jetpackBuilder = new SetSchemaResponse.Builder()
+ .addDeletedTypes(platformResponse.getDeletedTypes())
+ .addIncompatibleTypes(platformResponse.getIncompatibleTypes())
+ .addMigratedTypes(platformResponse.getMigratedTypes());
+ for (android.app.appsearch.SetSchemaResponse.MigrationFailure migrationFailure :
+ platformResponse.getMigrationFailures()) {
+ jetpackBuilder.addMigrationFailure(new SetSchemaResponse.MigrationFailure(
+ migrationFailure.getNamespace(),
+ migrationFailure.getDocumentId(),
+ migrationFailure.getSchemaType(),
+ AppSearchResultToPlatformConverter.platformAppSearchResultToJetpack(
+ migrationFailure.getAppSearchResult())));
+ }
+ return jetpackBuilder.build();
+ }
+}
diff --git a/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/util/BatchResultCallbackAdapter.java b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/util/BatchResultCallbackAdapter.java
new file mode 100644
index 0000000..226e274
--- /dev/null
+++ b/appsearch/platform-storage/src/main/java/androidx/appsearch/platformstorage/util/BatchResultCallbackAdapter.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appsearch.platformstorage.util;
+
+import android.app.appsearch.BatchResultCallback;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.AppSearchBatchResult;
+import androidx.appsearch.platformstorage.converter.AppSearchResultToPlatformConverter;
+import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.util.Preconditions;
+
+import java.util.function.Function;
+
+/**
+ * An implementation of the framework API's {@link android.app.appsearch.BatchResultCallback} which
+ * return the result as a {@link com.google.common.util.concurrent.ListenableFuture}.
+ *
+ * @param <K> The type of key in the batch result (both Framework and Jetpack)
+ * @param <PlatformValue> The type of value in the Framework's
+ * {@link android.app.appsearch.AppSearchBatchResult}.
+ * @param <JetpackValue> The type of value in Jetpack's {@link AppSearchBatchResult}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(Build.VERSION_CODES.S)
+public final class BatchResultCallbackAdapter<K, PlatformValue, JetpackValue>
+ implements BatchResultCallback<K, PlatformValue> {
+ private final ResolvableFuture<AppSearchBatchResult<K, JetpackValue>> mFuture;
+ private final Function<PlatformValue, JetpackValue> mValueMapper;
+
+ public BatchResultCallbackAdapter(
+ @NonNull ResolvableFuture<AppSearchBatchResult<K, JetpackValue>> future,
+ @NonNull Function<PlatformValue, JetpackValue> valueMapper) {
+ mFuture = Preconditions.checkNotNull(future);
+ mValueMapper = Preconditions.checkNotNull(valueMapper);
+ }
+
+ @Override
+ public void onResult(
+ @NonNull android.app.appsearch.AppSearchBatchResult<K, PlatformValue> platformResult) {
+ AppSearchBatchResult<K, JetpackValue> jetpackResult =
+ AppSearchResultToPlatformConverter.platformAppSearchBatchResultToJetpack(
+ platformResult, mValueMapper);
+ mFuture.set(jetpackResult);
+ }
+
+ @Override
+ public void onSystemError(@Nullable Throwable t) {
+ mFuture.setException(t);
+ }
+
+ /**
+ * Returns a {@link androidx.appsearch.platformstorage.util.BatchResultCallbackAdapter} where
+ * the Platform value is identical to the Jetpack value, needing no transformation.
+ */
+ @NonNull
+ public static <K, V> BatchResultCallbackAdapter<K, V, V> forSameValueType(
+ @NonNull ResolvableFuture<AppSearchBatchResult<K, V>> future) {
+ return new BatchResultCallbackAdapter<>(future, Function.identity());
+ }
+}
diff --git a/benchmark/benchmark-common/api/current.txt b/benchmark/benchmark-common/api/current.txt
index 1874053..7410e3f 100644
--- a/benchmark/benchmark-common/api/current.txt
+++ b/benchmark/benchmark-common/api/current.txt
@@ -29,11 +29,27 @@
public static final class BenchmarkState.Companion {
}
+ public final class ConfigurationErrorKt {
+ }
+
public final class MetricNameUtilsKt {
}
public final class ProfilerKt {
}
+ public final class UserspaceTracingKt {
+ }
+
+}
+
+package androidx.benchmark.perfetto {
+
+ public final class PerfettoConfigKt {
+ }
+
+ public final class UiStateKt {
+ }
+
}
diff --git a/benchmark/benchmark-common/api/public_plus_experimental_current.txt b/benchmark/benchmark-common/api/public_plus_experimental_current.txt
index 39d1008..db914e9 100644
--- a/benchmark/benchmark-common/api/public_plus_experimental_current.txt
+++ b/benchmark/benchmark-common/api/public_plus_experimental_current.txt
@@ -34,11 +34,27 @@
@kotlin.Experimental @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget) public static @interface BenchmarkState.Companion.ExperimentalExternalReport {
}
+ public final class ConfigurationErrorKt {
+ }
+
public final class MetricNameUtilsKt {
}
public final class ProfilerKt {
}
+ public final class UserspaceTracingKt {
+ }
+
+}
+
+package androidx.benchmark.perfetto {
+
+ public final class PerfettoConfigKt {
+ }
+
+ public final class UiStateKt {
+ }
+
}
diff --git a/benchmark/benchmark-common/api/restricted_current.txt b/benchmark/benchmark-common/api/restricted_current.txt
index 39bcc5a..ac28e4c 100644
--- a/benchmark/benchmark-common/api/restricted_current.txt
+++ b/benchmark/benchmark-common/api/restricted_current.txt
@@ -31,11 +31,27 @@
public static final class BenchmarkState.Companion {
}
+ public final class ConfigurationErrorKt {
+ }
+
public final class MetricNameUtilsKt {
}
public final class ProfilerKt {
}
+ public final class UserspaceTracingKt {
+ }
+
+}
+
+package androidx.benchmark.perfetto {
+
+ public final class PerfettoConfigKt {
+ }
+
+ public final class UiStateKt {
+ }
+
}
diff --git a/benchmark/benchmark-common/build.gradle b/benchmark/benchmark-common/build.gradle
index 6d47166..97d492f 100644
--- a/benchmark/benchmark-common/build.gradle
+++ b/benchmark/benchmark-common/build.gradle
@@ -16,12 +16,47 @@
import androidx.build.LibraryGroups
import androidx.build.Publish
+import androidx.build.SupportConfigKt
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("AndroidXPlugin")
id("com.android.library")
id("kotlin-android")
+ id("com.squareup.wire")
+}
+
+android {
+ sourceSets {
+ main.assets.srcDirs += new File(
+ SupportConfigKt.getPrebuiltsRoot(project),
+ "androidx/traceprocessor/perfetto"
+ )
+ main.assets.srcDirs += new File(
+ SupportConfigKt.getPrebuiltsRoot(project),
+ "androidx/traceprocessor/traced"
+ )
+ main.assets.srcDirs += new File(
+ SupportConfigKt.getPrebuiltsRoot(project),
+ "androidx/traceprocessor/traced_probes"
+ )
+ androidTest.assets.srcDirs += new File(
+ SupportConfigKt.getPrebuiltsRoot(project),
+ "androidx/traceprocessor/testdata"
+ )
+ }
+}
+
+wire {
+ kotlin {}
+
+ // prune unused config components which have deprecated fields
+ prune 'perfetto.protos.TraceConfig.IncidentReportConfig'
+ prune 'perfetto.protos.ProcessStatsConfig.Quirks'
+
+ sourcePath {
+ srcDir 'src/main/proto'
+ }
}
dependencies {
@@ -30,6 +65,7 @@
api("androidx.annotation:annotation-experimental:1.0.0")
implementation("androidx.tracing:tracing-ktx:1.0.0")
implementation(libs.testMonitor)
+ implementation(libs.wireRuntime)
androidTestImplementation(libs.testRules)
androidTestImplementation(libs.testExtJunit)
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ConfigurationErrorTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ConfigurationErrorTest.kt
new file mode 100644
index 0000000..7342c236
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ConfigurationErrorTest.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertNotNull
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+public class ConfigurationErrorTest {
+ @Test
+ public fun constructor_valid() {
+ ConfigurationError(
+ id = "ID",
+ summary = "summary",
+ message = "message"
+ )
+ }
+
+ @Test
+ public fun constructor_throw() {
+ assertFailsWith<IllegalArgumentException> {
+ ConfigurationError(
+ id = "idCanNotHaveLowercase", // invalid, IDs always uppercase
+ summary = "summary",
+ message = "message"
+ )
+ }
+
+ assertFailsWith<IllegalArgumentException> {
+ ConfigurationError(
+ id = "i_d", // invalid, IDs can't have underscores
+ summary = "summary",
+ message = "message"
+ )
+ }
+ assertFailsWith<IllegalArgumentException> {
+ ConfigurationError(
+ id = "ID",
+ summary = "summary\nsummary", // invalid, summary is single line
+ message = "message"
+ )
+ }
+ }
+
+ @Test
+ public fun checkAndGetSuppressionState_empty() {
+ // no throw or suppressed error
+ assertNull(listOf<ConfigurationError>().checkAndGetSuppressionState(setOf()))
+ }
+
+ @Test
+ public fun checkAndGetSuppressionState_suppressed() {
+ // two suppressed errors
+ val suppression = listOf(
+ ConfigurationError(
+ id = "ID1",
+ summary = "summary1",
+ message = "message1"
+ ),
+ ConfigurationError(
+ id = "ID2",
+ summary = "summary2",
+ message = "message2"
+ )
+ ).checkAndGetSuppressionState(setOf("ID1", "ID2"))
+
+ assertNotNull(suppression)
+ assertEquals("ID1_ID2_", suppression.prefix)
+ assertEquals(
+ """
+ |WARNING: summary1
+ | message1
+
+ |WARNING: summary2
+ | message2
+
+ """.trimMargin(),
+ suppression.warningMessage
+ )
+ }
+
+ @Test
+ public fun checkAndGetSuppressionState_unsuppressed() {
+ // one unsuppressed error, so throw
+ val exception = assertFailsWith<AssertionError> {
+ listOf(
+ ConfigurationError(
+ id = "ID1",
+ summary = "summary1",
+ message = "message1"
+ ),
+ ConfigurationError(
+ id = "ID2",
+ summary = "summary2",
+ message = "message2"
+ )
+ ).checkAndGetSuppressionState(setOf("ID1"))
+ }
+
+ val message = exception.message!!
+ assertTrue(message.contains("ERRORS (not suppressed): ID2"))
+ assertTrue(message.contains("WARNINGS (suppressed): ID1"))
+ assertTrue(
+ message.contains(
+ """
+ |
+ |ERROR: summary2
+ | message2
+ |
+ """.trimMargin()
+ )
+ )
+ // suppression warning should contain *both* errors to be suppressed
+ assertTrue(
+ message.contains(
+ """testInstrumentationRunnerArguments""" +
+ """["androidx.benchmark.suppressErrors"] = "ID1,ID2""""
+ )
+ )
+ }
+}
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/Packages.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/Packages.kt
new file mode 100644
index 0000000..28585a6
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/Packages.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import androidx.test.platform.app.InstrumentationRegistry
+
+object Packages {
+ val TEST: String = InstrumentationRegistry.getInstrumentation()
+ .context
+ .packageName
+}
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellBehaviorTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellBehaviorTest.kt
new file mode 100644
index 0000000..5f4ccbc
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellBehaviorTest.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import android.os.Build
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+/**
+ * This class collects tests of strange shell behavior, for the purpose of documenting
+ * and validating how general the problems are.
+ */
+@MediumTest
+@SdkSuppress(minSdkVersion = 21)
+@RunWith(AndroidJUnit4::class)
+class ShellBehaviorTest {
+ @Test
+ fun pidof() {
+ // Should only be one process - this one!
+ val pidofString = Shell.executeCommand("pidof ${Packages.TEST}").trim()
+
+ when {
+ Build.VERSION.SDK_INT < 23 -> {
+ // command doesn't exist (and we don't try and read stderr here)
+ assertEquals("", pidofString)
+ }
+ Build.VERSION.SDK_INT == 23 -> {
+ // on API 23 specifically, pidof prints... all processes, ignoring the arg...
+ assertTrue(pidofString.contains(" "))
+ }
+ else -> {
+ assertNotNull(pidofString.toLongOrNull(), "Error, can't parse $pidofString")
+ }
+ }
+ }
+
+ @Test
+ fun psDashA() {
+ val output = Shell.executeCommand("ps -A").trim()
+ when {
+ Build.VERSION.SDK_INT <= 23 -> {
+ // doesn't correctly handle -A
+ assertTrue(
+ output.matches(Regex("USER.+PID.+PPID.+VSIZE.+RSS.+WCHAN.+PC.+NAME")),
+ "expected no processes from 'ps -A', saw $output"
+ )
+ }
+ Build.VERSION.SDK_INT in 24..25 -> {
+ // still doesn't support, but useful error at least
+ assertEquals("bad pid '-A'", output)
+ }
+ else -> {
+ // ps -A should work - expect several processes including this one
+ val processes = output.split("\n")
+ assertTrue(processes.size > 5)
+ assertTrue(processes.any { it.endsWith(Packages.TEST) })
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
index dce8b61..d02717f 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
@@ -18,7 +18,9 @@
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import org.junit.Assert
import org.junit.Assume.assumeTrue
import org.junit.Test
import org.junit.runner.RunWith
@@ -84,4 +86,133 @@
}
}
}
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun executeScript_trivial() {
+ Assert.assertEquals("foo\n", Shell.executeScript("echo foo"))
+ }
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun executeScriptWithStderr_trivial() {
+ Assert.assertEquals(Shell.Output("foo\n", ""), Shell.executeScriptWithStderr("echo foo"))
+ }
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun executeScriptWithStderr_invalidCommand() {
+ val shellOutput = Shell.executeScriptWithStderr("invalidCommand")
+
+ Assert.assertEquals("", shellOutput.stdout)
+
+ val stderr = shellOutput.stderr
+
+ // sample stderr observed in manual testing:
+ // API 23: "invalidCommand: not found"
+ // API 30: "invalidCommand: inaccessible or not found"
+ Assert.assertTrue(
+ "unexpected stderr \"$stderr\"",
+ stderr.contains("invalidCommand") && stderr.contains("not found")
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = 26) // xargs only available 26+
+ @Test
+ fun executeScript_pipe_xargs() {
+ // validate piping works with xargs
+ Assert.assertEquals("foo\n", Shell.executeScript("echo foo | xargs echo $1"))
+ }
+
+ @SdkSuppress(minSdkVersion = 29) // `$(</dev/stdin)` doesn't work before 29
+ @Test
+ fun executeScript_pipe_echo() {
+ // validate piping works
+ Assert.assertEquals("foo\n", Shell.executeScript("echo foo | echo $(</dev/stdin)"))
+ }
+
+ @SdkSuppress(minSdkVersion = 26) // xargs only available 26+
+ @Test
+ fun executeScript_stdinArg_xargs() {
+ // validate stdin to first command in script
+ Assert.assertEquals("foo\n", Shell.executeScript("xargs echo $1", stdin = "foo"))
+ }
+
+ @SdkSuppress(minSdkVersion = 29) // `$(</dev/stdin)` doesn't work before 29
+ @Test
+ fun executeScript_stdinArg_echo() {
+ // validate stdin to first command in script
+ Assert.assertEquals("foo\n", Shell.executeScript("echo $(</dev/stdin)", stdin = "foo"))
+ }
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun executeScript_multilineRedirect() {
+ Assert.assertEquals(
+ "foo\n",
+ Shell.executeScript(
+ """
+ echo foo > /data/local/tmp/foofile
+ cat /data/local/tmp/foofile
+ """.trimIndent()
+ )
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = 26) // xargs only available 26+
+ @Test
+ fun executeScript_multilineRedirectStdin_xargs() {
+ Assert.assertEquals(
+ "foo\n",
+ Shell.executeScript(
+ """
+ xargs echo $1 > /data/local/tmp/foofile
+ cat /data/local/tmp/foofile
+ """.trimIndent(),
+ stdin = "foo"
+ )
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = 29) // `$(</dev/stdin)` doesn't work before 29
+ @Test
+ fun executeScript_multilineRedirectStdin_echo() {
+ Assert.assertEquals(
+ "foo\n",
+ Shell.executeScript(
+ """
+ echo $(</dev/stdin) > /data/local/tmp/foofile
+ cat /data/local/tmp/foofile
+ """.trimIndent(),
+ stdin = "foo"
+ )
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun createRunnableExecutable_simpleScript() {
+ val path = Shell.createRunnableExecutable(
+ name = "myScript.sh",
+ inputStream = "echo foo".byteInputStream()
+ )
+ try {
+ Assert.assertEquals(
+ "foo\n",
+ Shell.executeCommand(path)
+ )
+ } finally {
+ Shell.executeCommand("rm $path")
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun isPackageAlive() {
+ // this package is certainly alive...
+ assertNotNull(Shell.isPackageAlive(Packages.TEST))
+
+ // this made up one shouldn't be
+ assertNotNull(Shell.isPackageAlive("com.notalive.package.notarealapp"))
+ }
}
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
new file mode 100644
index 0000000..73f5067
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import perfetto.protos.TracePacket
+import perfetto.protos.TrackDescriptor
+import perfetto.protos.TrackEvent
+import java.io.File
+import kotlin.test.assertNotNull
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class UserspaceTracingTest {
+ @Before
+ @After
+ fun setup() {
+ UserspaceTracing.commitToTrace() // reset
+ }
+
+ @Test
+ fun emptyTrace() {
+ val beforeTime = System.nanoTime()
+ UserspaceTracing.commitToTrace() // reset, and trigger first event in next trace
+ val afterTime = System.nanoTime()
+
+ val trace = UserspaceTracing.commitToTrace() // capture trace
+
+ assertEquals(1, trace.packet.size)
+ val packet = trace.packet.first()
+
+ assertTrue(packet.timestamp in beforeTime..afterTime)
+ assertEquals(
+ packet,
+ TracePacket(
+ timestamp = packet.timestamp,
+ timestamp_clock_id = 3,
+ incremental_state_cleared = true,
+ track_descriptor = TrackDescriptor(
+ uuid = packet.track_descriptor?.uuid,
+ name = "Macrobenchmark"
+ )
+ )
+ )
+ }
+
+ @Test
+ fun minimalTrace() {
+ val beforeTime = System.nanoTime()
+ userspaceTrace("test trace section") {}
+ val afterTime = System.nanoTime()
+
+ val trace = UserspaceTracing.commitToTrace()
+
+ assertEquals(3, trace.packet.size)
+
+ val descriptor = trace.packet.first().track_descriptor
+ assertNotNull(descriptor) // verify track
+
+ trace.packet[1].apply {
+ assert(timestamp in beforeTime..afterTime)
+ assertEquals(
+ TracePacket(
+ timestamp = timestamp,
+ timestamp_clock_id = 3,
+ trusted_packet_sequence_id = trusted_packet_sequence_id,
+ track_event = TrackEvent(
+ type = TrackEvent.Type.TYPE_SLICE_BEGIN,
+ track_uuid = descriptor.uuid,
+ categories = listOf("benchmark"),
+ name = "test trace section"
+ )
+ ),
+ this
+ )
+ }
+ trace.packet[2].apply {
+ assert(timestamp in beforeTime..afterTime)
+ assertEquals(
+ TracePacket(
+ timestamp = timestamp,
+ timestamp_clock_id = 3,
+ trusted_packet_sequence_id = trusted_packet_sequence_id,
+ track_event = TrackEvent(
+ type = TrackEvent.Type.TYPE_SLICE_END,
+ track_uuid = descriptor.uuid,
+ )
+ ),
+ this
+ )
+ }
+ }
+}
+
+@Suppress("SameParameterValue")
+internal fun createTempFileFromAsset(prefix: String, suffix: String): File {
+ val file = File.createTempFile(prefix, suffix, Outputs.dirUsableByAppAndShell)
+ InstrumentationRegistry
+ .getInstrumentation()
+ .context
+ .assets
+ .open(prefix + suffix)
+ .copyTo(file.outputStream())
+ return file
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/AtraceTagTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/AtraceTagTest.kt
new file mode 100644
index 0000000..88f8578
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/AtraceTagTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import androidx.benchmark.Shell
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import org.junit.Assume
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertContains
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = 21)
+@SmallTest
+class AtraceTagTest {
+ private val shellSessionRooted = Shell.isSessionRooted()
+
+ @Test
+ fun atraceListCategories_readable() {
+ val results = Shell.executeCommand("atrace --list_categories")
+ assertNotEquals("", results)
+ }
+
+ private fun getActualSupportedTags(): Set<String> {
+ val results = Shell.executeCommand("atrace --list_categories")
+
+ assertNotEquals("", results)
+ val actualSupportedTags = results
+ .split("\n")
+ .map {
+ println("captured $it")
+ it.trim().split(" ").first()
+ }
+ .filter { it.isNotBlank() }
+ .toSet()
+
+ // verify able to read stdout with guaranteed tag
+ assertContains(actualSupportedTags, "view")
+
+ return actualSupportedTags
+ }
+
+ @Test
+ fun atraceListCategories_unsupported() {
+ val actualSupportedTags = getActualSupportedTags()
+
+ val expectedUnsupportedTags = AtraceTag.unsupported(rooted = shellSessionRooted)
+ val unexpectedTags = expectedUnsupportedTags.intersect(actualSupportedTags)
+ assertEquals(setOf(), unexpectedTags, "Tags expected to be unsupported weren't")
+ }
+
+ @Test
+ fun atraceListCategories_supported() {
+ val actualSupportedTags = getActualSupportedTags()
+ val expectedSupportedTags = AtraceTag.supported(rooted = shellSessionRooted)
+ .map { it.tag }
+ .toSet()
+
+ val missingTags = expectedSupportedTags - actualSupportedTags
+ assertEquals(setOf(), missingTags, "Tags expected to be supported weren't")
+ }
+
+ @Test
+ fun shellSession_root() {
+ Assume.assumeTrue(shellSessionRooted)
+ }
+
+ @Test
+ fun shellSession_unroot() {
+ Assume.assumeFalse(shellSessionRooted)
+ }
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/PerfettoConfigTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/PerfettoConfigTest.kt
new file mode 100644
index 0000000..45f983d
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/PerfettoConfigTest.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import androidx.benchmark.Packages
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import perfetto.protos.DataSourceConfig
+import perfetto.protos.FtraceConfig
+import perfetto.protos.TraceConfig
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
+import kotlin.test.assertNotNull
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class PerfettoConfigTest {
+ @Test
+ fun ftraceBasics() {
+ val atraceApps = listOf(Packages.TEST)
+ val ftraceDataSource = perfettoConfig(atraceApps)
+ .data_sources
+ .first { it.config?.name == "linux.ftrace" }
+
+ assertNotNull(ftraceDataSource)
+
+ val ftraceConfig = ftraceDataSource.config?.ftrace_config
+ assertNotNull(ftraceConfig)
+
+ assertEquals(listOf(Packages.TEST), ftraceConfig.atrace_apps)
+
+ assertTrue(ftraceConfig.atrace_categories.contains("view"))
+ assertFalse(ftraceConfig.atrace_categories.contains("webview"))
+ assertFalse(ftraceConfig.atrace_categories.contains("memory"))
+ }
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun validateAndEncode() {
+ // default config shouldn't throw
+ perfettoConfig(listOf(Packages.TEST)).validateAndEncode()
+ }
+
+ @SdkSuppress(minSdkVersion = 21)
+ @Test
+ fun validateAndEncode_invalidAtraceCategories() {
+ val invalidConfig = TraceConfig(
+ buffers = listOf(
+ TraceConfig.BufferConfig(
+ size_kb = 16384,
+ fill_policy = TraceConfig.BufferConfig.FillPolicy.RING_BUFFER
+ )
+ ),
+ data_sources = listOf(
+ TraceConfig.DataSource(
+ config = DataSourceConfig(
+ name = "linux.ftrace",
+ target_buffer = 0,
+ ftrace_config = FtraceConfig(
+ atrace_categories = listOf("bad_category")
+ ),
+ )
+ )
+ )
+ )
+ val exception = assertFailsWith<IllegalStateException> {
+ invalidConfig.validateAndEncode()
+ }
+ assertTrue(exception.message!!.contains("bad_category"))
+ }
+
+ @SdkSuppress(minSdkVersion = 21, maxSdkVersion = 27)
+ @Test
+ fun validateAndEncode_invalidWildcard() {
+ val invalidConfig = TraceConfig(
+ buffers = listOf(
+ TraceConfig.BufferConfig(
+ size_kb = 16384,
+ fill_policy = TraceConfig.BufferConfig.FillPolicy.RING_BUFFER
+ )
+ ),
+ data_sources = listOf(
+ TraceConfig.DataSource(
+ config = DataSourceConfig(
+ name = "linux.ftrace",
+ target_buffer = 0,
+ ftrace_config = FtraceConfig(
+ atrace_categories = listOf("view"),
+ atrace_apps = listOf("*")
+ ),
+ )
+ )
+ )
+ )
+ val exception = assertFailsWith<IllegalStateException> {
+ invalidConfig.validateAndEncode()
+ }
+ assertEquals(
+ expected = "Support for wildcard (*) app matching in atrace added in API 28",
+ actual = exception.message
+ )
+ }
+}
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/UiStateTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/UiStateTest.kt
new file mode 100644
index 0000000..5199c56
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/UiStateTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import androidx.benchmark.createTempFileFromAsset
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import okio.ByteString
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import perfetto.protos.Trace
+import perfetto.protos.TracePacket
+import perfetto.protos.UiState
+import java.io.File
+import kotlin.test.assertEquals
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+public class UiStateTest {
+ @Test
+ public fun uiStateConstructor() {
+ assertEquals(
+ UiState(
+ timeline_start_ts = 1,
+ timeline_end_ts = 100,
+ UiState.HighlightProcess(cmdline = "test.package")
+ ),
+ UiState(
+ timelineStart = 1,
+ timelineEnd = 100,
+ highlightPackage = "test.package"
+ )
+ )
+ }
+
+ @Test
+ public fun uiStateCheck() {
+ val uiState = UiState(
+ timelineStart = 1,
+ timelineEnd = 100,
+ highlightPackage = "test.package"
+ )
+
+ val bytes = UiState.ADAPTER.encode(uiState)
+ val uiStateParse = UiState.ADAPTER.decode(bytes)
+ assertEquals(uiState, uiStateParse)
+ }
+
+ @Test
+ public fun append() {
+ val initial = Trace(
+ packet = listOf(
+ TracePacket(
+ compressed_packets = ByteString.of(0, 1, 3)
+ )
+ )
+ )
+ val file = File.createTempFile("append", ".trace")
+ file.writeBytes(Trace.ADAPTER.encode(initial))
+ file.appendUiState(
+ UiState(
+ timelineStart = 0,
+ timelineEnd = 1,
+ highlightPackage = "test.package"
+ )
+ )
+
+ val final = Trace.ADAPTER.decode(file.readBytes())
+
+ val expected = Trace(
+ packet = listOf(
+ TracePacket(
+ compressed_packets = ByteString.of(0, 1, 3)
+ ),
+ TracePacket(
+ ui_state = UiState(
+ timeline_start_ts = 0,
+ timeline_end_ts = 1,
+ UiState.HighlightProcess(cmdline = "test.package")
+ )
+ )
+ )
+ )
+ assertEquals(expected, final)
+ }
+
+ @Test
+ public fun actualTraceAppend() {
+ val traceFile = createTempFileFromAsset("WarmStartup", ".trace")
+ val initialSize = traceFile.readBytes().size
+ traceFile.appendUiState(
+ UiState(
+ timelineStart = 2,
+ timelineEnd = 4,
+ highlightPackage = "test.package"
+ )
+ )
+
+ val finalSize = traceFile.readBytes().size
+
+ // file may shrink slightly due to re-encode, but shouldn't be significant
+ assertTrue(finalSize > initialSize * 0.95f)
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/ConfigurationError.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/ConfigurationError.kt
new file mode 100644
index 0000000..ab498d3
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/ConfigurationError.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import androidx.annotation.RestrictTo
+
+/**
+ * Represents an error in configuration of a benchmark.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+data class ConfigurationError(
+ /**
+ * All-caps, publicly visible ID for the error.
+ *
+ * Used for suppression via instrumentation arguments.
+ */
+ val id: String,
+
+ /**
+ * One-line summary of the problem.
+ */
+ val summary: String,
+
+ /**
+ * Multi-line, preformatted detailed description of the problem.
+ */
+ val message: String
+) {
+ init {
+ validateParams(id, summary)
+ }
+
+ companion object {
+ internal fun validateParams(
+ id: String,
+ summary: String
+ ) {
+ require(!id.contains("[a-z]".toRegex())) {
+ "IDs must be ALL-CAPs by convention (id=$id)"
+ }
+ require(!id.contains("_")) {
+ "Use hyphen instead of underscore for consistency (id=$id)"
+ }
+ require(!summary.contains("\n")) {
+ "Summary must be one line"
+ }
+ }
+ }
+
+ /**
+ * Representation of suppressed errors during a running benchmark.
+ */
+ class SuppressionState(
+ /**
+ * Prefix for output data to mark as potentially invalid.
+ */
+ val prefix: String,
+
+ /**
+ * Warning message to present to the user.
+ */
+ val warningMessage: String
+ )
+}
+
+/** @suppress */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun conditionalError(
+ hasError: Boolean,
+ id: String,
+ summary: String,
+ message: String
+): ConfigurationError? {
+ // validation done here *and* in constructor to ensure it happens even when error doesn't fire
+ ConfigurationError.validateParams(id, summary)
+ return if (hasError) {
+ ConfigurationError(id, summary, message)
+ } else null
+}
+
+internal fun List<ConfigurationError>.prettyPrint(prefix: String): String {
+ return joinToString("\n") {
+ prefix + it.summary + "\n" + it.message.prependIndent() + "\n"
+ }
+}
+
+/**
+ * Throw an AssertionError if the list contains an unsuppressed error, and return either a
+ * SuppressionState if errors are suppressed, or null otherwise.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun List<ConfigurationError>.checkAndGetSuppressionState(
+ suppressedErrorIds: Set<String>,
+): ConfigurationError.SuppressionState? {
+ val (suppressed, unsuppressed) = partition {
+ suppressedErrorIds.contains(it.id)
+ }
+
+ val prefix = suppressed.joinToString("_") { it.id } + "_"
+
+ val unsuppressedString = unsuppressed.joinToString(" ") { it.id }
+ val suppressedString = suppressed.joinToString(" ") { it.id }
+ val howToSuppressString = this.joinToString(",") { it.id }
+
+ if (unsuppressed.isNotEmpty()) {
+ throw AssertionError(
+ """
+ |ERRORS (not suppressed): $unsuppressedString
+ |WARNINGS (suppressed): $suppressedString
+ |
+ |${unsuppressed.prettyPrint("ERROR: ")}
+ |While you can suppress these errors (turning them into warnings)
+ |PLEASE NOTE THAT EACH SUPPRESSED ERROR COMPROMISES ACCURACY
+ |
+ |// Sample suppression, in a benchmark module's build.gradle:
+ |android {
+ | defaultConfig {
+ | testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "$howToSuppressString"
+ | }
+ |}
+ """.trimMargin()
+ )
+ }
+
+ if (suppressed.isEmpty()) {
+ return null
+ }
+
+ return ConfigurationError.SuppressionState(prefix, suppressed.prettyPrint("WARNING: "))
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
new file mode 100644
index 0000000..1378bad
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.BatteryManager
+import android.os.Build
+import androidx.annotation.RestrictTo
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.File
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+object DeviceInfo {
+ val isEmulator = Build.FINGERPRINT.startsWith("generic") ||
+ Build.FINGERPRINT.startsWith("unknown") ||
+ Build.MODEL.contains("google_sdk") ||
+ Build.MODEL.contains("Emulator") ||
+ Build.MODEL.contains("Android SDK built for x86") ||
+ Build.MANUFACTURER.contains("Genymotion") ||
+ Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic") ||
+ "google_sdk" == Build.PRODUCT
+
+ val isEngBuild = Build.FINGERPRINT.contains(":eng/")
+
+ val isRooted =
+ arrayOf(
+ "/system/app/Superuser.apk",
+ "/sbin/su",
+ "/system/bin/su",
+ "/system/xbin/su",
+ "/data/local/xbin/su",
+ "/data/local/bin/su",
+ "/system/sd/xbin/su",
+ "/system/bin/failsafe/su",
+ "/data/local/su",
+ "/su/bin/su"
+ ).any { File(it).exists() }
+
+ /**
+ * Battery percentage required to avoid low battery warning.
+ *
+ * This number is supposed to be a conservative cutoff for when low-battery-triggered power
+ * savings modes (such as disabling cores) may be enabled. It's possible that
+ * [BatteryManager.EXTRA_BATTERY_LOW] is a better source of truth for this, but we want to be
+ * conservative in case the device loses power slowly while benchmarks run.
+ */
+ const val MINIMUM_BATTERY_PERCENT = 25
+
+ val initialBatteryPercent: Int
+
+ /**
+ * String summarizing device hardware and software, for bug reporting purposes.
+ */
+ val deviceSummaryString: String
+
+ /**
+ * General errors about device configuration, applicable to all types of benchmark.
+ *
+ * These errors indicate no performance tests should be performed on this device, in it's
+ * current conditions.
+ */
+ val errors: List<ConfigurationError>
+
+ init {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+
+ val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
+ initialBatteryPercent = context.registerReceiver(null, filter)?.run {
+ val level = getIntExtra(BatteryManager.EXTRA_LEVEL, 100)
+ val scale = getIntExtra(BatteryManager.EXTRA_SCALE, 100)
+ level * 100 / scale
+ } ?: 100
+
+ deviceSummaryString = "DeviceInfo(Brand=${Build.BRAND}" +
+ ", Model=${Build.MODEL}" +
+ ", SDK=${Build.VERSION.SDK_INT}" +
+ ", BuildFp=${Build.FINGERPRINT})"
+
+ errors = listOfNotNull(
+ conditionalError(
+ hasError = isEngBuild,
+ id = "ENG-BUILD",
+ summary = "Running on Eng Build",
+ message = """
+ Benchmark is running on device flashed with a '-eng' build. Eng builds
+ of the platform drastically reduce performance to enable testing
+ changes quickly. For this reason they should not be used for
+ benchmarking. Use a '-user' or '-userdebug' system image.
+ """.trimIndent()
+ ),
+ conditionalError(
+ hasError = isEmulator,
+ id = "EMULATOR",
+ summary = "Running on Emulator",
+ message = """
+ Benchmark is running on an emulator, which is not representative of
+ real user devices. Use a physical device to benchmark. Emulator
+ benchmark improvements might not carry over to a real user's
+ experience (or even regress real device performance).
+ """.trimIndent()
+ ),
+ conditionalError(
+ hasError = initialBatteryPercent < MINIMUM_BATTERY_PERCENT,
+ id = "LOW-BATTERY",
+ summary = "Device has low battery ($initialBatteryPercent)",
+ message = """
+ When battery is low, devices will often reduce performance (e.g. disabling big
+ cores) to save remaining battery. This occurs even when they are plugged in.
+ Wait for your battery to charge to at least $MINIMUM_BATTERY_PERCENT%.
+ Currently at $initialBatteryPercent%.
+ """.trimIndent()
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
index 208f711..6ed7d6d 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
@@ -22,12 +22,13 @@
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.test.platform.app.InstrumentationRegistry
+import java.io.File
+import java.io.InputStream
import java.nio.charset.Charset
/**
- * Shell command helpers, which no-op below API 21
- *
- * Eventually, ShellUtils in macrobenchmark should likely merge into this.
+ * Wrappers for UiAutomation.executeShellCommand to handle compat behavior, and add additional
+ * features like script execution (with piping), stdin/stderr.
*
* @suppress
*/
@@ -54,7 +55,7 @@
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun executeCommand(command: String): String {
- return ShellImpl.executeShellCommand(command)
+ return ShellImpl.executeCommand(command)
}
/**
@@ -73,6 +74,133 @@
}
}
}
+
+ @RequiresApi(21)
+ fun chmodExecutable(absoluteFilePath: String) {
+ if (Build.VERSION.SDK_INT >= 23) {
+ ShellImpl.executeCommand("chmod +x $absoluteFilePath")
+ } else {
+ // chmod with support for +x only added in API 23
+ // While 777 is technically more permissive, this is only used for scripts and temporary
+ // files in tests, so we don't worry about permissions / access here
+ ShellImpl.executeCommand("chmod 777 $absoluteFilePath")
+ }
+ }
+
+ @RequiresApi(21)
+ fun moveToTmpAndMakeExecutable(src: String, dst: String) {
+ // Note: we don't check for return values from the below, since shell based file
+ // permission errors generally crash our process.
+ ShellImpl.executeCommand("cp $src $dst")
+ chmodExecutable(dst)
+ }
+
+ /**
+ * Writes the inputStream to an executable file with the given name in `/data/local/tmp`
+ */
+ @RequiresApi(21)
+ fun createRunnableExecutable(name: String, inputStream: InputStream): String {
+ // dirUsableByAppAndShell is writable, but we can't execute there (as of Q),
+ // so we copy to /data/local/tmp
+ val externalDir = Outputs.dirUsableByAppAndShell
+ val writableExecutableFile = File.createTempFile(
+ /* prefix */ "temporary_$name",
+ /* suffix */ null,
+ /* directory */ externalDir
+ )
+ val runnableExecutablePath = "/data/local/tmp/$name"
+
+ try {
+ writableExecutableFile.outputStream().use {
+ inputStream.copyTo(it)
+ }
+ moveToTmpAndMakeExecutable(
+ src = writableExecutableFile.absolutePath,
+ dst = runnableExecutablePath
+ )
+ } finally {
+ writableExecutableFile.delete()
+ }
+
+ return runnableExecutablePath
+ }
+
+ /**
+ * Returns true if the shell session is rooted, and thus root commands can be run (e.g. atrace
+ * commands with root-only tags)
+ */
+ @RequiresApi(21)
+ fun isSessionRooted(): Boolean {
+ return ShellImpl.executeCommand("getprop service.adb.root").trim() == "1"
+ }
+
+ /**
+ * Convenience wrapper around [UiAutomation.executeShellCommand()] which enables redirects,
+ * piping, and all other shell script functionality.
+ *
+ * Unlike [UiDevice.executeShellCommand()], this method supports arbitrary multi-line shell
+ * expressions, as it creates and executes a shell script in `/data/local/tmp/`.
+ *
+ * Note that shell scripting capabilities differ based on device version. To see which utilities
+ * are available on which platform versions,see
+ * [Android's shell and utilities](https://android.googlesource.com/platform/system/core/+/master/shell_and_utilities/README.md#)
+ *
+ * @param script Script content to run
+ * @param stdin String to pass in as stdin to first command in script
+ *
+ * @return Stdout string
+ */
+ @RequiresApi(21)
+ fun executeScript(script: String, stdin: String? = null): String {
+ return ShellImpl.executeScript(script, stdin, false).first
+ }
+
+ data class Output(val stdout: String, val stderr: String)
+
+ /**
+ * Convenience wrapper around [UiAutomation.executeShellCommand()] which enables redirects,
+ * piping, and all other shell script functionality, and which captures stderr of last command.
+ *
+ * Unlike [UiDevice.executeShellCommand()], this method supports arbitrary multi-line shell
+ * expressions, as it creates and executes a shell script in `/data/local/tmp/`.
+ *
+ * Note that shell scripting capabilities differ based on device version. To see which utilities
+ * are available on which platform versions,see
+ * [Android's shell and utilities](https://android.googlesource.com/platform/system/core/+/master/shell_and_utilities/README.md#)
+ *
+ * @param script Script content to run
+ * @param stdin String to pass in as stdin to first command in script
+ *
+ * @return ShellOutput, including stdout of full script, and stderr of last command.
+ */
+ @RequiresApi(21)
+ fun executeScriptWithStderr(
+ script: String,
+ stdin: String? = null
+ ): Output {
+ return ShellImpl.executeScript(
+ script = script,
+ stdin = stdin,
+ includeStderr = true
+ ).run {
+ Output(first, second!!)
+ }
+ }
+
+ @RequiresApi(21)
+ fun isPackageAlive(packageName: String): Boolean {
+ if (Build.VERSION.SDK_INT >= 24) {
+ // On API 23 (first version to offer it) we observe that 'pidof'
+ // returns list of all processes :|
+ return executeCommand("pidof $packageName").isNotBlank()
+ }
+
+ // Can't use ps -A on older platforms, arg isn't supported.
+ // Can't simply run ps, since it gets truncated
+ return executeScript("ps | grep $packageName")
+ .split("\r?\n")
+ .any { it.trim().endsWith(" $packageName") }
+ }
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
@@ -90,10 +218,64 @@
* Reimplementation of UiAutomator's Device.executeShellCommand,
* to avoid the UiAutomator dependency
*/
- fun executeShellCommand(cmd: String): String {
+ fun executeCommand(cmd: String): String {
val parcelFileDescriptor = uiAutomation.executeShellCommand(cmd)
AutoCloseInputStream(parcelFileDescriptor).use { inputStream ->
return inputStream.readBytes().toString(Charset.defaultCharset())
}
}
+
+ fun executeScript(
+ script: String,
+ stdin: String?,
+ includeStderr: Boolean
+ ): Pair<String, String?> {
+ // dirUsableByAppAndShell is writable, but we can't execute there (as of Q),
+ // so we copy to /data/local/tmp
+ val externalDir = androidx.benchmark.Outputs.dirUsableByAppAndShell
+ val writableScriptFile = java.io.File.createTempFile("temporaryScript", ".sh", externalDir)
+ val runnableScriptPath = "/data/local/tmp/" + writableScriptFile.name
+
+ // only create/read/delete stdin/stderr files if they are needed
+ val stdinFile = stdin?.run {
+ java.io.File.createTempFile("temporaryStdin", null, externalDir)
+ }
+ val stderrPath = if (includeStderr) {
+ // we use a modified runnableScriptPath (as opposed to externalDir) because some shell
+ // commands fail to redirect stderr to externalDir (notably, `am start`).
+ // This also means we need to `cat` the file to read it, and `rm` to remove it.
+ runnableScriptPath + "_stderr"
+ } else {
+ null
+ }
+
+ try {
+ var scriptText: String = script
+ if (stdinFile != null) {
+ stdinFile.writeText(stdin)
+ scriptText = "cat ${stdinFile.absolutePath} | $scriptText"
+ }
+ if (stderrPath != null) {
+ scriptText = "$scriptText 2> $stderrPath"
+ }
+ writableScriptFile.writeText(scriptText)
+
+ // Note: we don't check for return values from the below, since shell based file
+ // permission errors generally crash our process.
+ executeCommand("cp ${writableScriptFile.absolutePath} $runnableScriptPath")
+ androidx.benchmark.Shell.chmodExecutable(runnableScriptPath)
+
+ val stdout = executeCommand(runnableScriptPath)
+ val stderr = stderrPath?.run { executeCommand("cat $stderrPath") }
+
+ return Pair(stdout, stderr)
+ } finally {
+ stdinFile?.delete()
+ stderrPath?.run {
+ executeCommand("rm $stderrPath")
+ }
+ writableScriptFile.delete()
+ executeCommand("rm $runnableScriptPath")
+ }
+ }
}
\ No newline at end of file
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
new file mode 100644
index 0000000..b27c1ed
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import androidx.annotation.RestrictTo
+import perfetto.protos.Trace
+import perfetto.protos.TracePacket
+import perfetto.protos.TrackDescriptor
+import perfetto.protos.TrackEvent
+
+/**
+ * Userspace-buffer-based tracing api, that provides implementation for [userspaceTrace].
+ *
+ * This records while atrace isn't capturing by storing trace events manually in a list of
+ * in-userspace-memory perfetto protos.
+ *
+ * After trace processing, the extra events (before _and_ after the measureBlock section of a
+ * benchmark) can be added to the trace by calling [commitToTrace], and appending that to the
+ * trace on-disk.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+object UserspaceTracing {
+ /**
+ * All events emitted by the benchmark annotation should have the same value.
+ * the value needs to not conflict with any sequence id emitted in the trace.
+ * You can rely on the fact that traces will never contain an ID >
+ * kMaxProducerID * kMaxWriterID (65536 * 1024) = 67108864. A high number will
+ * be good enough without having to read the trace (unless something else
+ * outside of your control is also emitting fake slices)
+ */
+ private const val TRUSTED_PACKET_SEQUENCE_ID: Int = 1_234_543_210
+
+ /**
+ * This is a unique ID of the track. The state is global and 64 bit. Tracks are
+ * obtained by hashing pids/tids. Just picked an arbitrary 64 bit value. You have
+ * more probability of winning the lottery than hitting a collision.
+ */
+ private const val UUID = 123_456_543_210L
+
+ /**
+ * Clock id for clock used by tracing events - this corresponds to CLOCK_MONOTONIC
+ */
+ private const val CLOCK_ID = 3
+
+ /**
+ * Name of track in for userspace tracing events
+ */
+ private const val TRACK_DESCRIPTOR_NAME = "Macrobenchmark"
+
+ /**
+ * Tag to enable post-filtering of events in the trace.
+ */
+ private val TRACK_EVENT_CATEGORIES = listOf("benchmark")
+
+ private fun createInitialTracePacket() = TracePacket(
+ timestamp = System.nanoTime(),
+ timestamp_clock_id = CLOCK_ID,
+ incremental_state_cleared = true,
+ track_descriptor = TrackDescriptor(
+ uuid = UUID,
+ name = TRACK_DESCRIPTOR_NAME
+ )
+ )
+
+ /**
+ * For perf/simplicity, this isn't protected by a lock - it should only every be
+ * accessed by the test thread, and dumped/reset between tests.
+ */
+ val events = mutableListOf(createInitialTracePacket())
+
+ /**
+ * Capture trace state, and return as a Trace(), which can be appended to a trace file.
+ */
+ fun commitToTrace(): Trace {
+ val capturedEvents = events.toList()
+ events.clear()
+ events.add(createInitialTracePacket())
+ return Trace(capturedEvents)
+ }
+
+ fun startSection(label: String) {
+ events.add(
+ TracePacket(
+ timestamp = System.nanoTime(),
+ timestamp_clock_id = CLOCK_ID,
+ trusted_packet_sequence_id = TRUSTED_PACKET_SEQUENCE_ID,
+ track_event = TrackEvent(
+ type = TrackEvent.Type.TYPE_SLICE_BEGIN,
+ track_uuid = UUID,
+ categories = TRACK_EVENT_CATEGORIES,
+ name = label
+ )
+ )
+ )
+ }
+
+ fun endSection() {
+ events.add(
+ TracePacket(
+ timestamp = System.nanoTime(),
+ timestamp_clock_id = CLOCK_ID,
+ trusted_packet_sequence_id = TRUSTED_PACKET_SEQUENCE_ID,
+ track_event = TrackEvent(
+ type = TrackEvent.Type.TYPE_SLICE_END,
+ track_uuid = UUID,
+ )
+ )
+ )
+ }
+}
+
+/** @suppress */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+inline fun <T> userspaceTrace(label: String, block: () -> T): T {
+ UserspaceTracing.startSection(label)
+ return try {
+ block()
+ } finally {
+ UserspaceTracing.endSection()
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/AtraceTag.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/AtraceTag.kt
new file mode 100644
index 0000000..31e6a21
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/AtraceTag.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import android.os.Build
+
+/**
+ * Enum representing set of all atrace tags used by macrobenchmark, and whether they're expected to
+ * be supported on the current device.
+ *
+ * Note that this API assumes API >= 21, as that's the library's min API
+ *
+ * While supported tags could be collected from the local device (e.g. in `AtraceTagTest`), the
+ * intent of this class is to track this information statically.
+ */
+@Suppress("unused") // enums always accessed via values()
+internal enum class AtraceTag(
+ val tag: String
+) {
+ ActivityManager("am"),
+ BinderDriver("binder_driver") {
+ override fun supported(api: Int, rooted: Boolean): Boolean {
+ return api >= 24
+ }
+ },
+ Camera("camera"),
+ Dalvik("dalvik"),
+ Frequency("freq"),
+ Graphics("gfx"),
+ HardwareModules("hal"),
+ Idle("idle"),
+ Input("input"),
+ MemReclaim("memreclaim"),
+ Resources("res"),
+ Scheduling("sched"),
+ Synchronization("sync") {
+ override fun supported(api: Int, rooted: Boolean): Boolean {
+ return rooted || api >= 28
+ }
+ },
+ View("view"),
+ WebView("webview"),
+ WindowManager("wm");
+
+ /**
+ * Return true if the tag is available on the specified api level, with specified shell
+ * session root status.
+ */
+ open fun supported(api: Int, rooted: Boolean): Boolean {
+ return true
+ }
+
+ companion object {
+ fun supported(
+ api: Int = Build.VERSION.SDK_INT,
+ rooted: Boolean
+ ): Set<AtraceTag> {
+ return values()
+ .filter { it.supported(api = api, rooted = rooted) }
+ .toSet()
+ }
+
+ fun unsupported(
+ api: Int = Build.VERSION.SDK_INT,
+ rooted: Boolean
+ ): Set<AtraceTag> {
+ return values().toSet() - supported(api, rooted)
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
new file mode 100644
index 0000000..b8c6474
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.benchmark.Outputs
+import androidx.benchmark.userspaceTrace
+import java.io.File
+
+/**
+ * Enables capturing a Perfetto trace from a test on Q+ devices.
+ *
+ * It's possible to support API 28, but there are a few issues to resolve:
+ * - Use binary config protos
+ * - May need to distribute perfetto binary, with atrace workaround
+ * - App tags are not available, due to lack of `<profileable shell=true>`. Can potentially hack
+ * around this for individual tags within test infra as needed.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(21)
+public class PerfettoCapture(
+ unbundled: Boolean = Build.VERSION.SDK_INT in 21..28
+) {
+
+ private val helper: PerfettoHelper = PerfettoHelper(unbundled)
+
+ /**
+ * Kill perfetto process, if it is running.
+ */
+ public fun cancel() {
+ if (helper.isPerfettoRunning()) {
+ helper.stopPerfetto()
+ }
+ }
+
+ /**
+ * Start collecting perfetto trace.
+ *
+ * TODO: provide configuration options
+ */
+ public fun start(packages: List<String>) = userspaceTrace("start perfetto") {
+ // Write binary proto to dir that shell can read
+ // TODO: cache on disk
+ val configProtoFile = File(Outputs.dirUsableByAppAndShell, "trace_config.pb")
+ try {
+ userspaceTrace("write config") {
+ val atraceApps = if (Build.VERSION.SDK_INT <= 28) {
+ packages
+ } else {
+ listOf("*")
+ }
+ configProtoFile.writeBytes(perfettoConfig(atraceApps).validateAndEncode())
+ }
+ userspaceTrace("start perfetto process") {
+ helper.startCollecting(configProtoFile.absolutePath, false)
+ }
+ } finally {
+ configProtoFile.delete()
+ }
+ }
+
+ /**
+ * Stop collection, and record trace to the specified file path.
+ *
+ * @param destinationPath Absolute path to write perfetto trace to. Must be shell-writable,
+ * such as result of `context.getExternalFilesDir(null)` or other similar `external` paths.
+ */
+ public fun stop(destinationPath: String) = userspaceTrace("stop perfetto") {
+ // Wait time determined empirically by running a trivial startup test (3 iterations) 200
+ // times, and validating no metric capture failures.
+ if (!helper.stopCollecting(500, destinationPath)) {
+ // TODO: move internal failures to be exceptions
+ throw IllegalStateException("Unable to store perfetto trace in $destinationPath")
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
new file mode 100644
index 0000000..11ebeb0
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import android.os.Build
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.benchmark.Outputs
+import androidx.benchmark.Outputs.dateToFileName
+import androidx.benchmark.PropOverride
+
+/**
+ * Wrapper for [PerfettoCapture] which does nothing below L.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class PerfettoCaptureWrapper {
+ private var capture: PerfettoCapture? = null
+ private val TRACE_ENABLE_PROP = "persist.traced.enable"
+
+ init {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ capture = PerfettoCapture()
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ private fun start(packages: List<String>): Boolean {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ Log.d(PerfettoHelper.LOG_TAG, "Recording perfetto trace")
+ capture?.start(packages)
+ }
+ return true
+ }
+
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ private fun stop(benchmarkName: String, iteration: Int): String {
+ val iterString = iteration.toString().padStart(3, '0')
+ val traceName = "${benchmarkName}_iter${iterString}_${dateToFileName()}.perfetto-trace"
+ return Outputs.writeFile(fileName = traceName, reportKey = "perfetto_trace_$iterString") {
+ capture!!.stop(it.absolutePath)
+ }
+ }
+
+ fun record(
+ benchmarkName: String,
+ iteration: Int,
+ packages: List<String>,
+ block: () -> Unit
+ ): String? {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ return null // tracing currently not supported on this version
+ }
+
+ // Prior to Android 11 (R), a shell property must be set to enable perfetto tracing, see
+ // https://perfetto.dev/docs/quickstart/android-tracing#starting-the-tracing-services
+ val propOverride = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
+ PropOverride(TRACE_ENABLE_PROP, "1")
+ } else null
+ try {
+ propOverride?.forceValue()
+ start(packages)
+ block()
+ return stop(benchmarkName, iteration)
+ } finally {
+ propOverride?.resetIfOverridden()
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
new file mode 100644
index 0000000..34adfb4
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.benchmark.Shell
+import perfetto.protos.DataSourceConfig
+import perfetto.protos.FtraceConfig
+import perfetto.protos.MeminfoCounters
+import perfetto.protos.ProcessStatsConfig
+import perfetto.protos.SysStatsConfig
+import perfetto.protos.TraceConfig
+import perfetto.protos.TraceConfig.BufferConfig
+import perfetto.protos.TraceConfig.BufferConfig.FillPolicy
+
+private fun ftraceDataSource(
+ atraceApps: List<String>
+) = TraceConfig.DataSource(
+ config = DataSourceConfig(
+ name = "linux.ftrace",
+ target_buffer = 0,
+ ftrace_config = FtraceConfig(
+ // These parameters affect only the kernel trace buffer size and how
+ // frequently it gets moved into the userspace buffer defined above.
+ buffer_size_kb = 16384,
+ drain_period_ms = 250,
+ ftrace_events = listOf(
+ // We need to do process tracking to ensure kernel ftrace events targeted at short-lived
+ // threads are associated correctly
+ "task/task_newtask",
+ "task/task_rename",
+ "sched/sched_process_exit",
+ "sched/sched_process_free",
+
+ // Memory events
+ "mm_event/mm_event_record",
+ "kmem/rss_stat",
+ "kmem/ion_heap_shrink",
+ "kmem/ion_heap_grow",
+ "ion/ion_stat",
+ "oom/oom_score_adj_update",
+
+ // Old (kernel) LMK
+ "lowmemorykiller/lowmemory_kill",
+ ),
+ atrace_categories = listOf(
+ AtraceTag.ActivityManager,
+ AtraceTag.BinderDriver,
+ AtraceTag.Camera,
+ AtraceTag.Dalvik,
+ AtraceTag.Frequency,
+ AtraceTag.Graphics,
+ AtraceTag.HardwareModules,
+ AtraceTag.Idle,
+ AtraceTag.Input,
+ AtraceTag.MemReclaim,
+ AtraceTag.Resources,
+ AtraceTag.Scheduling,
+ AtraceTag.Synchronization,
+ AtraceTag.View,
+ AtraceTag.WindowManager
+ // "webview" not included to workaround b/190743595
+ // "memory" not included as some Q devices requiring ftrace_event
+ // configuration directly to collect this data. See b/171085599
+ ).filter {
+ // filter to only supported tags on unrooted build
+ // TODO: use root-only tags as needed
+ it.supported(api = Build.VERSION.SDK_INT, rooted = false)
+ }.map {
+ it.tag
+ },
+ atrace_apps = atraceApps
+ )
+ )
+)
+
+private val PROCESS_STATS_DATASOURCE = TraceConfig.DataSource(
+ config = DataSourceConfig(
+ name = "linux.process_stats",
+ target_buffer = 1,
+ process_stats_config = ProcessStatsConfig(
+ proc_stats_poll_ms = 10000
+ )
+ )
+)
+
+private val LINUX_SYS_STATS_DATASOURCE = TraceConfig.DataSource(
+ config = DataSourceConfig(
+ name = "linux.sys_stats",
+ target_buffer = 1,
+ sys_stats_config = SysStatsConfig(
+ meminfo_period_ms = 1000,
+ meminfo_counters = listOf(
+ MeminfoCounters.MEMINFO_MEM_TOTAL,
+ MeminfoCounters.MEMINFO_MEM_FREE,
+ MeminfoCounters.MEMINFO_MEM_AVAILABLE,
+ MeminfoCounters.MEMINFO_BUFFERS,
+ MeminfoCounters.MEMINFO_CACHED,
+ MeminfoCounters.MEMINFO_SWAP_CACHED,
+ MeminfoCounters.MEMINFO_ACTIVE,
+ MeminfoCounters.MEMINFO_INACTIVE,
+ MeminfoCounters.MEMINFO_ACTIVE_ANON,
+ MeminfoCounters.MEMINFO_INACTIVE_ANON,
+ MeminfoCounters.MEMINFO_ACTIVE_FILE,
+ MeminfoCounters.MEMINFO_INACTIVE_FILE,
+ MeminfoCounters.MEMINFO_UNEVICTABLE,
+ MeminfoCounters.MEMINFO_SWAP_TOTAL,
+ MeminfoCounters.MEMINFO_SWAP_FREE,
+ MeminfoCounters.MEMINFO_DIRTY,
+ MeminfoCounters.MEMINFO_WRITEBACK,
+ MeminfoCounters.MEMINFO_ANON_PAGES,
+ MeminfoCounters.MEMINFO_MAPPED,
+ MeminfoCounters.MEMINFO_SHMEM,
+ )
+ )
+ )
+)
+
+/**
+ * Global config for perfetto.
+ *
+ * Eventually, this should be more configurable.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun perfettoConfig(
+ atraceApps: List<String>
+) = TraceConfig(
+ buffers = listOf(
+ BufferConfig(size_kb = 16384, FillPolicy.RING_BUFFER),
+ BufferConfig(size_kb = 16384, FillPolicy.RING_BUFFER)
+ ),
+ data_sources = listOf(
+ ftraceDataSource(atraceApps),
+ PROCESS_STATS_DATASOURCE,
+ LINUX_SYS_STATS_DATASOURCE,
+ ),
+)
+
+@RequiresApi(21) // needed for shell access
+internal fun TraceConfig.validateAndEncode(): ByteArray {
+ val ftraceConfig = data_sources
+ .mapNotNull { it.config?.ftrace_config }
+ .first()
+
+ // check tags against known-supported tags based on SDK_INT / root status
+ val supportedTags = AtraceTag.supported(
+ api = Build.VERSION.SDK_INT,
+ rooted = Shell.isSessionRooted()
+ ).map { it.tag }.toSet()
+
+ val unsupportedTags = (ftraceConfig.atrace_categories - supportedTags)
+ check(unsupportedTags.isEmpty()) {
+ "Error - attempted to use unsupported atrace tags: $unsupportedTags"
+ }
+
+ if (Build.VERSION.SDK_INT < 28) {
+ check(!ftraceConfig.atrace_apps.contains("*")) {
+ "Support for wildcard (*) app matching in atrace added in API 28"
+ }
+ }
+ return encode()
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
new file mode 100644
index 0000000..4cee2fc
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import android.os.Build
+import android.os.SystemClock
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.benchmark.Shell
+import androidx.benchmark.DeviceInfo.deviceSummaryString
+import androidx.benchmark.userspaceTrace
+import androidx.test.platform.app.InstrumentationRegistry
+import org.jetbrains.annotations.TestOnly
+import java.io.File
+import java.io.IOException
+
+/**
+ * PerfettoHelper is used to start and stop the perfetto tracing and move the
+ * output perfetto trace file to destination folder.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(21)
+public class PerfettoHelper(
+ private val unbundled: Boolean = Build.VERSION.SDK_INT < LOWEST_BUNDLED_VERSION_SUPPORTED
+) {
+ init {
+ require(unbundled || Build.VERSION.SDK_INT >= LOWEST_BUNDLED_VERSION_SUPPORTED) {
+ "Perfetto capture using the os version of perfetto requires API " +
+ "$LOWEST_BUNDLED_VERSION_SUPPORTED or greater."
+ }
+ }
+
+ private fun perfettoStartupException(label: String, cause: Exception?): IllegalStateException {
+ return IllegalStateException(
+ """
+ $label
+ Please report a bug, and include a logcat capture of the test run and failure.
+ $deviceSummaryString
+ """.trimIndent(),
+ cause
+ )
+ }
+
+ /**
+ * Start the perfetto tracing in background using the given config file.
+ *
+ * The output will be written to /data/misc/perfetto-traces/trace_output.pb. Perfetto has
+ * write access only to /data/misc/perfetto-traces/ folder. The config file may be anywhere
+ * readable by shell.
+ *
+ * @param configFilePath used for collecting the perfetto trace.
+ * @param isTextProtoConfig true if the config file is textproto format otherwise false.
+ */
+ public fun startCollecting(configFilePath: String, isTextProtoConfig: Boolean) {
+ require(configFilePath.isNotEmpty()) {
+ "Perfetto config cannot be empty."
+ }
+
+ try {
+ // Cleanup already existing perfetto process.
+ Log.i(LOG_TAG, "Cleanup perfetto before starting.")
+ if (isPerfettoRunning()) {
+ Log.i(LOG_TAG, "Perfetto tracing is already running. Stopping perfetto.")
+ if (!stopPerfetto()) {
+ throw perfettoStartupException(
+ "Unable to stop Perfetto trace capture",
+ null
+ )
+ }
+ }
+
+ // The actual location of the config path.
+ val actualConfigPath = if (unbundled) {
+ val path = "$UNBUNDLED_PERFETTO_ROOT_DIR/config.pb"
+ // Move the config to a directory that unbundled perfetto has permissions for.
+ Shell.executeCommand("rm $path")
+ Shell.executeCommand("mv $configFilePath $path")
+ path
+ } else {
+ configFilePath
+ }
+
+ val outputPath = getPerfettoTmpOutputFilePath()
+ // Remove already existing temporary output trace file if any.
+ val output = Shell.executeCommand("rm $outputPath")
+ Log.i(LOG_TAG, "Perfetto output file cleanup - $output")
+
+ // Setup `traced` and `traced_probes` if necessary.
+ setupTracedAndProbes()
+
+ // Perfetto
+ val perfettoCmd = perfettoCommand(actualConfigPath, isTextProtoConfig)
+ Log.i(LOG_TAG, "Starting perfetto tracing with cmd: $perfettoCmd")
+ val perfettoCmdOutput = Shell.executeScript(perfettoCmd)
+ Log.i(LOG_TAG, "Perfetto pid - $perfettoCmdOutput")
+ } catch (ioe: IOException) {
+ throw perfettoStartupException("Unable to start perfetto tracing", ioe)
+ }
+
+ if (!isPerfettoRunning()) {
+ throw perfettoStartupException("Perfetto tracing failed to start. ", null)
+ }
+
+ Log.i(LOG_TAG, "Perfetto tracing started successfully.")
+ }
+
+ /**
+ * Stop the perfetto trace collection under /data/misc/perfetto-traces/trace_output.pb after
+ * waiting for given time in msecs and copy the output to the destination file.
+ *
+ * @param waitTimeInMsecs time to wait in msecs before stopping the trace collection.
+ * @param destinationFile file to copy the perfetto output trace.
+ * @return true if the trace collection is successful otherwise false.
+ */
+ public fun stopCollecting(waitTimeInMsecs: Long, destinationFile: String): Boolean {
+ // Wait for the dump interval before stopping the trace.
+ userspaceTrace("Wait for perfetto flush") {
+ Log.i(LOG_TAG, "Waiting for $waitTimeInMsecs millis before stopping perfetto.")
+ SystemClock.sleep(waitTimeInMsecs)
+ }
+
+ // Stop the perfetto and copy the output file.
+ Log.i(LOG_TAG, "Stopping perfetto.")
+ try {
+ var stopped = userspaceTrace("stop perfetto process") { stopPerfetto() }
+ if (unbundled) {
+ Log.i(LOG_TAG, "Stopping `traced` and `traced_probes`.")
+ stopped = stopped.or(stopProcess(getProcessId(TRACED)))
+ stopped = stopped.or(stopProcess(getProcessId(TRACED_PROBES)))
+ }
+ if (!stopped) {
+ Log.e(LOG_TAG, "Perfetto failed to stop.")
+ return false
+ }
+ Log.i(LOG_TAG, "Writing to $destinationFile.")
+ return userspaceTrace("copy trace to output dir") {
+ copyFileOutput(destinationFile)
+ }
+ } catch (ioe: IOException) {
+ Log.e(LOG_TAG, "Unable to stop the perfetto tracing due to " + ioe.message, ioe)
+ return false
+ }
+ }
+
+ /**
+ * Utility method for stopping perfetto.
+ *
+ * @return true if perfetto is stopped successfully.
+ */
+ @Throws(IOException::class)
+ public fun stopPerfetto(): Boolean = stopProcess(getProcessId(PERFETTO))
+
+ /**
+ * Check if perfetto process is running or not.
+ *
+ * @return true if perfetto is running otherwise false.
+ */
+ public fun isPerfettoRunning(): Boolean {
+ val pid = getProcessId(PERFETTO)
+ return !pid.isNullOrEmpty()
+ }
+
+ /**
+ * Sets up `traced` and `traced_probes` if necessary.
+ */
+ private fun setupTracedAndProbes() {
+ if (!unbundled) {
+ return
+ }
+
+ // Run `traced` and `traced_probes` in background mode.
+
+ // Setup traced
+ val tracedCmd = "$UNBUNDLED_ENV_PREFIX $tracedShellPath --background"
+ Log.i(LOG_TAG, "Starting traced cmd: $tracedCmd")
+ Shell.executeScript(tracedCmd)
+
+ // Setup traced_probes
+ val tracedProbesCmd = "$UNBUNDLED_ENV_PREFIX $tracedProbesShellPath --background"
+ Log.i(LOG_TAG, "Starting traced_probes cmd: $tracedProbesCmd")
+ Shell.executeScript(tracedProbesCmd)
+ }
+
+ /**
+ * @return the shell command that can be used to start Perfetto.
+ */
+ private fun perfettoCommand(configFilePath: String, isTextProtoConfig: Boolean): String {
+ val outputPath = getPerfettoTmpOutputFilePath()
+ var command = if (!unbundled) (
+ // Bundled perfetto reads configuration from stdin.
+ "cat $configFilePath | perfetto --background -c - -o $outputPath"
+ ) else {
+ // Unbundled perfetto can read configuration from a file that it has permissions to
+ // read from. This because it assumes the identity of the shell and therefore has
+ // access to /data/local/tmp directory.
+ "$UNBUNDLED_ENV_PREFIX $perfettoShellPath --background" +
+ " -c $configFilePath" +
+ " -o $outputPath"
+ }
+
+ if (isTextProtoConfig) {
+ command += PERFETTO_TXT_PROTO_ARG
+ }
+ return command
+ }
+
+ /**
+ * @return the [String] path to the temporary output file used to store the trace file
+ * during collection.
+ */
+ private fun getPerfettoTmpOutputFilePath(): String {
+ return if (unbundled) {
+ UNBUNDLED_TEMP_OUTPUT_FILE
+ } else {
+ PERFETTO_TMP_OUTPUT_FILE
+ }
+ }
+
+ /**
+ * @return the [String] process id for a given process name.
+ */
+ private fun getProcessId(processName: String): String? {
+ return try {
+ val processId = Shell.executeCommand("pidof $processName")
+ // We want to pick the most recent invocation of the command.
+ // This is because we may have more than once instance of the process.
+ val pid = processId.split(" ").lastOrNull()?.trim()
+ Log.d(LOG_TAG, "Process id is $pid")
+ pid
+ } catch (ioe: IOException) {
+ Log.i(LOG_TAG, "Unable to check process status due to $ioe.", ioe)
+ null
+ }
+ }
+
+ /**
+ * Utility method for stopping a process with a given `pid`.
+ *
+ * @return true if the process was stopped successfully.
+ */
+ private fun stopProcess(pid: String?): Boolean {
+ val stopOutput = Shell.executeCommand("kill -TERM $pid")
+ Log.i(LOG_TAG, "Stop command output - $stopOutput")
+ var waitCount = 0
+ while (isProcessRunning(pid)) {
+ Log.d(LOG_TAG, "Process ($pid) is running")
+ // timeout for process shutdown.
+ if (waitCount < PERFETTO_KILL_WAIT_COUNT) {
+ // Check every 100 millis if process stopped successfully.
+ userspaceTrace("wait for process kill") {
+ SystemClock.sleep(PERFETTO_KILL_WAIT_TIME_MS)
+ }
+ waitCount++
+ continue
+ }
+ return false
+ }
+ Log.i(LOG_TAG, "Process stopped successfully.")
+ return true
+ }
+
+ /**
+ * Utility method for checking if a process with a given `pid` is still running.
+ *
+ * @return true if still running.
+ */
+ @Throws(IOException::class)
+ private fun isProcessRunning(pid: String?): Boolean {
+ if (pid.isNullOrEmpty()) {
+ return false
+ }
+
+ Log.d(LOG_TAG, "Checking if $pid is running")
+
+ if (Build.VERSION.SDK_INT <= 23) {
+ TODO("pid checking for api 23 and below not yet supported")
+ }
+ val output = Shell.executeCommand("ps -A $pid")
+ return output.contains(pid)
+ }
+
+ /**
+ * Copy the temporary perfetto trace output file from /data/local/tmp/trace_output.pb to given
+ * destinationFile.
+ *
+ * @param destinationFile file to copy the perfetto output trace.
+ * @return true if the trace file copied successfully otherwise false.
+ */
+ private fun copyFileOutput(destinationFile: String): Boolean {
+ val sourceFile = getPerfettoTmpOutputFilePath()
+ val filePath = File(destinationFile)
+ val destDirectory = filePath.parent
+ if (destDirectory != null) {
+ // Check if the directory already exists
+ val directory = File(destDirectory)
+ if (!directory.exists()) {
+ val success = directory.mkdirs()
+ if (!success) {
+ Log.e(
+ LOG_TAG,
+ "Result output directory $destDirectory not created successfully."
+ )
+ return false
+ }
+ }
+ }
+
+ // Copy the collected trace from /data/misc/perfetto-traces/trace_output.pb to
+ // destinationFile
+ try {
+ val moveResult =
+ Shell.executeCommand("mv $sourceFile $destinationFile")
+ if (moveResult.isNotEmpty()) {
+ Log.e(
+ LOG_TAG,
+ """
+ Unable to move perfetto output file from $sourceFile
+ to $destinationFile due to $moveResult.
+ """.trimIndent()
+ )
+ return false
+ }
+ } catch (ioe: IOException) {
+ Log.e(
+ LOG_TAG,
+ "Unable to move the perfetto trace file to destination file.",
+ ioe
+ )
+ return false
+ }
+ return true
+ }
+
+ companion object {
+ internal const val LOG_TAG = "PerfettoCapture"
+
+ const val LOWEST_BUNDLED_VERSION_SUPPORTED = 29
+
+ // Command to start the perfetto tracing in the background.
+ // perfetto --background -c /data/misc/perfetto-traces/trace_config.pb -o
+ // /data/misc/perfetto-traces/trace_output.pb
+ private const val PERFETTO_TMP_OUTPUT_FILE = "/data/misc/perfetto-traces/trace_output.pb"
+
+ // Additional arg to indicate that the perfetto config file is text format.
+ private const val PERFETTO_TXT_PROTO_ARG = " --txt"
+
+ // Max wait count for checking if perfetto is stopped successfully
+ private const val PERFETTO_KILL_WAIT_COUNT = 30
+
+ // Check if perfetto is stopped every 100 millis.
+ private const val PERFETTO_KILL_WAIT_TIME_MS: Long = 100
+
+ // Path where perfetto, traced, and traced_probes are copied to if API >= 21 and < 29
+ private const val UNBUNDLED_PERFETTO_ROOT_DIR = "/data/local/tmp"
+
+ private const val UNBUNDLED_TEMP_OUTPUT_FILE =
+ "$UNBUNDLED_PERFETTO_ROOT_DIR/trace_output.pb"
+
+ // The environment variables necessary for unbundled perfetto (unnamed domain sockets).
+ // We need unnamed sockets here because SELinux dictates that we cannot use real, file
+ // based, domain sockets on Platform versions prior to S.
+ private const val UNBUNDLED_ENV_PREFIX =
+ "PERFETTO_PRODUCER_SOCK_NAME=@macrobenchmark_producer " +
+ "PERFETTO_CONSUMER_SOCK_NAME=@macrobenchmark_consumer"
+
+ // A set of supported ABIs
+ private val SUPPORTED_64_ABIS = setOf("arm64-v8a", "x86_64")
+ private val SUPPORTED_32_ABIS = setOf("armeabi")
+
+ // Perfetto executable
+ private const val PERFETTO = "perfetto"
+
+ // Trace daemon
+ private const val TRACED = "traced"
+
+ // Traced probes
+ private const val TRACED_PROBES = "traced_probes"
+
+ @TestOnly
+ fun isAbiSupported(): Boolean {
+ Log.d(LOG_TAG, "Supported ABIs: ${Build.SUPPORTED_ABIS.joinToString()}")
+ // Cuttlefish is x86 but claims support for x86_64
+ return !Build.MODEL.contains("Cuttlefish") && ( // b/180022458
+ Build.SUPPORTED_64_BIT_ABIS.any { SUPPORTED_64_ABIS.contains(it) } ||
+ Build.SUPPORTED_32_BIT_ABIS.any { SUPPORTED_32_ABIS.contains(it) }
+ )
+ }
+
+ @get:TestOnly
+ val tracedProbesShellPath: String by lazy {
+ createExecutable(TRACED_PROBES)
+ }
+
+ @get:TestOnly
+ val tracedShellPath: String by lazy {
+ createExecutable(TRACED)
+ }
+
+ @get:TestOnly
+ val perfettoShellPath: String by lazy {
+ createExecutable(PERFETTO)
+ }
+
+ fun createExecutable(tool: String): String {
+ userspaceTrace("create executable: $tool") {
+ if (!isAbiSupported()) {
+ throw IllegalStateException(
+ "Unsupported ABI (${Build.SUPPORTED_ABIS.joinToString()})"
+ )
+ }
+ val suffix = when {
+ // The order is important because `SUPPORTED_64_BIT_ABIS` lists all ABI
+ // supported by a device. That is why we need to search from most specific to
+ // least specific. For e.g. emulators claim to support aarch64, when in reality
+ // they can only support x86 or x86_64.
+ Build.SUPPORTED_64_BIT_ABIS.any { it.startsWith("x86_64") } -> "x86_64"
+ Build.SUPPORTED_64_BIT_ABIS.any { it.startsWith("arm64") } -> "aarch64"
+ Build.SUPPORTED_32_BIT_ABIS.any { it.startsWith("armeabi") } -> "arm"
+ else -> IllegalStateException(
+ // Perfetto does not support x86 binaries
+ "Unsupported ABI (${Build.SUPPORTED_ABIS.joinToString()})"
+ )
+ }
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val inputStream = instrumentation.context.assets.open("${tool}_$suffix")
+ return Shell.createRunnableExecutable(tool, inputStream)
+ }
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/UiState.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/UiState.kt
new file mode 100644
index 0000000..bcd94d2
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/UiState.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.perfetto
+
+import androidx.annotation.RestrictTo
+import perfetto.protos.Trace
+import perfetto.protos.TracePacket
+import perfetto.protos.UiState
+import java.io.File
+
+/**
+ * Convenience for UiState construction with specified package
+ */
+@Suppress("FunctionName") // constructor convenience
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun UiState(
+ timelineStart: Long?,
+ timelineEnd: Long?,
+ highlightPackage: String?
+) = UiState(
+ timeline_start_ts = timelineStart,
+ timeline_end_ts = timelineEnd,
+ highlight_process = highlightPackage?.run {
+ UiState.HighlightProcess(cmdline = highlightPackage)
+ }
+)
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun File.appendUiState(state: UiState) {
+ val traceToAppend = Trace(packet = listOf(TracePacket(ui_state = state)))
+ appendBytes(traceToAppend.encode())
+}
diff --git a/benchmark/benchmark-common/src/main/java/perfetto/protos/package-info.java b/benchmark/benchmark-common/src/main/java/perfetto/protos/package-info.java
new file mode 100644
index 0000000..fd5614d
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/perfetto/protos/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Hide the perfetto.protos package, as it's an implementation detail of benchmark
+ *
+ * Note: other attempts to use these protos in a benchmark process may clash with our
+ * definitions. If this becomes an issue, we can move ours to a separate, internal package.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package perfetto.protos;
+
+import androidx.annotation.RestrictTo;
diff --git a/benchmark/benchmark-macro/src/main/proto/perfetto_config.proto b/benchmark/benchmark-common/src/main/proto/perfetto_config.proto
similarity index 100%
rename from benchmark/benchmark-macro/src/main/proto/perfetto_config.proto
rename to benchmark/benchmark-common/src/main/proto/perfetto_config.proto
diff --git a/benchmark/benchmark-macro/src/main/proto/perfetto_trace.proto b/benchmark/benchmark-common/src/main/proto/perfetto_trace.proto
similarity index 100%
rename from benchmark/benchmark-macro/src/main/proto/perfetto_trace.proto
rename to benchmark/benchmark-common/src/main/proto/perfetto_trace.proto
diff --git a/benchmark/benchmark-junit4/api/current.txt b/benchmark/benchmark-junit4/api/current.txt
index 873f105..bb78174 100644
--- a/benchmark/benchmark-junit4/api/current.txt
+++ b/benchmark/benchmark-junit4/api/current.txt
@@ -19,5 +19,8 @@
method public static inline void measureRepeated(androidx.benchmark.junit4.BenchmarkRule, kotlin.jvm.functions.Function1<? super androidx.benchmark.junit4.BenchmarkRule.Scope,kotlin.Unit> block);
}
+ public final class PerfettoRuleKt {
+ }
+
}
diff --git a/benchmark/benchmark-junit4/api/public_plus_experimental_current.txt b/benchmark/benchmark-junit4/api/public_plus_experimental_current.txt
index 873f105..bb78174 100644
--- a/benchmark/benchmark-junit4/api/public_plus_experimental_current.txt
+++ b/benchmark/benchmark-junit4/api/public_plus_experimental_current.txt
@@ -19,5 +19,8 @@
method public static inline void measureRepeated(androidx.benchmark.junit4.BenchmarkRule, kotlin.jvm.functions.Function1<? super androidx.benchmark.junit4.BenchmarkRule.Scope,kotlin.Unit> block);
}
+ public final class PerfettoRuleKt {
+ }
+
}
diff --git a/benchmark/benchmark-junit4/api/restricted_current.txt b/benchmark/benchmark-junit4/api/restricted_current.txt
index c2d8056..8ffdd9b 100644
--- a/benchmark/benchmark-junit4/api/restricted_current.txt
+++ b/benchmark/benchmark-junit4/api/restricted_current.txt
@@ -20,5 +20,13 @@
method public static inline void measureRepeated(androidx.benchmark.junit4.BenchmarkRule, kotlin.jvm.functions.Function1<? super androidx.benchmark.junit4.BenchmarkRule.Scope,kotlin.Unit> block);
}
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class PerfettoRule implements org.junit.rules.TestRule {
+ ctor public PerfettoRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ }
+
+ public final class PerfettoRuleKt {
+ }
+
}
diff --git a/benchmark/benchmark-junit4/build.gradle b/benchmark/benchmark-junit4/build.gradle
index 11d54c0..cd30ba8 100644
--- a/benchmark/benchmark-junit4/build.gradle
+++ b/benchmark/benchmark-junit4/build.gradle
@@ -40,6 +40,7 @@
implementation("androidx.tracing:tracing-ktx:1.0.0")
api("androidx.annotation:annotation:1.1.0")
+ androidTestImplementation(project(":internal-testutils-ktx"))
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testExtJunit)
}
diff --git a/benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/PerfettoRuleTest.kt b/benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/PerfettoRuleTest.kt
new file mode 100644
index 0000000..ab6003a
--- /dev/null
+++ b/benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/PerfettoRuleTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.junit4
+
+import android.os.Build
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SmallTest
+import androidx.testutils.verifyWithPolling
+import androidx.tracing.Trace
+import androidx.tracing.trace
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest // recording is expensive
+@RunWith(AndroidJUnit4::class)
+class PerfettoRuleTest {
+ @get:Rule
+ val perfettoRule = PerfettoRule()
+
+ @Test
+ fun tracingEnabled() {
+ trace("PerfettoCaptureTest") {
+ val traceShouldBeEnabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
+ verifyTraceEnable(traceShouldBeEnabled)
+ }
+
+ // NOTE: ideally, we'd validate the output file, but it's difficult to assert the
+ // behavior of the rule, since we can't really assert the result of a rule, which
+ // occurs after both @Test and @After
+ }
+}
+
+@SmallTest // not recording is cheap
+@RunWith(AndroidJUnit4::class)
+class PerfettoRuleControlTest {
+ @Test
+ fun tracingNotEnabled() {
+ verifyTraceEnable(false)
+ }
+}
+
+private fun verifyTraceEnable(enabled: Boolean) {
+ // We poll here, since we may need to wait for enable flags to propagate to apps
+ verifyWithPolling(
+ "Timeout waiting for Trace.isEnabled == $enabled",
+ periodMs = 50,
+ timeoutMs = 5000
+ ) {
+ Trace.isEnabled() == enabled
+ }
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/PerfettoRule.kt b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/PerfettoRule.kt
new file mode 100644
index 0000000..1c900ee
--- /dev/null
+++ b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/PerfettoRule.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.junit4
+
+import android.os.Build
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.benchmark.Outputs
+import androidx.benchmark.Outputs.dateToFileName
+import androidx.benchmark.perfetto.PerfettoCapture
+import androidx.benchmark.perfetto.PerfettoHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Add this rule to record a Perfetto trace for each test on Q+ devices.
+ *
+ * Relies on either AGP's additionalTestOutputDir copying, or (in Jetpack CI),
+ * `additionalTestOutputFile_***` copying.
+ *
+ * When invoked locally with Gradle, file will be copied to host path like the following:
+ *
+ * ```
+ * out/androidx/benchmark/benchmark-macro/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/<deviceName>/androidx.mypackage.TestClass_testMethod.perfetto-trace
+ * ```
+ *
+ * Note: if run from Studio, the file must be `adb pull`-ed manually, e.g.:
+ * ```
+ * > adb pull /storage/emulated/0/Android/data/androidx.mypackage.test/files/test_data/androidx.mypackage.TestClass_testMethod.trace
+ * ```
+ *
+ * You can check logcat for messages tagged "PerfettoRule:" for the path of each perfetto trace.
+ * ```
+ * > adb pull /storage/emulated/0/Android/data/mypackage.test/files/PerfettoCaptureTest.trace
+ * ```
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+public class PerfettoRule : TestRule {
+ override fun apply(
+ base: Statement,
+ description: Description
+ ): Statement = object : Statement() {
+ override fun evaluate() {
+ if (Build.VERSION.SDK_INT >= PerfettoHelper.LOWEST_BUNDLED_VERSION_SUPPORTED) {
+ val prefix = "${description.className}_${description.methodName}"
+ val suffix = dateToFileName()
+ val traceName = "${prefix}_$suffix.perfetto-trace"
+ PerfettoCapture(unbundled = false).recordAndReportFile(traceName) {
+ base.evaluate()
+ }
+ } else {
+ Log.d(TAG, "Perfetto trace skipped due to API level (${Build.VERSION.SDK_INT})")
+ base.evaluate()
+ }
+ }
+ }
+
+ internal companion object {
+ internal const val TAG = "PerfettoRule"
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.Q)
+internal fun PerfettoCapture.recordAndReportFile(traceName: String, block: () -> Unit) {
+ try {
+ Log.d(PerfettoRule.TAG, "Recording perfetto trace $traceName")
+ val targetPackage = InstrumentationRegistry
+ .getInstrumentation()
+ .targetContext
+ .packageName
+ start(packages = listOf(targetPackage))
+ block()
+ Outputs.writeFile(fileName = traceName, reportKey = "perfetto_trace") {
+ val destinationPath = it.absolutePath
+ stop(destinationPath)
+ Log.d(PerfettoRule.TAG, "Finished recording to $destinationPath")
+ }
+ } finally {
+ cancel()
+ }
+}
diff --git a/benchmark/benchmark-macro-junit4/api/current.txt b/benchmark/benchmark-macro-junit4/api/current.txt
index 5d2528d..1c277c8 100644
--- a/benchmark/benchmark-macro-junit4/api/current.txt
+++ b/benchmark/benchmark-macro-junit4/api/current.txt
@@ -10,8 +10,5 @@
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
}
- public final class PerfettoRuleKt {
- }
-
}
diff --git a/benchmark/benchmark-macro-junit4/api/public_plus_experimental_current.txt b/benchmark/benchmark-macro-junit4/api/public_plus_experimental_current.txt
index 5d2528d..1c277c8 100644
--- a/benchmark/benchmark-macro-junit4/api/public_plus_experimental_current.txt
+++ b/benchmark/benchmark-macro-junit4/api/public_plus_experimental_current.txt
@@ -10,8 +10,5 @@
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
}
- public final class PerfettoRuleKt {
- }
-
}
diff --git a/benchmark/benchmark-macro-junit4/api/restricted_current.txt b/benchmark/benchmark-macro-junit4/api/restricted_current.txt
index 431728d..1c277c8 100644
--- a/benchmark/benchmark-macro-junit4/api/restricted_current.txt
+++ b/benchmark/benchmark-macro-junit4/api/restricted_current.txt
@@ -10,13 +10,5 @@
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
}
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class PerfettoRule implements org.junit.rules.TestRule {
- ctor public PerfettoRule();
- method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
- }
-
- public final class PerfettoRuleKt {
- }
-
}
diff --git a/benchmark/benchmark-macro-junit4/src/androidTest/java/androidx/benchmark/macro/test/PerfettoRuleTest.kt b/benchmark/benchmark-macro-junit4/src/androidTest/java/androidx/benchmark/macro/test/PerfettoRuleTest.kt
deleted file mode 100644
index cb58a02..0000000
--- a/benchmark/benchmark-macro-junit4/src/androidTest/java/androidx/benchmark/macro/test/PerfettoRuleTest.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.test
-
-import android.os.Build
-import androidx.benchmark.macro.junit4.PerfettoRule
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.test.filters.SmallTest
-import androidx.testutils.verifyWithPolling
-import androidx.tracing.Trace
-import androidx.tracing.trace
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@LargeTest // recording is expensive
-@RunWith(AndroidJUnit4::class)
-class PerfettoRuleTest {
- @get:Rule
- val perfettoRule = PerfettoRule()
-
- @Test
- fun tracingEnabled() {
- trace("PerfettoCaptureTest") {
- val traceShouldBeEnabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
- verifyTraceEnable(traceShouldBeEnabled)
- }
-
- // NOTE: ideally, we'd validate the output file, but it's difficult to assert the
- // behavior of the rule, since we can't really assert the result of a rule, which
- // occurs after both @Test and @After
- }
-}
-
-@SmallTest // not recording is cheap
-@RunWith(AndroidJUnit4::class)
-class PerfettoRuleControlTest {
- @Test
- fun tracingNotEnabled() {
- verifyTraceEnable(false)
- }
-}
-
-private fun verifyTraceEnable(enabled: Boolean) {
- // We poll here, since we may need to wait for enable flags to propagate to apps
- verifyWithPolling(
- "Timeout waiting for Trace.isEnabled == $enabled",
- periodMs = 50,
- timeoutMs = 5000
- ) {
- Trace.isEnabled() == enabled
- }
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/PerfettoRule.kt b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/PerfettoRule.kt
deleted file mode 100644
index fc36ac4..0000000
--- a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/PerfettoRule.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.junit4
-
-import android.os.Build
-import android.util.Log
-import androidx.annotation.RequiresApi
-import androidx.annotation.RestrictTo
-import androidx.benchmark.Outputs
-import androidx.benchmark.Outputs.dateToFileName
-import androidx.benchmark.macro.perfetto.PerfettoCapture
-import androidx.test.platform.app.InstrumentationRegistry
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-
-/**
- * Add this rule to record a Perfetto trace for each test on Q+ devices.
- *
- * Relies on either AGP's additionalTestOutputDir copying, or (in Jetpack CI),
- * `additionalTestOutputFile_***` copying.
- *
- * When invoked locally with Gradle, file will be copied to host path like the following:
- *
- * ```
- * out/androidx/benchmark/benchmark-macro/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/<deviceName>/androidx.mypackage.TestClass_testMethod.perfetto-trace
- * ```
- *
- * Note: if run from Studio, the file must be `adb pull`-ed manually, e.g.:
- * ```
- * > adb pull /storage/emulated/0/Android/data/androidx.mypackage.test/files/test_data/androidx.mypackage.TestClass_testMethod.trace
- * ```
- *
- * You can check logcat for messages tagged "PerfettoRule:" for the path of each perfetto trace.
- * ```
- * > adb pull /storage/emulated/0/Android/data/mypackage.test/files/PerfettoCaptureTest.trace
- * ```
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public class PerfettoRule : TestRule {
- override fun apply(
- base: Statement,
- description: Description
- ): Statement = object : Statement() {
- override fun evaluate() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- val prefix = "${description.className}_${description.methodName}"
- val suffix = dateToFileName()
- val traceName = "${prefix}_$suffix.perfetto-trace"
- PerfettoCapture().recordAndReportFile(traceName) {
- base.evaluate()
- }
- } else {
- Log.d(TAG, "Perfetto trace skipped due to API level (${Build.VERSION.SDK_INT})")
- base.evaluate()
- }
- }
- }
-
- internal companion object {
- internal const val TAG = "PerfettoRule"
- }
-}
-
-@RequiresApi(Build.VERSION_CODES.Q)
-internal fun PerfettoCapture.recordAndReportFile(traceName: String, block: () -> Unit) {
- try {
- Log.d(PerfettoRule.TAG, "Recording perfetto trace $traceName")
- val targetPackage = InstrumentationRegistry
- .getInstrumentation()
- .targetContext
- .packageName
- start(packages = listOf(targetPackage))
- block()
- Outputs.writeFile(fileName = traceName, reportKey = "perfetto_trace") {
- val destinationPath = it.absolutePath
- stop(destinationPath)
- Log.d(PerfettoRule.TAG, "Finished recording to $destinationPath")
- }
- } finally {
- cancel()
- }
-}
diff --git a/benchmark/benchmark-macro/api/current.txt b/benchmark/benchmark-macro/api/current.txt
index 1bed5d9..1ee96be0 100644
--- a/benchmark/benchmark-macro/api/current.txt
+++ b/benchmark/benchmark-macro/api/current.txt
@@ -4,7 +4,7 @@
@RequiresApi(29) public final class Api29Kt {
}
- public abstract sealed class CompilationMode {
+ @RequiresApi(21) public abstract sealed class CompilationMode {
}
public static final class CompilationMode.BaselineProfile extends androidx.benchmark.macro.CompilationMode {
@@ -28,10 +28,7 @@
public final class CompilationModeKt {
}
- public final class ConfigurationErrorKt {
- }
-
- public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
+ @RequiresApi(21) public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
ctor public FrameTimingMetric();
}
@@ -41,7 +38,7 @@
public final class MacrobenchmarkKt {
}
- public final class MacrobenchmarkScope {
+ @RequiresApi(21) public final class MacrobenchmarkScope {
ctor public MacrobenchmarkScope(String packageName, boolean launchWithClearTask);
method public void dropKernelPageCache();
method public void killProcess();
@@ -50,7 +47,7 @@
method public void startActivityAndWait(android.content.Intent intent);
}
- public abstract sealed class Metric {
+ @RequiresApi(21) public abstract sealed class Metric {
}
public final class MetricKt {
@@ -72,21 +69,5 @@
public final class TagKt {
}
- public final class UserspaceTracingKt {
- }
-
-}
-
-package androidx.benchmark.macro.perfetto {
-
- public final class PerfettoConfigKt {
- }
-
- public final class ShellUtilsKt {
- }
-
- public final class UiStateKt {
- }
-
}
diff --git a/benchmark/benchmark-macro/api/public_plus_experimental_current.txt b/benchmark/benchmark-macro/api/public_plus_experimental_current.txt
index 1bed5d9..1ee96be0 100644
--- a/benchmark/benchmark-macro/api/public_plus_experimental_current.txt
+++ b/benchmark/benchmark-macro/api/public_plus_experimental_current.txt
@@ -4,7 +4,7 @@
@RequiresApi(29) public final class Api29Kt {
}
- public abstract sealed class CompilationMode {
+ @RequiresApi(21) public abstract sealed class CompilationMode {
}
public static final class CompilationMode.BaselineProfile extends androidx.benchmark.macro.CompilationMode {
@@ -28,10 +28,7 @@
public final class CompilationModeKt {
}
- public final class ConfigurationErrorKt {
- }
-
- public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
+ @RequiresApi(21) public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
ctor public FrameTimingMetric();
}
@@ -41,7 +38,7 @@
public final class MacrobenchmarkKt {
}
- public final class MacrobenchmarkScope {
+ @RequiresApi(21) public final class MacrobenchmarkScope {
ctor public MacrobenchmarkScope(String packageName, boolean launchWithClearTask);
method public void dropKernelPageCache();
method public void killProcess();
@@ -50,7 +47,7 @@
method public void startActivityAndWait(android.content.Intent intent);
}
- public abstract sealed class Metric {
+ @RequiresApi(21) public abstract sealed class Metric {
}
public final class MetricKt {
@@ -72,21 +69,5 @@
public final class TagKt {
}
- public final class UserspaceTracingKt {
- }
-
-}
-
-package androidx.benchmark.macro.perfetto {
-
- public final class PerfettoConfigKt {
- }
-
- public final class ShellUtilsKt {
- }
-
- public final class UiStateKt {
- }
-
}
diff --git a/benchmark/benchmark-macro/api/restricted_current.txt b/benchmark/benchmark-macro/api/restricted_current.txt
index 3568b81..3a19a6a 100644
--- a/benchmark/benchmark-macro/api/restricted_current.txt
+++ b/benchmark/benchmark-macro/api/restricted_current.txt
@@ -4,7 +4,7 @@
@RequiresApi(29) public final class Api29Kt {
}
- public abstract sealed class CompilationMode {
+ @RequiresApi(21) public abstract sealed class CompilationMode {
}
public static final class CompilationMode.BaselineProfile extends androidx.benchmark.macro.CompilationMode {
@@ -29,13 +29,10 @@
}
public final class CompilationModeKt {
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static boolean isSupportedWithVmSettings(androidx.benchmark.macro.CompilationMode);
+ method @RequiresApi(21) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static boolean isSupportedWithVmSettings(androidx.benchmark.macro.CompilationMode);
}
- public final class ConfigurationErrorKt {
- }
-
- public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
+ @RequiresApi(21) public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
ctor public FrameTimingMetric();
}
@@ -45,7 +42,7 @@
public final class MacrobenchmarkKt {
}
- public final class MacrobenchmarkScope {
+ @RequiresApi(21) public final class MacrobenchmarkScope {
ctor public MacrobenchmarkScope(String packageName, boolean launchWithClearTask);
method public void dropKernelPageCache();
method public void killProcess();
@@ -54,7 +51,7 @@
method public void startActivityAndWait(android.content.Intent intent);
}
- public abstract sealed class Metric {
+ @RequiresApi(21) public abstract sealed class Metric {
}
public final class MetricKt {
@@ -76,21 +73,5 @@
public final class TagKt {
}
- public final class UserspaceTracingKt {
- }
-
-}
-
-package androidx.benchmark.macro.perfetto {
-
- public final class PerfettoConfigKt {
- }
-
- public final class ShellUtilsKt {
- }
-
- public final class UiStateKt {
- }
-
}
diff --git a/benchmark/benchmark-macro/build.gradle b/benchmark/benchmark-macro/build.gradle
index 640b7cf..3b22be8 100644
--- a/benchmark/benchmark-macro/build.gradle
+++ b/benchmark/benchmark-macro/build.gradle
@@ -22,7 +22,6 @@
id("AndroidXPlugin")
id("com.android.library")
id("kotlin-android")
- id("com.squareup.wire")
}
android {
@@ -36,18 +35,6 @@
SupportConfigKt.getPrebuiltsRoot(project),
"androidx/traceprocessor/trace_processor_shell"
)
- main.assets.srcDirs += new File(
- SupportConfigKt.getPrebuiltsRoot(project),
- "androidx/traceprocessor/perfetto"
- )
- main.assets.srcDirs += new File(
- SupportConfigKt.getPrebuiltsRoot(project),
- "androidx/traceprocessor/traced"
- )
- main.assets.srcDirs += new File(
- SupportConfigKt.getPrebuiltsRoot(project),
- "androidx/traceprocessor/traced_probes"
- )
androidTest.assets.srcDirs += new File(
SupportConfigKt.getPrebuiltsRoot(project),
"androidx/traceprocessor/testdata"
@@ -55,18 +42,6 @@
}
}
-wire {
- kotlin {}
-
- // prune unused config components which have deprecated fields
- prune 'perfetto.protos.TraceConfig.IncidentReportConfig'
- prune 'perfetto.protos.ProcessStatsConfig.Quirks'
-
- sourcePath {
- srcDir 'src/main/proto'
- }
-}
-
dependencies {
api(libs.junit)
api(libs.kotlinStdlib)
@@ -77,7 +52,6 @@
implementation("androidx.tracing:tracing-ktx:1.0.0")
implementation(libs.testCore)
implementation(libs.testUiautomator)
- implementation(libs.wireRuntime)
androidTestImplementation(project(":internal-testutils-ktx"))
androidTestImplementation(project(":activity:activity-ktx"))
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/CompilationModeTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/CompilationModeTest.kt
index 84d0a07..f74887b 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/CompilationModeTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/CompilationModeTest.kt
@@ -16,9 +16,10 @@
package androidx.benchmark.macro
+import androidx.benchmark.Shell
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -29,12 +30,12 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
+@SdkSuppress(minSdkVersion = 21)
public class CompilationModeTest {
private val vmRunningInterpretedOnly: Boolean
init {
- val device = InstrumentationRegistry.getInstrumentation().device()
- val getProp = device.executeShellCommand("getprop dalvik.vm.extra-opts")
+ val getProp = Shell.executeCommand("getprop dalvik.vm.extra-opts")
vmRunningInterpretedOnly = getProp.contains("-Xusejit:false")
}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ConfigurationErrorTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ConfigurationErrorTest.kt
deleted file mode 100644
index 0889c6a..0000000
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ConfigurationErrorTest.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-import kotlin.test.assertFailsWith
-import kotlin.test.assertNotNull
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-public class ConfigurationErrorTest {
- @Test
- public fun constructor_valid() {
- ConfigurationError(
- id = "ID",
- summary = "summary",
- message = "message"
- )
- }
-
- @Test
- public fun constructor_throw() {
- assertFailsWith<IllegalArgumentException> {
- ConfigurationError(
- id = "idCanNotHaveLowercase", // invalid, IDs always uppercase
- summary = "summary",
- message = "message"
- )
- }
-
- assertFailsWith<IllegalArgumentException> {
- ConfigurationError(
- id = "i_d", // invalid, IDs can't have underscores
- summary = "summary",
- message = "message"
- )
- }
- assertFailsWith<IllegalArgumentException> {
- ConfigurationError(
- id = "ID",
- summary = "summary\nsummary", // invalid, summary is single line
- message = "message"
- )
- }
- }
-
- @Test
- public fun checkAndGetSuppressionState_empty() {
- // no throw or suppressed error
- assertNull(listOf<ConfigurationError>().checkAndGetSuppressionState(setOf()))
- }
-
- @Test
- public fun checkAndGetSuppressionState_suppressed() {
- // two suppressed errors
- val suppression = listOf(
- ConfigurationError(
- id = "ID1",
- summary = "summary1",
- message = "message1"
- ),
- ConfigurationError(
- id = "ID2",
- summary = "summary2",
- message = "message2"
- )
- ).checkAndGetSuppressionState(setOf("ID1", "ID2"))
-
- assertNotNull(suppression)
- assertEquals("ID1_ID2_", suppression.prefix)
- assertEquals(
- """
- |WARNING: summary1
- | message1
-
- |WARNING: summary2
- | message2
-
- """.trimMargin(),
- suppression.warningMessage
- )
- }
-
- @Test
- public fun checkAndGetSuppressionState_unsuppressed() {
- // one unsuppressed error, so throw
- val exception = assertFailsWith<AssertionError> {
- listOf(
- ConfigurationError(
- id = "ID1",
- summary = "summary1",
- message = "message1"
- ),
- ConfigurationError(
- id = "ID2",
- summary = "summary2",
- message = "message2"
- )
- ).checkAndGetSuppressionState(setOf("ID1"))
- }
-
- val message = exception.message!!
- assertTrue(message.contains("ERRORS (not suppressed): ID2"))
- assertTrue(message.contains("WARNINGS (suppressed): ID1"))
- assertTrue(
- message.contains(
- """
- |
- |ERROR: summary2
- | message2
- |
- """.trimMargin()
- )
- )
- // suppression warning should contain *both* errors to be suppressed
- assertTrue(
- message.contains(
- """testInstrumentationRunnerArguments""" +
- """["androidx.benchmark.suppressErrors"] = "ID1,ID2""""
- )
- )
- }
-}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/FileLinkingRule.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/FileLinkingRule.kt
index 8214ab4..bfe4fb6 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/FileLinkingRule.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/FileLinkingRule.kt
@@ -18,8 +18,8 @@
import androidx.benchmark.InstrumentationResults
import androidx.benchmark.Outputs
-import androidx.benchmark.macro.perfetto.UiState
-import androidx.benchmark.macro.perfetto.appendUiState
+import androidx.benchmark.perfetto.UiState
+import androidx.benchmark.perfetto.appendUiState
import org.junit.rules.RuleChain
import org.junit.rules.TestRule
import org.junit.runner.Description
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
index c86c136..b02abfd 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
@@ -19,8 +19,7 @@
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
-import androidx.benchmark.macro.perfetto.isPackageAlive
-import androidx.benchmark.macro.perfetto.isShellSessionRooted
+import androidx.benchmark.Shell
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
@@ -63,9 +62,9 @@
val scope = MacrobenchmarkScope(Packages.TARGET, launchWithClearTask = true)
scope.pressHome()
scope.startActivityAndWait()
- assertTrue(device.isPackageAlive(Packages.TARGET))
+ assertTrue(Shell.isPackageAlive(Packages.TARGET))
scope.killProcess()
- assertFalse(device.isPackageAlive(Packages.TARGET))
+ assertFalse(Shell.isPackageAlive(Packages.TARGET))
}
@SdkSuppress(minSdkVersion = 24) // TODO: define behavior for older platforms
@@ -101,12 +100,12 @@
intent.setPackage(Packages.TARGET)
intent.action = "${Packages.TARGET}.NOT_EXPORTED_ACTIVITY"
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- if (device.isShellSessionRooted() || Build.VERSION.SDK_INT <= 23) {
+ if (Shell.isSessionRooted() || Build.VERSION.SDK_INT <= 23) {
// while device and adb session are both rooted, doesn't throw
// TODO: verify whether pre-23 behavior requires userdebug device, only tested with
// emulator so far
scope.startActivityAndWait(intent)
+ val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
assertTrue(device.hasObject(By.text("NOT EXPORTED ACTIVITY")))
} else {
// should throw, warning to set exported = true
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
index 8efef1c..114cafd 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
@@ -25,6 +25,7 @@
import kotlin.test.assertTrue
@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = 21)
@SmallTest
class MacrobenchmarkTest {
@Test
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/OutputsTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/OutputsTest.kt
index 1a72cd3..a56635d7 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/OutputsTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/OutputsTest.kt
@@ -18,6 +18,7 @@
import androidx.benchmark.Outputs
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
@@ -46,6 +47,7 @@
}
@Test
+ @SdkSuppress(minSdkVersion = 21) // executeShellCommand
public fun dirUsableByAppAndShell_writeAppReadShell() {
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val dir = Outputs.dirUsableByAppAndShell
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ShellBehaviorTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ShellBehaviorTest.kt
deleted file mode 100644
index 820fb939..0000000
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ShellBehaviorTest.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro
-
-import android.os.Build
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
-import kotlin.test.assertTrue
-
-/**
- * This class collects tests of strange shell behavior, for the purpose of documenting
- * and validating how general the problems are.
- */
-@MediumTest
-@SdkSuppress(minSdkVersion = 21)
-@RunWith(AndroidJUnit4::class)
-class ShellBehaviorTest {
- private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
-
- @Test
- fun pidof() {
- // Should only be one process - this one!
- val pidofString = device.executeShellCommand("pidof ${Packages.TEST}").trim()
-
- when {
- Build.VERSION.SDK_INT < 23 -> {
- // command doesn't exist (and we don't try and read stderr here)
- assertEquals("", pidofString)
- }
- Build.VERSION.SDK_INT == 23 -> {
- // on API 23 specifically, pidof prints... all processes, ignoring the arg...
- assertTrue(pidofString.contains(" "))
- }
- else -> {
- assertNotNull(pidofString.toLongOrNull(), "Error, can't parse $pidofString")
- }
- }
- }
-
- @Test
- fun psDashA() {
- val output = device.executeShellCommand("ps -A").trim()
- when {
- Build.VERSION.SDK_INT <= 23 -> {
- // doesn't correctly handle -A
- assertTrue(
- output.matches(Regex("USER.+PID.+PPID.+VSIZE.+RSS.+WCHAN.+PC.+NAME")),
- "expected no processes from 'ps -A', saw $output"
- )
- }
- Build.VERSION.SDK_INT in 24..25 -> {
- // still doesn't support, but useful error at least
- assertEquals("bad pid '-A'", output)
- }
- else -> {
- // ps -A should work - expect several processes including this one
- val processes = output.split("\n")
- assertTrue(processes.size > 5)
- assertTrue(processes.any { it.endsWith(Packages.TEST) })
- }
- }
- }
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt
index c5d3ca2..cfb5e4e 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt
@@ -18,9 +18,9 @@
import android.content.Intent
import androidx.annotation.RequiresApi
-import androidx.benchmark.macro.perfetto.PerfettoCaptureWrapper
-import androidx.benchmark.macro.perfetto.PerfettoHelper.Companion.isAbiSupported
-import androidx.benchmark.macro.perfetto.createTempFileFromAsset
+import androidx.benchmark.Outputs
+import androidx.benchmark.perfetto.PerfettoCaptureWrapper
+import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.MediumTest
@@ -32,6 +32,7 @@
import org.junit.Assume.assumeTrue
import org.junit.Test
import org.junit.runner.RunWith
+import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
@@ -153,3 +154,15 @@
)!!
return metric.getMetrics(packageName, tracePath)
}
+
+@Suppress("SameParameterValue")
+internal fun createTempFileFromAsset(prefix: String, suffix: String): File {
+ val file = File.createTempFile(prefix, suffix, Outputs.dirUsableByAppAndShell)
+ InstrumentationRegistry
+ .getInstrumentation()
+ .context
+ .assets
+ .open(prefix + suffix)
+ .copyTo(file.outputStream())
+ return file
+}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/UserspaceTracingTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/UserspaceTracingTest.kt
deleted file mode 100644
index d1d5423..0000000
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/UserspaceTracingTest.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import perfetto.protos.TracePacket
-import perfetto.protos.TrackDescriptor
-import perfetto.protos.TrackEvent
-import kotlin.test.assertNotNull
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class UserspaceTracingTest {
- @Before
- @After
- fun setup() {
- UserspaceTracing.commitToTrace() // reset
- }
-
- @Test
- fun emptyTrace() {
- val beforeTime = System.nanoTime()
- UserspaceTracing.commitToTrace() // reset, and trigger first event in next trace
- val afterTime = System.nanoTime()
-
- val trace = UserspaceTracing.commitToTrace() // capture trace
-
- assertEquals(1, trace.packet.size)
- val packet = trace.packet.first()
-
- assertTrue(packet.timestamp in beforeTime..afterTime)
- assertEquals(
- packet,
- TracePacket(
- timestamp = packet.timestamp,
- timestamp_clock_id = 3,
- incremental_state_cleared = true,
- track_descriptor = TrackDescriptor(
- uuid = packet.track_descriptor?.uuid,
- name = "Macrobenchmark"
- )
- )
- )
- }
-
- @Test
- fun minimalTrace() {
- val beforeTime = System.nanoTime()
- userspaceTrace("test trace section") {}
- val afterTime = System.nanoTime()
-
- val trace = UserspaceTracing.commitToTrace()
-
- assertEquals(3, trace.packet.size)
-
- val descriptor = trace.packet.first().track_descriptor
- assertNotNull(descriptor) // verify track
-
- trace.packet[1].apply {
- assert(timestamp in beforeTime..afterTime)
- assertEquals(
- TracePacket(
- timestamp = timestamp,
- timestamp_clock_id = 3,
- trusted_packet_sequence_id = trusted_packet_sequence_id,
- track_event = TrackEvent(
- type = TrackEvent.Type.TYPE_SLICE_BEGIN,
- track_uuid = descriptor.uuid,
- categories = listOf("benchmark"),
- name = "test trace section"
- )
- ),
- this
- )
- }
- trace.packet[2].apply {
- assert(timestamp in beforeTime..afterTime)
- assertEquals(
- TracePacket(
- timestamp = timestamp,
- timestamp_clock_id = 3,
- trusted_packet_sequence_id = trusted_packet_sequence_id,
- track_event = TrackEvent(
- type = TrackEvent.Type.TYPE_SLICE_END,
- track_uuid = descriptor.uuid,
- )
- ),
- this
- )
- }
- }
-}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AtraceTagTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AtraceTagTest.kt
deleted file mode 100644
index 4dec363..0000000
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AtraceTagTest.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
-import org.junit.Assume
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertContains
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 21)
-@SmallTest
-class AtraceTagTest {
- private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- private val shellSessionRooted = device.isShellSessionRooted()
-
- @Test
- fun atraceListCategories_readable() {
- val results = device.executeShellCommand("atrace --list_categories")
- assertNotEquals("", results)
- }
-
- private fun getActualSupportedTags(): Set<String> {
- val results = device.executeShellCommand("atrace --list_categories")
-
- assertNotEquals("", results)
- val actualSupportedTags = results
- .split("\n")
- .map {
- println("captured $it")
- it.trim().split(" ").first()
- }
- .filter { it.isNotBlank() }
- .toSet()
-
- // verify able to read stdout with guaranteed tag
- assertContains(actualSupportedTags, "view")
-
- return actualSupportedTags
- }
-
- @Test
- fun atraceListCategories_unsupported() {
- val actualSupportedTags = getActualSupportedTags()
-
- val expectedUnsupportedTags = AtraceTag.unsupported(rooted = shellSessionRooted)
- val unexpectedTags = expectedUnsupportedTags.intersect(actualSupportedTags)
- assertEquals(setOf(), unexpectedTags, "Tags expected to be unsupported weren't")
- }
-
- @Test
- fun atraceListCategories_supported() {
- val actualSupportedTags = getActualSupportedTags()
- val expectedSupportedTags = AtraceTag.supported(rooted = shellSessionRooted)
- .map { it.tag }
- .toSet()
-
- val missingTags = expectedSupportedTags - actualSupportedTags
- assertEquals(setOf(), missingTags, "Tags expected to be supported weren't")
- }
-
- @Test
- fun shellSession_root() {
- Assume.assumeTrue(shellSessionRooted)
- }
-
- @Test
- fun shellSession_unroot() {
- Assume.assumeFalse(shellSessionRooted)
- }
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
index 083add8..13ba705 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,9 @@
import android.os.Build
import androidx.benchmark.macro.FileLinkingRule
import androidx.benchmark.macro.Packages
-import androidx.benchmark.macro.perfetto.PerfettoHelper.Companion.LOWEST_BUNDLED_VERSION_SUPPORTED
-import androidx.benchmark.macro.perfetto.PerfettoHelper.Companion.isAbiSupported
+import androidx.benchmark.perfetto.PerfettoCapture
+import androidx.benchmark.perfetto.PerfettoHelper.Companion.LOWEST_BUNDLED_VERSION_SUPPORTED
+import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
@@ -40,6 +41,12 @@
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
+/**
+ * Tests for PerfettoCapture
+ *
+ * Note: this test is defined in benchmark-macro instead of benchmark-common so that it can
+ * validate trace contents with PerfettoTraceProcessor
+ */
@SdkSuppress(minSdkVersion = 28) // Lowering blocked by b/131359446
@RunWith(AndroidJUnit4::class)
class PerfettoCaptureTest {
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoConfigTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoConfigTest.kt
deleted file mode 100644
index 7f7da87..0000000
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoConfigTest.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import androidx.benchmark.macro.Packages
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import perfetto.protos.DataSourceConfig
-import perfetto.protos.FtraceConfig
-import perfetto.protos.TraceConfig
-import kotlin.test.assertEquals
-import kotlin.test.assertFailsWith
-import kotlin.test.assertFalse
-import kotlin.test.assertNotNull
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class PerfettoConfigTest {
- @Test
- fun ftraceBasics() {
- val atraceApps = listOf(Packages.TEST)
- val ftraceDataSource = perfettoConfig(atraceApps)
- .data_sources
- .first { it.config?.name == "linux.ftrace" }
-
- assertNotNull(ftraceDataSource)
-
- val ftraceConfig = ftraceDataSource.config?.ftrace_config
- assertNotNull(ftraceConfig)
-
- assertEquals(listOf(Packages.TEST), ftraceConfig.atrace_apps)
-
- assertTrue(ftraceConfig.atrace_categories.contains("view"))
- assertFalse(ftraceConfig.atrace_categories.contains("webview"))
- assertFalse(ftraceConfig.atrace_categories.contains("memory"))
- }
-
- @Test
- fun validateAndEncode() {
- // default config shouldn't throw
- perfettoConfig(listOf(Packages.TEST)).validateAndEncode()
- }
-
- @Test
- fun validateAndEncode_invalidAtraceCategories() {
- val invalidConfig = TraceConfig(
- buffers = listOf(
- TraceConfig.BufferConfig(
- size_kb = 16384,
- fill_policy = TraceConfig.BufferConfig.FillPolicy.RING_BUFFER
- )
- ),
- data_sources = listOf(
- TraceConfig.DataSource(
- config = DataSourceConfig(
- name = "linux.ftrace",
- target_buffer = 0,
- ftrace_config = FtraceConfig(
- atrace_categories = listOf("bad_category")
- ),
- )
- )
- )
- )
- val exception = assertFailsWith<IllegalStateException> {
- invalidConfig.validateAndEncode()
- }
- assertTrue(exception.message!!.contains("bad_category"))
- }
-
- @SdkSuppress(maxSdkVersion = 27)
- @Test
- fun validateAndEncode_invalidWildcard() {
- val invalidConfig = TraceConfig(
- buffers = listOf(
- TraceConfig.BufferConfig(
- size_kb = 16384,
- fill_policy = TraceConfig.BufferConfig.FillPolicy.RING_BUFFER
- )
- ),
- data_sources = listOf(
- TraceConfig.DataSource(
- config = DataSourceConfig(
- name = "linux.ftrace",
- target_buffer = 0,
- ftrace_config = FtraceConfig(
- atrace_categories = listOf("view"),
- atrace_apps = listOf("*")
- ),
- )
- )
- )
- )
- val exception = assertFailsWith<IllegalStateException> {
- invalidConfig.validateAndEncode()
- }
- assertEquals(
- expected = "Support for wildcard (*) app matching in atrace added in API 28",
- actual = exception.message
- )
- }
-}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessorTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessorTest.kt
index 3726a28..c224a52 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessorTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessorTest.kt
@@ -16,9 +16,11 @@
package androidx.benchmark.macro.perfetto
-import androidx.benchmark.macro.device
-import androidx.benchmark.macro.perfetto.PerfettoHelper.Companion.isAbiSupported
+import androidx.benchmark.Shell
+import androidx.benchmark.macro.createTempFileFromAsset
+import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertTrue
@@ -30,14 +32,14 @@
import kotlin.test.assertFailsWith
@SmallTest
+@SdkSuppress(minSdkVersion = 21)
@RunWith(AndroidJUnit4::class)
class PerfettoTraceProcessorTest {
@Test
fun shellPath() {
assumeTrue(isAbiSupported())
val shellPath = PerfettoTraceProcessor.shellPath
- val device = InstrumentationRegistry.getInstrumentation().device()
- val out = device.executeShellCommand("$shellPath --version")
+ val out = Shell.executeCommand("$shellPath --version")
assertTrue(
"expect to get Perfetto version string, saw: $out",
out.contains("Perfetto v")
@@ -119,4 +121,4 @@
assets.toSet().containsAll(entries)
)
}
-}
+}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/ShellUtilsTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/ShellUtilsTest.kt
deleted file mode 100644
index 229ae61..0000000
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/ShellUtilsTest.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import androidx.benchmark.macro.Packages
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertNotNull
-
-@MediumTest
-@RunWith(AndroidJUnit4::class)
-class ShellUtilsTest {
- private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
-
- @Test
- fun trivial() {
- assertEquals("foo\n", device.executeShellScript("echo foo"))
-
- assertEquals(ShellOutput("foo\n", ""), device.executeShellScriptWithStderr("echo foo"))
- }
-
- @Test
- fun trivialStderr() {
- val shellOutput = device.executeShellScriptWithStderr("invalidCommand")
-
- assertEquals("", shellOutput.stdout)
-
- val stderr = shellOutput.stderr
-
- // sample stderr observed in manual testing:
- // API 23: "invalidCommand: not found"
- // API 30: "invalidCommand: inaccessible or not found"
- assertTrue(
- "unexpected stderr \"$stderr\"",
- stderr.contains("invalidCommand") && stderr.contains("not found")
- )
- }
-
- @SdkSuppress(minSdkVersion = 26) // xargs only available 26+
- @Test
- fun pipe_xargs() {
- // validate piping works with xargs
- assertEquals("foo\n", device.executeShellScript("echo foo | xargs echo $1"))
- }
-
- @SdkSuppress(minSdkVersion = 29) // `$(</dev/stdin)` doesn't work before 29
- @Test
- fun pipe_echo() {
- // validate piping works
- assertEquals("foo\n", device.executeShellScript("echo foo | echo $(</dev/stdin)"))
- }
-
- @SdkSuppress(minSdkVersion = 26) // xargs only available 26+
- @Test
- fun stdinArg_xargs() {
- // validate stdin to first command in script
- assertEquals("foo\n", device.executeShellScript("xargs echo $1", stdin = "foo"))
- }
-
- @SdkSuppress(minSdkVersion = 29) // `$(</dev/stdin)` doesn't work before 29
- @Test
- fun stdinArg_echo() {
- // validate stdin to first command in script
- assertEquals("foo\n", device.executeShellScript("echo $(</dev/stdin)", stdin = "foo"))
- }
-
- @Test
- fun multilineRedirect() {
- assertEquals(
- "foo\n",
- device.executeShellScript(
- """
- echo foo > /data/local/tmp/foofile
- cat /data/local/tmp/foofile
- """.trimIndent()
- )
- )
- }
-
- @SdkSuppress(minSdkVersion = 26) // xargs only available 26+
- @Test
- fun multilineRedirectStdin_xargs() {
- assertEquals(
- "foo\n",
- device.executeShellScript(
- """
- xargs echo $1 > /data/local/tmp/foofile
- cat /data/local/tmp/foofile
- """.trimIndent(),
- stdin = "foo"
- )
- )
- }
-
- @SdkSuppress(minSdkVersion = 29) // `$(</dev/stdin)` doesn't work before 29
- @Test
- fun multilineRedirectStdin_echo() {
- assertEquals(
- "foo\n",
- device.executeShellScript(
- """
- echo $(</dev/stdin) > /data/local/tmp/foofile
- cat /data/local/tmp/foofile
- """.trimIndent(),
- stdin = "foo"
- )
- )
- }
-
- @Test
- fun createRunnableExecutable_simpleScript() {
- val path = device.createRunnableExecutable(
- name = "myScript.sh",
- inputStream = "echo foo".byteInputStream()
- )
- try {
- assertEquals(
- "foo\n",
- device.executeShellCommand(path)
- )
- } finally {
- device.executeShellCommand("rm $path")
- }
- }
-
- @Test
- fun isPackageAlive() {
- // this package is certainly alive...
- assertNotNull(device.isPackageAlive(Packages.TEST))
-
- // this made up one shouldn't be
- assertNotNull(device.isPackageAlive("com.notalive.package.notarealapp"))
- }
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/UiStateTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/UiStateTest.kt
deleted file mode 100644
index 9d582fd..0000000
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/UiStateTest.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import androidx.benchmark.Outputs
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import okio.ByteString
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import perfetto.protos.Trace
-import perfetto.protos.TracePacket
-import perfetto.protos.UiState
-import java.io.File
-import kotlin.test.assertEquals
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-public class UiStateTest {
- @Test
- public fun uiStateConstructor() {
- assertEquals(
- UiState(
- timeline_start_ts = 1,
- timeline_end_ts = 100,
- UiState.HighlightProcess(cmdline = "test.package")
- ),
- UiState(
- timelineStart = 1,
- timelineEnd = 100,
- highlightPackage = "test.package"
- )
- )
- }
-
- @Test
- public fun uiStateCheck() {
- val uiState = UiState(
- timelineStart = 1,
- timelineEnd = 100,
- highlightPackage = "test.package"
- )
-
- val bytes = UiState.ADAPTER.encode(uiState)
- val uiStateParse = UiState.ADAPTER.decode(bytes)
- assertEquals(uiState, uiStateParse)
- }
-
- @Test
- public fun append() {
- val initial = Trace(
- packet = listOf(
- TracePacket(
- compressed_packets = ByteString.of(0, 1, 3)
- )
- )
- )
- val file = File.createTempFile("append", ".trace")
- file.writeBytes(Trace.ADAPTER.encode(initial))
- file.appendUiState(
- UiState(
- timelineStart = 0,
- timelineEnd = 1,
- highlightPackage = "test.package"
- )
- )
-
- val final = Trace.ADAPTER.decode(file.readBytes())
-
- val expected = Trace(
- packet = listOf(
- TracePacket(
- compressed_packets = ByteString.of(0, 1, 3)
- ),
- TracePacket(
- ui_state = UiState(
- timeline_start_ts = 0,
- timeline_end_ts = 1,
- UiState.HighlightProcess(cmdline = "test.package")
- )
- )
- )
- )
- assertEquals(expected, final)
- }
-
- @Test
- public fun actualTraceAppend() {
- val traceFile = createTempFileFromAsset("WarmStartup", ".trace")
- val initialSize = traceFile.readBytes().size
- traceFile.appendUiState(
- UiState(
- timelineStart = 2,
- timelineEnd = 4,
- highlightPackage = "test.package"
- )
- )
-
- val finalSize = traceFile.readBytes().size
-
- // file may shrink slightly due to re-encode, but shouldn't be significant
- assertTrue(finalSize > initialSize * 0.95f)
- }
-}
-
-@Suppress("SameParameterValue")
-internal fun createTempFileFromAsset(prefix: String, suffix: String): File {
- val file = File.createTempFile(prefix, suffix, Outputs.dirUsableByAppAndShell)
- InstrumentationRegistry
- .getInstrumentation()
- .context
- .assets
- .open(prefix + suffix)
- .copyTo(file.outputStream())
- return file
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
index 86a674e..a97ae5f 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
@@ -16,13 +16,14 @@
package androidx.benchmark.macro
-import android.app.Instrumentation
import android.util.Log
+import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
+import androidx.benchmark.DeviceInfo
+import androidx.benchmark.Shell
+import androidx.benchmark.macro.CompilationMode.SpeedProfile
import androidx.profileinstaller.ProfileInstallReceiver
import androidx.profileinstaller.ProfileInstaller
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
import org.junit.AssumptionViolatedException
/**
@@ -31,6 +32,7 @@
* For example, [SpeedProfile] will run a configurable number of profiling iterations to generate
* a profile, and use that to compile the target app.
*/
+@RequiresApi(21)
public sealed class CompilationMode(
// for modes other than [None], is argument passed `cmd package compile`
private val compileArgument: String?
@@ -94,24 +96,24 @@
*
* For more information: https://source.android.com/devices/tech/dalvik/jit-compiler
*/
+@RequiresApi(21)
internal fun CompilationMode.compile(packageName: String, block: () -> Unit) {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val device = instrumentation.device()
// Clear profile between runs.
Log.d(TAG, "Clearing profiles for $packageName")
- device.executeShellCommand("cmd package compile --reset $packageName")
-
+ Shell.executeCommand("cmd package compile --reset $packageName")
+ // Wait for the --reset to take affect.
+ Thread.sleep(1000)
if (this == CompilationMode.None || this == CompilationMode.Interpreted) {
return // nothing to do
}
if (this == CompilationMode.BaselineProfile) {
- // For baseline profiles, if the profileinstaller library is included in the APK, then we
+ // For baseline profiles, if the ProfileInstaller library is included in the APK, then we
// triggering this broadcast will cause the baseline profile to get installed
// synchronously, instead of waiting for the
val action = ProfileInstallReceiver.ACTION_INSTALL_PROFILE
// Use an explicit broadcast given the app was force-stopped.
val name = ProfileInstallReceiver::class.java.name
- val result = device.executeShellCommand("am broadcast -a $action $packageName/$name")
+ val result = Shell.executeCommand("am broadcast -a $action $packageName/$name")
.substringAfter("Broadcast completed: result=")
.trim()
.toIntOrNull()
@@ -148,6 +150,12 @@
)
}
}
+ // Kill Process
+ Log.d(TAG, "Killing process $packageName")
+ Shell.executeCommand("am force-stop $packageName")
+ // Compile
+ compilePackage(packageName)
+ Log.d(TAG, "$packageName is compiled.")
}
if (this is CompilationMode.SpeedProfile) {
repeat(this.warmupIterations) {
@@ -157,21 +165,12 @@
// is in the foreground, dump the profile, wait for another 5 secs before
// speed-profile compilation.
Thread.sleep(5000)
- val response = device.executeShellCommand("killall -s SIGUSR1 $packageName")
+ val response = Shell.executeCommand("killall -s SIGUSR1 $packageName")
if (response.isNotBlank()) {
Log.d(TAG, "Received dump profile response $response")
throw RuntimeException("Failed to dump profile for $packageName ($response)")
}
- Thread.sleep(5000)
- }
-
- Log.d(TAG, "Compiling $packageName ($this)")
- val response = device.executeShellCommand(
- "cmd package compile -f -m ${compileArgument()} $packageName"
- )
- if (!response.contains("Success")) {
- Log.d(TAG, "Received compile cmd response: $response")
- throw RuntimeException("Failed to compile $packageName ($response)")
+ compilePackage(packageName)
}
}
@@ -183,9 +182,9 @@
* @suppress
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RequiresApi(21)
public fun CompilationMode.isSupportedWithVmSettings(): Boolean {
- val device = InstrumentationRegistry.getInstrumentation().device()
- val getProp = device.executeShellCommand("getprop dalvik.vm.extra-opts")
+ val getProp = Shell.executeCommand("getprop dalvik.vm.extra-opts")
val vmRunningInterpretedOnly = getProp.contains("-Xusejit:false")
// true if requires interpreted, false otherwise
@@ -193,6 +192,7 @@
return vmRunningInterpretedOnly == interpreted
}
+@RequiresApi(21)
internal fun CompilationMode.assumeSupportedWithVmSettings() {
if (!isSupportedWithVmSettings()) {
throw AssumptionViolatedException(
@@ -217,6 +217,18 @@
}
}
-internal fun Instrumentation.device(): UiDevice {
- return UiDevice.getInstance(this)
+/**
+ * Compiles the application.
+ */
+@RequiresApi(21)
+internal fun CompilationMode.compilePackage(packageName: String) {
+ Log.d(TAG, "Compiling $packageName ($this)")
+ val response = Shell.executeCommand(
+ "cmd package compile -f -m ${compileArgument()} $packageName"
+ )
+ if (!response.contains("Success")) {
+ Log.d(TAG, "Received compile cmd response: $response")
+ throw RuntimeException("Failed to compile $packageName ($response)")
+ }
+ Thread.sleep(5000)
}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/ConfigurationError.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/ConfigurationError.kt
deleted file mode 100644
index 0758048..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/ConfigurationError.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro
-
-/**
- * Represents an error in configuration of a benchmark.
- */
-internal data class ConfigurationError(
- /**
- * All-caps, publicly visible ID for the error.
- *
- * Used for suppression via instrumentation arguments.
- */
- val id: String,
-
- /**
- * One-line summary of the problem.
- */
- val summary: String,
-
- /**
- * Multi-line, preformatted detailed description of the problem.
- */
- val message: String
-) {
- init {
- validateParams(id, summary)
- }
-
- companion object {
- internal fun validateParams(
- id: String,
- summary: String
- ) {
- require(!id.contains("[a-z]".toRegex())) {
- "IDs must be ALL-CAPs by convention (id=$id)"
- }
- require(!id.contains("_")) {
- "Use hyphen instead of underscore for consistency (id=$id)"
- }
- require(!summary.contains("\n")) {
- "Summary must be one line"
- }
- }
- }
-
- /**
- * Representation of suppressed errors during a running benchmark.
- */
- class SuppressionState(
- /**
- * Prefix for output data to mark as potentially invalid.
- */
- val prefix: String,
-
- /**
- * Warning message to present to the user.
- */
- val warningMessage: String
- )
-}
-
-internal fun conditionalError(
- hasError: Boolean,
- id: String,
- summary: String,
- message: String
-): ConfigurationError? {
- // validation done here *and* in constructor to ensure it happens even when error doesn't fire
- ConfigurationError.validateParams(id, summary)
- return if (hasError) {
- ConfigurationError(id, summary, message)
- } else null
-}
-
-internal fun List<ConfigurationError>.prettyPrint(prefix: String): String {
- return joinToString("\n") {
- prefix + it.summary + "\n" + it.message.prependIndent() + "\n"
- }
-}
-
-/**
- * Throw an AssertionError if the list contains an unsuppressed error, and return either a
- * SuppressionState if errors are suppressed, or null otherwise.
- */
-internal fun List<ConfigurationError>.checkAndGetSuppressionState(
- suppressedErrorIds: Set<String>,
-): ConfigurationError.SuppressionState? {
- val (suppressed, unsuppressed) = partition {
- suppressedErrorIds.contains(it.id)
- }
-
- val prefix = suppressed.joinToString("_") { it.id } + "_"
-
- val unsuppressedString = unsuppressed.joinToString(" ") { it.id }
- val suppressedString = suppressed.joinToString(" ") { it.id }
- val howToSuppressString = this.joinToString(",") { it.id }
-
- if (unsuppressed.isNotEmpty()) {
- throw AssertionError(
- """
- |ERRORS (not suppressed): $unsuppressedString
- |WARNINGS (suppressed): $suppressedString
- |
- |${unsuppressed.prettyPrint("ERROR: ")}
- |While you can suppress these errors (turning them into warnings)
- |PLEASE NOTE THAT EACH SUPPRESSED ERROR COMPROMISES ACCURACY
- |
- |// Sample suppression, in a benchmark module's build.gradle:
- |android {
- | defaultConfig {
- | testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "$howToSuppressString"
- | }
- |}
- """.trimMargin()
- )
- }
-
- if (suppressed.isEmpty()) {
- return null
- }
-
- return ConfigurationError.SuppressionState(prefix, suppressed.prettyPrint("WARNING: "))
-}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/DeviceInfo.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/DeviceInfo.kt
deleted file mode 100644
index a93a8b7..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/DeviceInfo.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro
-
-import android.content.Intent
-import android.content.IntentFilter
-import android.os.BatteryManager
-import android.os.Build
-import androidx.test.platform.app.InstrumentationRegistry
-import java.io.File
-
-internal object DeviceInfo {
- val isEmulator = Build.FINGERPRINT.startsWith("generic") ||
- Build.FINGERPRINT.startsWith("unknown") ||
- Build.MODEL.contains("google_sdk") ||
- Build.MODEL.contains("Emulator") ||
- Build.MODEL.contains("Android SDK built for x86") ||
- Build.MANUFACTURER.contains("Genymotion") ||
- Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic") ||
- "google_sdk" == Build.PRODUCT
-
- val isEngBuild = Build.FINGERPRINT.contains(":eng/")
-
- val isRooted =
- arrayOf(
- "/system/app/Superuser.apk",
- "/sbin/su",
- "/system/bin/su",
- "/system/xbin/su",
- "/data/local/xbin/su",
- "/data/local/bin/su",
- "/system/sd/xbin/su",
- "/system/bin/failsafe/su",
- "/data/local/su",
- "/su/bin/su"
- ).any { File(it).exists() }
-
- /**
- * Battery percentage required to avoid low battery warning.
- *
- * This number is supposed to be a conservative cutoff for when low-battery-triggered power
- * savings modes (such as disabling cores) may be enabled. It's possible that
- * [BatteryManager.EXTRA_BATTERY_LOW] is a better source of truth for this, but we want to be
- * conservative in case the device loses power slowly while benchmarks run.
- */
- const val MINIMUM_BATTERY_PERCENT = 25
-
- val initialBatteryPercent: Int
-
- /**
- * String summarizing device hardware and software, for bug reporting purposes.
- */
- val deviceSummaryString: String
-
- /**
- * General errors about device configuration, applicable to all types of benchmark.
- *
- * These errors indicate no performance tests should be performed on this device, in it's
- * current conditions.
- */
- val errors: List<ConfigurationError>
-
- init {
- val context = InstrumentationRegistry.getInstrumentation().targetContext
-
- val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
- initialBatteryPercent = context.registerReceiver(null, filter)?.run {
- val level = getIntExtra(BatteryManager.EXTRA_LEVEL, 100)
- val scale = getIntExtra(BatteryManager.EXTRA_SCALE, 100)
- level * 100 / scale
- } ?: 100
-
- deviceSummaryString = "DeviceInfo(Brand=${Build.BRAND}" +
- ", Model=${Build.MODEL}" +
- ", SDK=${Build.VERSION.SDK_INT}" +
- ", BuildFp=${Build.FINGERPRINT})"
-
- errors = listOfNotNull(
- conditionalError(
- hasError = isEngBuild,
- id = "ENG-BUILD",
- summary = "Running on Eng Build",
- message = """
- Benchmark is running on device flashed with a '-eng' build. Eng builds
- of the platform drastically reduce performance to enable testing
- changes quickly. For this reason they should not be used for
- benchmarking. Use a '-user' or '-userdebug' system image.
- """.trimIndent()
- ),
- conditionalError(
- hasError = isEmulator,
- id = "EMULATOR",
- summary = "Running on Emulator",
- message = """
- Benchmark is running on an emulator, which is not representative of
- real user devices. Use a physical device to benchmark. Emulator
- benchmark improvements might not carry over to a real user's
- experience (or even regress real device performance).
- """.trimIndent()
- ),
- conditionalError(
- hasError = initialBatteryPercent < MINIMUM_BATTERY_PERCENT,
- id = "LOW-BATTERY",
- summary = "Device has low battery ($initialBatteryPercent)",
- message = """
- When battery is low, devices will often reduce performance (e.g. disabling big
- cores) to save remaining battery. This occurs even when they are plugged in.
- Wait for your battery to charge to at least $MINIMUM_BATTERY_PERCENT%.
- Currently at $initialBatteryPercent%.
- """.trimIndent()
- )
- )
- }
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
index 56d76cb..5657ac5 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
@@ -20,14 +20,21 @@
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
+import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.benchmark.Arguments
import androidx.benchmark.BenchmarkResult
+import androidx.benchmark.ConfigurationError
+import androidx.benchmark.DeviceInfo
import androidx.benchmark.InstrumentationResults
import androidx.benchmark.ResultWriter
-import androidx.benchmark.macro.perfetto.PerfettoCaptureWrapper
-import androidx.benchmark.macro.perfetto.UiState
-import androidx.benchmark.macro.perfetto.appendUiState
+import androidx.benchmark.UserspaceTracing
+import androidx.benchmark.checkAndGetSuppressionState
+import androidx.benchmark.conditionalError
+import androidx.benchmark.perfetto.PerfettoCaptureWrapper
+import androidx.benchmark.perfetto.UiState
+import androidx.benchmark.perfetto.appendUiState
+import androidx.benchmark.userspaceTrace
import androidx.test.platform.app.InstrumentationRegistry
import java.io.File
@@ -92,6 +99,7 @@
*
* This function is a building block for public testing APIs
*/
+@RequiresApi(21)
private fun macrobenchmark(
uniqueName: String,
className: String,
@@ -247,6 +255,7 @@
*
* @suppress
*/
+@RequiresApi(21)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun macrobenchmarkWithStartupMode(
uniqueName: String,
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
index 192490e..939b9ce 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
@@ -18,8 +18,8 @@
import android.content.Intent
import android.util.Log
-import androidx.benchmark.macro.perfetto.executeShellScript
-import androidx.benchmark.macro.perfetto.executeShellScriptWithStderr
+import androidx.annotation.RequiresApi
+import androidx.benchmark.Shell
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import androidx.tracing.trace
@@ -28,6 +28,7 @@
* Provides access to common operations in app automation, such as killing the app,
* or navigating home.
*/
+@RequiresApi(21)
public class MacrobenchmarkScope(
private val packageName: String,
/**
@@ -88,7 +89,7 @@
Log.d(TAG, "Starting activity with command: $cmd")
// executeShellScript used to access stderr, and avoid need to escape special chars like `;`
- val result = device.executeShellScriptWithStderr(cmd)
+ val result = Shell.executeScriptWithStderr(cmd)
// Check for errors
result.stdout
@@ -133,7 +134,7 @@
* held in memory, such as during [cold startup](androidx.benchmark.macro.StartupMode.COLD).
*/
public fun dropKernelPageCache() {
- val result = device.executeShellScript(
+ val result = Shell.executeScript(
"echo 3 > /proc/sys/vm/drop_caches && echo Success || echo Failure"
).trim()
// User builds don't allow drop caches yet.
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
index f40148e..374e6d0 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
@@ -17,15 +17,15 @@
package androidx.benchmark.macro
import androidx.annotation.RequiresApi
+import androidx.benchmark.Shell
import androidx.benchmark.macro.perfetto.PerfettoResultsParser.parseStartupResult
import androidx.benchmark.macro.perfetto.PerfettoTraceProcessor
-import androidx.benchmark.macro.perfetto.isPackageAlive
import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
/**
* Metric interface.
*/
+@RequiresApi(21)
public sealed class Metric {
internal abstract fun configure(packageName: String)
@@ -41,6 +41,7 @@
internal abstract fun getMetrics(packageName: String, tracePath: String): MetricsWithUiState
}
+@RequiresApi(21)
public class FrameTimingMetric : Metric() {
private lateinit var packageName: String
private val helper = JankCollectionHelper()
@@ -63,8 +64,7 @@
// a designated setup block, we can get rid of this.
val instrumentation = InstrumentationRegistry.getInstrumentation()
if (instrumentation != null) {
- val device = UiDevice.getInstance(instrumentation)
- if (!device.isPackageAlive(packageName)) {
+ if (!Shell.isPackageAlive(packageName)) {
error(exception.message ?: "Assertion error, $packageName not running")
}
}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/UserspaceTracing.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/UserspaceTracing.kt
deleted file mode 100644
index 17f03b2..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/UserspaceTracing.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro
-
-import perfetto.protos.Trace
-import perfetto.protos.TracePacket
-import perfetto.protos.TrackDescriptor
-import perfetto.protos.TrackEvent
-
-/**
- * Userspace-buffer-based tracing api, that provides implementation for [userspaceTrace].
- *
- * This records while atrace isn't capturing by storing trace events manually in a list of
- * in-userspace-memory perfetto protos.
- *
- * After trace processing, the extra events (before _and_ after the measureBlock section of a
- * benchmark) can be added to the trace by calling [commitToTrace], and appending that to the
- * trace on-disk.
- */
-internal object UserspaceTracing {
- /**
- * All events emitted by the benchmark annotation should have the same value.
- * the value needs to not conflict with any sequence id emitted in the trace.
- * You can rely on the fact that traces will never contain an ID >
- * kMaxProducerID * kMaxWriterID (65536 * 1024) = 67108864. A high number will
- * be good enough without having to read the trace (unless something else
- * outside of your control is also emitting fake slices)
- */
- private const val TRUSTED_PACKET_SEQUENCE_ID: Int = 1_234_543_210
-
- /**
- * This is a unique ID of the track. The state is global and 64 bit. Tracks are
- * obtained by hashing pids/tids. Just picked an arbitrary 64 bit value. You have
- * more probability of winning the lottery than hitting a collision.
- */
- private const val UUID = 123_456_543_210L
-
- /**
- * Clock id for clock used by tracing events - this corresponds to CLOCK_MONOTONIC
- */
- private const val CLOCK_ID = 3
-
- /**
- * Name of track in for userspace tracing events
- */
- private const val TRACK_DESCRIPTOR_NAME = "Macrobenchmark"
-
- /**
- * Tag to enable post-filtering of events in the trace.
- */
- private val TRACK_EVENT_CATEGORIES = listOf("benchmark")
-
- private fun createInitialTracePacket() = TracePacket(
- timestamp = System.nanoTime(),
- timestamp_clock_id = CLOCK_ID,
- incremental_state_cleared = true,
- track_descriptor = TrackDescriptor(
- uuid = UUID,
- name = TRACK_DESCRIPTOR_NAME
- )
- )
-
- /**
- * For perf/simplicity, this isn't protected by a lock - it should only every be
- * accessed by the test thread, and dumped/reset between tests.
- */
- val events = mutableListOf(createInitialTracePacket())
-
- /**
- * Capture trace state, and return as a Trace(), which can be appended to a trace file.
- */
- fun commitToTrace(): Trace {
- val capturedEvents = events.toList()
- events.clear()
- events.add(createInitialTracePacket())
- return Trace(capturedEvents)
- }
-
- private fun startSection(label: String) {
- events.add(
- TracePacket(
- timestamp = System.nanoTime(),
- timestamp_clock_id = CLOCK_ID,
- trusted_packet_sequence_id = TRUSTED_PACKET_SEQUENCE_ID,
- track_event = TrackEvent(
- type = TrackEvent.Type.TYPE_SLICE_BEGIN,
- track_uuid = UUID,
- categories = TRACK_EVENT_CATEGORIES,
- name = label
- )
- )
- )
- }
-
- private fun endSection() {
- events.add(
- TracePacket(
- timestamp = System.nanoTime(),
- timestamp_clock_id = CLOCK_ID,
- trusted_packet_sequence_id = TRUSTED_PACKET_SEQUENCE_ID,
- track_event = TrackEvent(
- type = TrackEvent.Type.TYPE_SLICE_END,
- track_uuid = UUID,
- )
- )
- )
- }
-
- inline fun <T> trace(label: String, block: () -> T): T {
- startSection(label)
- return try {
- block()
- } finally {
- endSection()
- }
- }
-}
-
-internal inline fun <T> userspaceTrace(label: String, block: () -> T): T {
- return UserspaceTracing.trace(label, block)
-}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/AtraceTag.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/AtraceTag.kt
deleted file mode 100644
index ef21283..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/AtraceTag.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import android.os.Build
-
-/**
- * Enum representing set of all atrace tags used by macrobenchmark, and whether they're expected to
- * be supported on the current device.
- *
- * Note that this API assumes API >= 21, as that's the library's min API
- *
- * While supported tags could be collected from the local device (e.g. in `AtraceTagTest`), the
- * intent of this class is to track this information statically.
- */
-@Suppress("unused") // enums always accessed via values()
-internal enum class AtraceTag(
- val tag: String
-) {
- ActivityManager("am"),
- BinderDriver("binder_driver") {
- override fun supported(api: Int, rooted: Boolean): Boolean {
- return api >= 24
- }
- },
- Camera("camera"),
- Dalvik("dalvik"),
- Frequency("freq"),
- Graphics("gfx"),
- HardwareModules("hal"),
- Idle("idle"),
- Input("input"),
- MemReclaim("memreclaim"),
- Resources("res"),
- Scheduling("sched"),
- Synchronization("sync") {
- override fun supported(api: Int, rooted: Boolean): Boolean {
- return rooted || api >= 28
- }
- },
- View("view"),
- WebView("webview"),
- WindowManager("wm");
-
- /**
- * Return true if the tag is available on the specified api level, with specified shell
- * session root status.
- */
- open fun supported(api: Int, rooted: Boolean): Boolean {
- return true
- }
-
- companion object {
- fun supported(
- api: Int = Build.VERSION.SDK_INT,
- rooted: Boolean
- ): Set<AtraceTag> {
- return values()
- .filter { it.supported(api = api, rooted = rooted) }
- .toSet()
- }
-
- fun unsupported(
- api: Int = Build.VERSION.SDK_INT,
- rooted: Boolean
- ): Set<AtraceTag> {
- return values().toSet() - supported(api, rooted)
- }
- }
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCapture.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCapture.kt
deleted file mode 100644
index c286b81..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCapture.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import android.os.Build
-import androidx.annotation.RequiresApi
-import androidx.annotation.RestrictTo
-import androidx.benchmark.Outputs
-import androidx.benchmark.macro.userspaceTrace
-import java.io.File
-
-/**
- * Enables capturing a Perfetto trace from a test on Q+ devices.
- *
- * It's possible to support API 28, but there are a few issues to resolve:
- * - Use binary config protos
- * - May need to distribute perfetto binary, with atrace workaround
- * - App tags are not available, due to lack of `<profileable shell=true>`. Can potentially hack
- * around this for individual tags within test infra as needed.
- *
- * @suppress
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-@RequiresApi(21)
-public class PerfettoCapture(
- unbundled: Boolean = Build.VERSION.SDK_INT in 21..28
-) {
-
- private val helper: PerfettoHelper = PerfettoHelper(unbundled)
-
- /**
- * Kill perfetto process, if it is running.
- */
- public fun cancel() {
- if (helper.isPerfettoRunning()) {
- helper.stopPerfetto()
- }
- }
-
- /**
- * Start collecting perfetto trace.
- *
- * TODO: provide configuration options
- */
- public fun start(packages: List<String>) = userspaceTrace("start perfetto") {
- // Write binary proto to dir that shell can read
- // TODO: cache on disk
- val configProtoFile = File(Outputs.dirUsableByAppAndShell, "trace_config.pb")
- try {
- userspaceTrace("write config") {
- val atraceApps = if (Build.VERSION.SDK_INT <= 28) {
- packages
- } else {
- listOf("*")
- }
- configProtoFile.writeBytes(perfettoConfig(atraceApps).validateAndEncode())
- }
- userspaceTrace("start perfetto process") {
- helper.startCollecting(configProtoFile.absolutePath, false)
- }
- } finally {
- configProtoFile.delete()
- }
- }
-
- /**
- * Stop collection, and record trace to the specified file path.
- *
- * @param destinationPath Absolute path to write perfetto trace to. Must be shell-writable,
- * such as result of `context.getExternalFilesDir(null)` or other similar `external` paths.
- */
- public fun stop(destinationPath: String) = userspaceTrace("stop perfetto") {
- // Wait time determined empirically by running a trivial startup test (3 iterations) 200
- // times, and validating no metric capture failures.
- if (!helper.stopCollecting(500, destinationPath)) {
- // TODO: move internal failures to be exceptions
- throw IllegalStateException("Unable to store perfetto trace in $destinationPath")
- }
- }
-}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCaptureWrapper.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCaptureWrapper.kt
deleted file mode 100644
index 4c63fb6a..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCaptureWrapper.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import android.os.Build
-import android.util.Log
-import androidx.annotation.RequiresApi
-import androidx.benchmark.Outputs
-import androidx.benchmark.Outputs.dateToFileName
-import androidx.benchmark.PropOverride
-
-/**
- * Wrapper for [PerfettoCapture] which does nothing below L.
- */
-internal class PerfettoCaptureWrapper {
- private var capture: PerfettoCapture? = null
- private val TRACE_ENABLE_PROP = "persist.traced.enable"
-
- init {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- capture = PerfettoCapture()
- }
- }
-
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
- private fun start(packages: List<String>): Boolean {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- Log.d(PerfettoHelper.LOG_TAG, "Recording perfetto trace")
- capture?.start(packages)
- }
- return true
- }
-
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
- private fun stop(benchmarkName: String, iteration: Int): String {
- val iterString = iteration.toString().padStart(3, '0')
- val traceName = "${benchmarkName}_iter${iterString}_${dateToFileName()}.perfetto-trace"
- return Outputs.writeFile(fileName = traceName, reportKey = "perfetto_trace_$iterString") {
- capture!!.stop(it.absolutePath)
- }
- }
-
- fun record(
- benchmarkName: String,
- iteration: Int,
- packages: List<String>,
- block: () -> Unit
- ): String? {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
- return null // tracing currently not supported on this version
- }
-
- // Prior to Android 11 (R), a shell property must be set to enable perfetto tracing, see
- // https://perfetto.dev/docs/quickstart/android-tracing#starting-the-tracing-services
- val propOverride = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
- PropOverride(TRACE_ENABLE_PROP, "1")
- } else null
- try {
- propOverride?.forceValue()
- start(packages)
- block()
- return stop(benchmarkName, iteration)
- } finally {
- propOverride?.resetIfOverridden()
- }
- }
-}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoConfig.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoConfig.kt
deleted file mode 100644
index c28a518..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoConfig.kt
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import android.os.Build
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
-import perfetto.protos.DataSourceConfig
-import perfetto.protos.FtraceConfig
-import perfetto.protos.MeminfoCounters
-import perfetto.protos.ProcessStatsConfig
-import perfetto.protos.SysStatsConfig
-import perfetto.protos.TraceConfig
-import perfetto.protos.TraceConfig.BufferConfig
-import perfetto.protos.TraceConfig.BufferConfig.FillPolicy
-
-private fun ftraceDataSource(
- atraceApps: List<String>
-) = TraceConfig.DataSource(
- config = DataSourceConfig(
- name = "linux.ftrace",
- target_buffer = 0,
- ftrace_config = FtraceConfig(
- // These parameters affect only the kernel trace buffer size and how
- // frequently it gets moved into the userspace buffer defined above.
- buffer_size_kb = 16384,
- drain_period_ms = 250,
- ftrace_events = listOf(
- // We need to do process tracking to ensure kernel ftrace events targeted at short-lived
- // threads are associated correctly
- "task/task_newtask",
- "task/task_rename",
- "sched/sched_process_exit",
- "sched/sched_process_free",
-
- // Memory events
- "mm_event/mm_event_record",
- "kmem/rss_stat",
- "kmem/ion_heap_shrink",
- "kmem/ion_heap_grow",
- "ion/ion_stat",
- "oom/oom_score_adj_update",
-
- // Old (kernel) LMK
- "lowmemorykiller/lowmemory_kill",
- ),
- atrace_categories = listOf(
- AtraceTag.ActivityManager,
- AtraceTag.BinderDriver,
- AtraceTag.Camera,
- AtraceTag.Dalvik,
- AtraceTag.Frequency,
- AtraceTag.Graphics,
- AtraceTag.HardwareModules,
- AtraceTag.Idle,
- AtraceTag.Input,
- AtraceTag.MemReclaim,
- AtraceTag.Resources,
- AtraceTag.Scheduling,
- AtraceTag.Synchronization,
- AtraceTag.View,
- AtraceTag.WindowManager
- // "webview" not included to workaround b/190743595
- // "memory" not included as some Q devices requiring ftrace_event
- // configuration directly to collect this data. See b/171085599
- ).filter {
- // filter to only supported tags on unrooted build
- // TODO: use root-only tags as needed
- it.supported(api = Build.VERSION.SDK_INT, rooted = false)
- }.map {
- it.tag
- },
- atrace_apps = atraceApps
- )
- )
-)
-
-private val PROCESS_STATS_DATASOURCE = TraceConfig.DataSource(
- config = DataSourceConfig(
- name = "linux.process_stats",
- target_buffer = 1,
- process_stats_config = ProcessStatsConfig(
- proc_stats_poll_ms = 10000
- )
- )
-)
-
-private val LINUX_SYS_STATS_DATASOURCE = TraceConfig.DataSource(
- config = DataSourceConfig(
- name = "linux.sys_stats",
- target_buffer = 1,
- sys_stats_config = SysStatsConfig(
- meminfo_period_ms = 1000,
- meminfo_counters = listOf(
- MeminfoCounters.MEMINFO_MEM_TOTAL,
- MeminfoCounters.MEMINFO_MEM_FREE,
- MeminfoCounters.MEMINFO_MEM_AVAILABLE,
- MeminfoCounters.MEMINFO_BUFFERS,
- MeminfoCounters.MEMINFO_CACHED,
- MeminfoCounters.MEMINFO_SWAP_CACHED,
- MeminfoCounters.MEMINFO_ACTIVE,
- MeminfoCounters.MEMINFO_INACTIVE,
- MeminfoCounters.MEMINFO_ACTIVE_ANON,
- MeminfoCounters.MEMINFO_INACTIVE_ANON,
- MeminfoCounters.MEMINFO_ACTIVE_FILE,
- MeminfoCounters.MEMINFO_INACTIVE_FILE,
- MeminfoCounters.MEMINFO_UNEVICTABLE,
- MeminfoCounters.MEMINFO_SWAP_TOTAL,
- MeminfoCounters.MEMINFO_SWAP_FREE,
- MeminfoCounters.MEMINFO_DIRTY,
- MeminfoCounters.MEMINFO_WRITEBACK,
- MeminfoCounters.MEMINFO_ANON_PAGES,
- MeminfoCounters.MEMINFO_MAPPED,
- MeminfoCounters.MEMINFO_SHMEM,
- )
- )
- )
-)
-
-/**
- * Global config for perfetto.
- *
- * Eventually, this should be configurable.
- */
-internal fun perfettoConfig(
- atraceApps: List<String>
-) = TraceConfig(
- buffers = listOf(
- BufferConfig(size_kb = 16384, FillPolicy.RING_BUFFER),
- BufferConfig(size_kb = 16384, FillPolicy.RING_BUFFER)
- ),
- data_sources = listOf(
- ftraceDataSource(atraceApps),
- PROCESS_STATS_DATASOURCE,
- LINUX_SYS_STATS_DATASOURCE,
- ),
-)
-
-internal fun TraceConfig.validateAndEncode(): ByteArray {
- val ftraceConfig = data_sources
- .mapNotNull { it.config?.ftrace_config }
- .first()
-
- // check tags against known-supported tags based on SDK_INT / root status
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- val supportedTags = AtraceTag.supported(
- api = Build.VERSION.SDK_INT,
- rooted = device.isShellSessionRooted()
- ).map { it.tag }.toSet()
-
- val unsupportedTags = (ftraceConfig.atrace_categories - supportedTags)
- check(unsupportedTags.isEmpty()) {
- "Error - attempted to use unsupported atrace tags: $unsupportedTags"
- }
-
- if (Build.VERSION.SDK_INT < 28) {
- check(!ftraceConfig.atrace_apps.contains("*")) {
- "Support for wildcard (*) app matching in atrace added in API 28"
- }
- }
- return encode()
-}
\ No newline at end of file
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoHelper.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoHelper.kt
deleted file mode 100644
index d801ce9..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoHelper.kt
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import android.os.Build
-import android.os.SystemClock
-import android.util.Log
-import androidx.annotation.RequiresApi
-import androidx.annotation.RestrictTo
-import androidx.benchmark.macro.DeviceInfo.deviceSummaryString
-import androidx.benchmark.macro.device
-import androidx.benchmark.macro.userspaceTrace
-import androidx.test.platform.app.InstrumentationRegistry
-import org.jetbrains.annotations.TestOnly
-import java.io.File
-import java.io.IOException
-
-/**
- * PerfettoHelper is used to start and stop the perfetto tracing and move the
- * output perfetto trace file to destination folder.
- *
- * @suppress
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-@RequiresApi(21)
-public class PerfettoHelper(
- private val unbundled: Boolean = Build.VERSION.SDK_INT < LOWEST_BUNDLED_VERSION_SUPPORTED
-) {
-
- init {
- require(unbundled || Build.VERSION.SDK_INT >= LOWEST_BUNDLED_VERSION_SUPPORTED) {
- "Perfetto capture using the os version of perfetto requires API " +
- "$LOWEST_BUNDLED_VERSION_SUPPORTED or greater."
- }
- }
-
- private val instrumentation = InstrumentationRegistry.getInstrumentation()
- private val device = instrumentation.device()
-
- private fun perfettoStartupException(label: String, cause: Exception?): IllegalStateException {
- return IllegalStateException(
- """
- $label
- Please report a bug, and include a logcat capture of the test run and failure.
- $deviceSummaryString
- """.trimIndent(),
- cause
- )
- }
-
- /**
- * Start the perfetto tracing in background using the given config file.
- *
- * The output will be written to /data/misc/perfetto-traces/trace_output.pb. Perfetto has
- * write access only to /data/misc/perfetto-traces/ folder. The config file may be anywhere
- * readable by shell.
- *
- * @param configFilePath used for collecting the perfetto trace.
- * @param isTextProtoConfig true if the config file is textproto format otherwise false.
- */
- public fun startCollecting(configFilePath: String, isTextProtoConfig: Boolean) {
- require(configFilePath.isNotEmpty()) {
- "Perfetto config cannot be empty."
- }
-
- try {
- // Cleanup already existing perfetto process.
- Log.i(LOG_TAG, "Cleanup perfetto before starting.")
- if (isPerfettoRunning()) {
- Log.i(LOG_TAG, "Perfetto tracing is already running. Stopping perfetto.")
- if (!stopPerfetto()) {
- throw perfettoStartupException(
- "Unable to stop Perfetto trace capture",
- null
- )
- }
- }
-
- // The actual location of the config path.
- val actualConfigPath = if (unbundled) {
- val path = "$UNBUNDLED_PERFETTO_ROOT_DIR/config.pb"
- // Move the config to a directory that unbundled perfetto has permissions for.
- device.executeShellCommand("rm $path")
- device.executeShellCommand("mv $configFilePath $path")
- path
- } else {
- configFilePath
- }
-
- val outputPath = getPerfettoTmpOutputFilePath()
- // Remove already existing temporary output trace file if any.
- val output = device.executeShellCommand("rm $outputPath")
- Log.i(LOG_TAG, "Perfetto output file cleanup - $output")
-
- // Setup `traced` and `traced_probes` if necessary.
- setupTracedAndProbes()
-
- // Perfetto
- val perfettoCmd = perfettoCommand(actualConfigPath, isTextProtoConfig)
- Log.i(LOG_TAG, "Starting perfetto tracing with cmd: $perfettoCmd")
- val perfettoCmdOutput = device.executeShellScript(perfettoCmd)
- Log.i(LOG_TAG, "Perfetto pid - $perfettoCmdOutput")
- } catch (ioe: IOException) {
- throw perfettoStartupException("Unable to start perfetto tracing", ioe)
- }
-
- if (!isPerfettoRunning()) {
- throw perfettoStartupException("Perfetto tracing failed to start. ", null)
- }
-
- Log.i(LOG_TAG, "Perfetto tracing started successfully.")
- }
-
- /**
- * Stop the perfetto trace collection under /data/misc/perfetto-traces/trace_output.pb after
- * waiting for given time in msecs and copy the output to the destination file.
- *
- * @param waitTimeInMsecs time to wait in msecs before stopping the trace collection.
- * @param destinationFile file to copy the perfetto output trace.
- * @return true if the trace collection is successful otherwise false.
- */
- public fun stopCollecting(waitTimeInMsecs: Long, destinationFile: String): Boolean {
- // Wait for the dump interval before stopping the trace.
- userspaceTrace("Wait for perfetto flush") {
- Log.i(LOG_TAG, "Waiting for $waitTimeInMsecs millis before stopping perfetto.")
- SystemClock.sleep(waitTimeInMsecs)
- }
-
- // Stop the perfetto and copy the output file.
- Log.i(LOG_TAG, "Stopping perfetto.")
- try {
- var stopped = userspaceTrace("stop perfetto process") { stopPerfetto() }
- if (unbundled) {
- Log.i(LOG_TAG, "Stopping `traced` and `traced_probes`.")
- stopped = stopped.or(stopProcess(getProcessId(TRACED)))
- stopped = stopped.or(stopProcess(getProcessId(TRACED_PROBES)))
- }
- if (!stopped) {
- Log.e(LOG_TAG, "Perfetto failed to stop.")
- return false
- }
- Log.i(LOG_TAG, "Writing to $destinationFile.")
- return userspaceTrace("copy trace to output dir") {
- copyFileOutput(destinationFile)
- }
- } catch (ioe: IOException) {
- Log.e(LOG_TAG, "Unable to stop the perfetto tracing due to " + ioe.message, ioe)
- return false
- }
- }
-
- /**
- * Utility method for stopping perfetto.
- *
- * @return true if perfetto is stopped successfully.
- */
- @Throws(IOException::class)
- public fun stopPerfetto(): Boolean = stopProcess(getProcessId(PERFETTO))
-
- /**
- * Check if perfetto process is running or not.
- *
- * @return true if perfetto is running otherwise false.
- */
- public fun isPerfettoRunning(): Boolean {
- val pid = getProcessId(PERFETTO)
- return !pid.isNullOrEmpty()
- }
-
- /**
- * Sets up `traced` and `traced_probes` if necessary.
- */
- private fun setupTracedAndProbes() {
- if (!unbundled) {
- return
- }
-
- // Run `traced` and `traced_probes` in background mode.
-
- // Setup traced
- val tracedCmd = "$UNBUNDLED_ENV_PREFIX $tracedShellPath --background"
- Log.i(LOG_TAG, "Starting traced cmd: $tracedCmd")
- device.executeShellScript(tracedCmd)
-
- // Setup traced_probes
- val tracedProbesCmd = "$UNBUNDLED_ENV_PREFIX $tracedProbesShellPath --background"
- Log.i(LOG_TAG, "Starting traced_probes cmd: $tracedProbesCmd")
- device.executeShellScript(tracedProbesCmd)
- }
-
- /**
- * @return the shell command that can be used to start Perfetto.
- */
- private fun perfettoCommand(configFilePath: String, isTextProtoConfig: Boolean): String {
- val outputPath = getPerfettoTmpOutputFilePath()
- var command = if (!unbundled) (
- // Bundled perfetto reads configuration from stdin.
- "cat $configFilePath | perfetto --background -c - -o $outputPath"
- ) else {
- // Unbundled perfetto can read configuration from a file that it has permissions to
- // read from. This because it assumes the identity of the shell and therefore has
- // access to /data/local/tmp directory.
- "$UNBUNDLED_ENV_PREFIX $perfettoShellPath --background" +
- " -c $configFilePath" +
- " -o $outputPath"
- }
-
- if (isTextProtoConfig) {
- command += PERFETTO_TXT_PROTO_ARG
- }
- return command
- }
-
- /**
- * @return the [String] path to the temporary output file used to store the trace file
- * during collection.
- */
- private fun getPerfettoTmpOutputFilePath(): String {
- return if (unbundled) {
- UNBUNDLED_TEMP_OUTPUT_FILE
- } else {
- PERFETTO_TMP_OUTPUT_FILE
- }
- }
-
- /**
- * @return the [String] process id for a given process name.
- */
- private fun getProcessId(processName: String): String? {
- return try {
- val processId = device.executeShellCommand("pidof $processName")
- // We want to pick the most recent invocation of the command.
- // This is because we may have more than once instance of the process.
- val pid = processId.split(" ").lastOrNull()?.trim()
- Log.d(LOG_TAG, "Process id is $pid")
- pid
- } catch (ioe: IOException) {
- Log.i(LOG_TAG, "Unable to check process status due to $ioe.", ioe)
- null
- }
- }
-
- /**
- * Utility method for stopping a process with a given `pid`.
- *
- * @return true if the process was stopped successfully.
- */
- private fun stopProcess(pid: String?): Boolean {
- val stopOutput = device.executeShellCommand("kill -TERM $pid")
- Log.i(LOG_TAG, "Stop command output - $stopOutput")
- var waitCount = 0
- while (isProcessRunning(pid)) {
- Log.d(LOG_TAG, "Process ($pid) is running")
- // timeout for process shutdown.
- if (waitCount < PERFETTO_KILL_WAIT_COUNT) {
- // Check every 100 millis if process stopped successfully.
- userspaceTrace("wait for process kill") {
- SystemClock.sleep(PERFETTO_KILL_WAIT_TIME_MS)
- }
- waitCount++
- continue
- }
- return false
- }
- Log.i(LOG_TAG, "Process stopped successfully.")
- return true
- }
-
- /**
- * Utility method for checking if a process with a given `pid` is still running.
- *
- * @return true if still running.
- */
- @Throws(IOException::class)
- private fun isProcessRunning(pid: String?): Boolean {
- if (pid.isNullOrEmpty()) {
- return false
- }
-
- Log.d(LOG_TAG, "Checking if $pid is running")
-
- if (Build.VERSION.SDK_INT <= 23) {
- TODO("pid checking for api 23 and below not yet supported")
- }
- val output = device.executeShellCommand("ps -A $pid")
- return output.contains(pid)
- }
-
- /**
- * Copy the temporary perfetto trace output file from /data/local/tmp/trace_output.pb to given
- * destinationFile.
- *
- * @param destinationFile file to copy the perfetto output trace.
- * @return true if the trace file copied successfully otherwise false.
- */
- private fun copyFileOutput(destinationFile: String): Boolean {
- val sourceFile = getPerfettoTmpOutputFilePath()
- val filePath = File(destinationFile)
- val destDirectory = filePath.parent
- if (destDirectory != null) {
- // Check if the directory already exists
- val directory = File(destDirectory)
- if (!directory.exists()) {
- val success = directory.mkdirs()
- if (!success) {
- Log.e(
- LOG_TAG,
- "Result output directory $destDirectory not created successfully."
- )
- return false
- }
- }
- }
-
- // Copy the collected trace from /data/misc/perfetto-traces/trace_output.pb to
- // destinationFile
- try {
- val moveResult =
- device.executeShellCommand("mv $sourceFile $destinationFile")
- if (moveResult.isNotEmpty()) {
- Log.e(
- LOG_TAG,
- """
- Unable to move perfetto output file from $sourceFile
- to $destinationFile due to $moveResult.
- """.trimIndent()
- )
- return false
- }
- } catch (ioe: IOException) {
- Log.e(
- LOG_TAG,
- "Unable to move the perfetto trace file to destination file.",
- ioe
- )
- return false
- }
- return true
- }
-
- internal companion object {
- internal const val LOG_TAG = "PerfettoCapture"
-
- const val LOWEST_BUNDLED_VERSION_SUPPORTED = 29
-
- // Command to start the perfetto tracing in the background.
- // perfetto --background -c /data/misc/perfetto-traces/trace_config.pb -o
- // /data/misc/perfetto-traces/trace_output.pb
- private const val PERFETTO_TMP_OUTPUT_FILE = "/data/misc/perfetto-traces/trace_output.pb"
-
- // Additional arg to indicate that the perfetto config file is text format.
- private const val PERFETTO_TXT_PROTO_ARG = " --txt"
-
- // Max wait count for checking if perfetto is stopped successfully
- private const val PERFETTO_KILL_WAIT_COUNT = 30
-
- // Check if perfetto is stopped every 100 millis.
- private const val PERFETTO_KILL_WAIT_TIME_MS: Long = 100
-
- // Path where perfetto, traced, and traced_probes are copied to if API >= 21 and < 29
- private const val UNBUNDLED_PERFETTO_ROOT_DIR = "/data/local/tmp"
-
- private const val UNBUNDLED_TEMP_OUTPUT_FILE =
- "$UNBUNDLED_PERFETTO_ROOT_DIR/trace_output.pb"
-
- // The environment variables necessary for unbundled perfetto (unnamed domain sockets).
- // We need unnamed sockets here because SELinux dictates that we cannot use real, file
- // based, domain sockets on Platform versions prior to S.
- private const val UNBUNDLED_ENV_PREFIX =
- "PERFETTO_PRODUCER_SOCK_NAME=@macrobenchmark_producer " +
- "PERFETTO_CONSUMER_SOCK_NAME=@macrobenchmark_consumer"
-
- // A set of supported ABIs
- private val SUPPORTED_64_ABIS = setOf("arm64-v8a", "x86_64")
- private val SUPPORTED_32_ABIS = setOf("armeabi")
-
- // Perfetto executable
- private const val PERFETTO = "perfetto"
-
- // Trace daemon
- private const val TRACED = "traced"
-
- // Traced probes
- private const val TRACED_PROBES = "traced_probes"
-
- @TestOnly
- fun isAbiSupported(): Boolean {
- Log.d(LOG_TAG, "Supported ABIs: ${Build.SUPPORTED_ABIS.joinToString()}")
- // Cuttlefish is x86 but claims support for x86_64
- return !Build.MODEL.contains("Cuttlefish") && ( // b/180022458
- Build.SUPPORTED_64_BIT_ABIS.any { SUPPORTED_64_ABIS.contains(it) } ||
- Build.SUPPORTED_32_BIT_ABIS.any { SUPPORTED_32_ABIS.contains(it) }
- )
- }
-
- @get:TestOnly
- val tracedProbesShellPath: String by lazy {
- createExecutable(TRACED_PROBES)
- }
-
- @get:TestOnly
- val tracedShellPath: String by lazy {
- createExecutable(TRACED)
- }
-
- @get:TestOnly
- val perfettoShellPath: String by lazy {
- createExecutable(PERFETTO)
- }
-
- internal fun createExecutable(tool: String): String {
- userspaceTrace("create executable: $tool") {
- if (!isAbiSupported()) {
- throw IllegalStateException(
- "Unsupported ABI (${Build.SUPPORTED_ABIS.joinToString()})"
- )
- }
- val suffix = when {
- // The order is important because `SUPPORTED_64_BIT_ABIS` lists all ABI
- // supported by a device. That is why we need to search from most specific to
- // least specific. For e.g. emulators claim to support aarch64, when in reality
- // they can only support x86 or x86_64.
- Build.SUPPORTED_64_BIT_ABIS.any { it.startsWith("x86_64") } -> "x86_64"
- Build.SUPPORTED_64_BIT_ABIS.any { it.startsWith("arm64") } -> "aarch64"
- Build.SUPPORTED_32_BIT_ABIS.any { it.startsWith("armeabi") } -> "arm"
- else -> IllegalStateException(
- // Perfetto does not support x86 binaries
- "Unsupported ABI (${Build.SUPPORTED_ABIS.joinToString()})"
- )
- }
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val inputStream = instrumentation.context.assets.open("${tool}_$suffix")
- val device = instrumentation.device()
- return device.createRunnableExecutable(tool, inputStream)
- }
- }
- }
-}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
index 271192d..6c74086 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
@@ -17,16 +17,18 @@
package androidx.benchmark.macro.perfetto
import android.util.Log
+import androidx.annotation.RequiresApi
import androidx.benchmark.Outputs
-import androidx.benchmark.macro.device
-import androidx.benchmark.macro.userspaceTrace
-import androidx.test.platform.app.InstrumentationRegistry
+import androidx.benchmark.Shell
+import androidx.benchmark.perfetto.PerfettoHelper
+import androidx.benchmark.userspaceTrace
import org.jetbrains.annotations.TestOnly
import java.io.File
/**
* Enables parsing perfetto traces on-device
*/
+@RequiresApi(21)
internal object PerfettoTraceProcessor {
private const val TAG = "PerfettoTraceProcessor"
@@ -53,14 +55,11 @@
"Metric must not contain spaces: $metric"
}
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val device = instrumentation.device()
-
val command = "$shellPath --run-metric $metric $absoluteTracePath --metrics-output=json"
Log.d(TAG, "Executing command $command")
val json = userspaceTrace("trace_processor_shell") {
- device.executeShellCommand(command)
+ Shell.executeCommand(command)
.trim() // trim to enable empty check below
}
Log.d(TAG, "Trace Processor result: \n\n $json")
@@ -135,12 +134,9 @@
try {
queryFile.writeText(query)
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val device = instrumentation.device()
-
val command = "$shellPath --query-file ${queryFile.absolutePath} $absoluteTracePath"
return userspaceTrace("trace_processor_shell") {
- device.executeShellCommand(command)
+ Shell.executeCommand(command)
}
} finally {
queryFile.delete()
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/ShellUtils.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/ShellUtils.kt
deleted file mode 100644
index a3125d2..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/ShellUtils.kt
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import android.os.Build
-import androidx.benchmark.Outputs
-import androidx.test.uiautomator.UiDevice
-import java.io.File
-import java.io.InputStream
-
-internal data class ShellOutput(val stdout: String, val stderr: String)
-
-private fun UiDevice.chmodExecutable(absoluteFilePath: String) {
- if (Build.VERSION.SDK_INT >= 23) {
- executeShellCommand("chmod +x $absoluteFilePath")
- } else {
- // chmod with support for +x only added in API 23
- // While 777 is technically more permissive, this is only used for scripts and temporary
- // files in tests, so we don't worry about permissions / access here
- executeShellCommand("chmod 777 $absoluteFilePath")
- }
-}
-
-/**
- * Provides shell scripting functionality, as well as stdin/stderr capabilities (for the first/last
- * command, respectively)
- *
- * A better way to implement stdin/stderr may be to have an additional wrapper script when
- * stdin/stderr is required, so that all stderr can be captured (instead of redirecting the
- * last command), and stdin can be read by other commands in the script (instead of just the 1st).
- */
-private fun UiDevice.executeShellScript(
- script: String,
- stdin: String?,
- includeStderr: Boolean
-): Pair<String, String?> {
- // dirUsableByAppAndShell is writable, but we can't execute there (as of Q),
- // so we copy to /data/local/tmp
- val externalDir = Outputs.dirUsableByAppAndShell
- val writableScriptFile = File.createTempFile("temporaryScript", ".sh", externalDir)
- val runnableScriptPath = "/data/local/tmp/" + writableScriptFile.name
-
- // only create/read/delete stdin/stderr files if they are needed
- val stdinFile = stdin?.run {
- File.createTempFile("temporaryStdin", null, externalDir)
- }
- val stderrPath = if (includeStderr) {
- // we use a modified runnableScriptPath (as opposed to externalDir) because some shell
- // commands fail to redirect stderr to externalDir (notably, `am start`).
- // This also means we need to `cat` the file to read it, and `rm` to remove it.
- runnableScriptPath + "_stderr"
- } else {
- null
- }
-
- try {
- var scriptText: String = script
- if (stdinFile != null) {
- stdinFile.writeText(stdin)
- scriptText = "cat ${stdinFile.absolutePath} | $scriptText"
- }
- if (stderrPath != null) {
- scriptText = "$scriptText 2> $stderrPath"
- }
- writableScriptFile.writeText(scriptText)
-
- // Note: we don't check for return values from the below, since shell based file
- // permission errors generally crash our process.
- executeShellCommand("cp ${writableScriptFile.absolutePath} $runnableScriptPath")
- chmodExecutable(runnableScriptPath)
-
- val stdout = executeShellCommand(runnableScriptPath)
- val stderr = stderrPath?.run { executeShellCommand("cat $stderrPath") }
-
- return Pair(stdout, stderr)
- } finally {
- stdinFile?.delete()
- stderrPath?.run {
- executeShellCommand("rm $stderrPath")
- }
- writableScriptFile.delete()
- executeShellCommand("rm $runnableScriptPath")
- }
-}
-
-/**
- * Convenience wrapper around [UiDevice.executeShellCommand()] which enables redirects, piping, and
- * all other shell script functionality, and captures stderr of last command.
- *
- * Unlike [UiDevice.executeShellCommand()], this method supports arbitrary multi-line shell
- * expressions, as it creates and executes a shell script in `/data/local/tmp/`.
- *
- * Note that shell scripting capabilities differ based on device version. To see which utilities
- * are available on which platform versions,see
- * [Android's shell and utilities](https://android.googlesource.com/platform/system/core/+/master/shell_and_utilities/README.md#)
- *
- * @param script Script content to run
- * @param stdin String to pass in as stdin to first command in script
- *
- * @return ShellOutput, including stdout of full script, and stderr of last command.
- */
-internal fun UiDevice.executeShellScriptWithStderr(
- script: String,
- stdin: String? = null
-): ShellOutput {
- return executeShellScript(
- script = script,
- stdin = stdin,
- includeStderr = true
- ).run {
- ShellOutput(first, second!!)
- }
-}
-
-/**
- * Convenience wrapper around [UiDevice.executeShellCommand()] which enables redirects, piping, and
- * all other shell script functionality.
- *
- * Unlike [UiDevice.executeShellCommand()], this method supports arbitrary multi-line shell
- * expressions, as it creates and executes a shell script in `/data/local/tmp/`.
- *
- * Note that shell scripting capabilities differ based on device version. To see which utilities
- * are available on which platform versions,see
- * [Android's shell and utilities](https://android.googlesource.com/platform/system/core/+/master/shell_and_utilities/README.md#)
- *
- * @param script Script content to run
- * @param stdin String to pass in as stdin to first command in script
- *
- * @return Stdout string
- */
-internal fun UiDevice.executeShellScript(script: String, stdin: String? = null): String {
- return executeShellScript(script, stdin, false).first
-}
-
-/**
- * Writes the inputStream to an executable file with the given name in `/data/local/tmp`
- */
-internal fun UiDevice.createRunnableExecutable(name: String, inputStream: InputStream): String {
- // dirUsableByAppAndShell is writable, but we can't execute there (as of Q),
- // so we copy to /data/local/tmp
- val externalDir = Outputs.dirUsableByAppAndShell
- val writableExecutableFile = File.createTempFile(
- /* prefix */ "temporary_$name",
- /* suffix */ null,
- /* directory */ externalDir
- )
- val runnableExecutablePath = "/data/local/tmp/$name"
-
- try {
- writableExecutableFile.outputStream().use {
- inputStream.copyTo(it)
- }
- moveToTmpAndMakeExecutable(
- src = writableExecutableFile.absolutePath,
- dst = runnableExecutablePath
- )
- } finally {
- writableExecutableFile.delete()
- }
-
- return runnableExecutablePath
-}
-
-/**
- * Returns true if the shell session is rooted, and thus root commands can be run (e.g. atrace
- * commands with root-only tags)
- */
-internal fun UiDevice.isShellSessionRooted(): Boolean {
- return executeShellCommand("getprop service.adb.root").trim() == "1"
-}
-
-private fun UiDevice.moveToTmpAndMakeExecutable(src: String, dst: String) {
- // Note: we don't check for return values from the below, since shell based file
- // permission errors generally crash our process.
- executeShellCommand("cp $src $dst")
- chmodExecutable(dst)
-}
-
-internal fun UiDevice.isPackageAlive(packageName: String): Boolean {
- if (Build.VERSION.SDK_INT >= 24) {
- // On API 23 (first version to offer it) we observe that 'pidof'
- // returns list of all processes :|
- return executeShellCommand("pidof $packageName").isNotBlank()
- }
-
- // Can't use ps -A on older platforms, arg isn't supported.
- // Can't simply run ps, since it gets truncated
- return executeShellScript("ps | grep $packageName")
- .split("\r?\n")
- .any { it.trim().endsWith(" $packageName") }
-}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/UiState.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/UiState.kt
deleted file mode 100644
index 33bf7de..0000000
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/UiState.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.benchmark.macro.perfetto
-
-import perfetto.protos.Trace
-import perfetto.protos.TracePacket
-import perfetto.protos.UiState
-import java.io.File
-
-/**
- * Convenience for UiState construction with specified package
- */
-@Suppress("FunctionName") // constructor convenience
-internal fun UiState(
- timelineStart: Long?,
- timelineEnd: Long?,
- highlightPackage: String?
-) = UiState(
- timeline_start_ts = timelineStart,
- timeline_end_ts = timelineEnd,
- highlight_process = highlightPackage?.run {
- UiState.HighlightProcess(cmdline = highlightPackage)
- }
-)
-
-internal fun File.appendUiState(state: UiState) {
- val traceToAppend = Trace(packet = listOf(TracePacket(ui_state = state)))
- appendBytes(traceToAppend.encode())
-}
diff --git a/benchmark/benchmark-macro/src/main/java/perfetto/protos/package-info.java b/benchmark/benchmark-macro/src/main/java/perfetto/protos/package-info.java
deleted file mode 100644
index 4654d20..0000000
--- a/benchmark/benchmark-macro/src/main/java/perfetto/protos/package-info.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Hide the perfetto.protos package, as it's an implementation detail of benchmark.macro
- *
- * Note: other attempts to use these protos in the macrobench process will clash with our
- * definitions. If this becomes an issue, we can move ours to a separate, internal package.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-package perfetto.protos;
-
-import androidx.annotation.RestrictTo;
diff --git a/benchmark/benchmark/build.gradle b/benchmark/benchmark/build.gradle
index 09799ac..a69a0a3 100644
--- a/benchmark/benchmark/build.gradle
+++ b/benchmark/benchmark/build.gradle
@@ -21,16 +21,8 @@
id("androidx.benchmark")
}
-android {
- defaultConfig {
- // 18 needed for UI automator dependency, via benchmark-macro-junit4
- minSdkVersion 18
- }
-}
-
dependencies {
androidTestImplementation(project(":benchmark:benchmark-junit4"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
androidTestImplementation(project(":tracing:tracing-ktx"))
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.testRules)
diff --git a/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/PerfettoOverheadBenchmark.kt b/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/PerfettoOverheadBenchmark.kt
index 0b09e96..f2bfd74 100644
--- a/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/PerfettoOverheadBenchmark.kt
+++ b/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/PerfettoOverheadBenchmark.kt
@@ -17,8 +17,8 @@
package androidx.benchmark.benchmark
import androidx.benchmark.junit4.BenchmarkRule
+import androidx.benchmark.junit4.PerfettoRule
import androidx.benchmark.junit4.measureRepeated
-import androidx.benchmark.macro.junit4.PerfettoRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.tracing.Trace
diff --git a/biometric/biometric/src/main/res/values-te/strings.xml b/biometric/biometric/src/main/res/values-te/strings.xml
index bf81e43..07712d5 100644
--- a/biometric/biometric/src/main/res/values-te/strings.xml
+++ b/biometric/biometric/src/main/res/values-te/strings.xml
@@ -22,8 +22,8 @@
<string name="fingerprint_error_hw_not_available" msgid="8216738333501875566">"వేలిముద్ర హార్డ్వేర్ అందుబాటులో లేదు."</string>
<string name="fingerprint_error_no_fingerprints" msgid="7520712796891883488">"వేలిముద్రలు నమోదు చేయబడలేదు."</string>
<string name="fingerprint_error_hw_not_present" msgid="6306988885793029438">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ లేదు"</string>
- <string name="fingerprint_error_user_canceled" msgid="7627716295344353987">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేసారు."</string>
- <string name="fingerprint_error_lockout" msgid="7291787166416782245">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+ <string name="fingerprint_error_user_canceled" msgid="7627716295344353987">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేశారు."</string>
+ <string name="fingerprint_error_lockout" msgid="7291787166416782245">"చాలా ఎక్కువ ప్రయత్నాలు చేశారు. దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి."</string>
<string name="default_error_msg" msgid="4776854077120974966">"తెలియని ఎర్రర్"</string>
<string name="generic_error_user_canceled" msgid="7309881387583143581">"వినియోగదారు ద్వారా ప్రామాణీకరణ రద్దు చేయబడింది"</string>
<string name="confirm_device_credential_password" msgid="5912733858573823945">"పాస్వర్డ్ను ఉపయోగించు"</string>
diff --git a/biometric/biometric/src/test/resources/robolectric.properties b/biometric/biometric/src/test/resources/robolectric.properties
index 3f2e0d0..5fad9a0 100644
--- a/biometric/biometric/src/test/resources/robolectric.properties
+++ b/biometric/biometric/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
\ No newline at end of file
+sdk=30
\ No newline at end of file
diff --git a/biometric/integration-tests/testapp/src/main/AndroidManifest.xml b/biometric/integration-tests/testapp/src/main/AndroidManifest.xml
index ba58d87..ca5ff9c 100644
--- a/biometric/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/biometric/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -28,6 +28,7 @@
<activity
android:name=".MainActivity"
android:label="@string/biometric_test_app_name"
+ android:exported="true"
android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -38,11 +39,13 @@
<activity
android:name=".BiometricPromptTestActivity"
android:label="@string/biometric_prompt_test_title"
+ android:exported="false"
android:theme="@style/Theme.AppCompat.Light" />
<activity
android:name=".AuthPromptTestActivity"
android:label="@string/auth_prompt_test_title"
+ android:exported="false"
android:theme="@style/Theme.AppCompat.Light" />
</application>
</manifest>
\ No newline at end of file
diff --git a/browser/browser/build.gradle b/browser/browser/build.gradle
index c900186..c5f3330 100644
--- a/browser/browser/build.gradle
+++ b/browser/browser/build.gradle
@@ -33,7 +33,7 @@
testImplementation(libs.robolectric)
testImplementation(libs.mockitoCore)
- androidTestImplementation("androidx.appcompat:appcompat:1.0.0")
+ androidTestImplementation("androidx.appcompat:appcompat:1.1.0")
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRunner)
diff --git a/browser/browser/src/androidTest/AndroidManifest.xml b/browser/browser/src/androidTest/AndroidManifest.xml
index 3e5c314..da0b286 100644
--- a/browser/browser/src/androidTest/AndroidManifest.xml
+++ b/browser/browser/src/androidTest/AndroidManifest.xml
@@ -15,59 +15,39 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.support.customtabs.test">
+ package="android.support.customtabs.test">
<application>
- <activity android:name="androidx.browser.customtabs.TestActivity"
- android:enabled="false">
+ <activity
+ android:name="androidx.browser.customtabs.TestActivity"
+ android:enabled="false"
+ android:exported="true">
<!-- A browsable intent filter is required for the TrustedWebActivityService. -->
<intent-filter>
- <action android:name="android.intent.action.VIEW"/>
+ <action android:name="android.intent.action.VIEW" />
+
<category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE"/>
- <data android:scheme="https"
- android:host="www.example.com"
- android:pathPrefix="/notifications"/>
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.example.com"
+ android:pathPrefix="/notifications"
+ android:scheme="https" />
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
- <service android:name="androidx.browser.customtabs.PostMessageService"
- android:enabled="false"/>
-
- <service android:name="androidx.browser.customtabs.TestCustomTabsService"
- android:enabled="false">
- <intent-filter>
- <category android:name="androidx.browser.trusted.category.TrustedWebActivities" />
- </intent-filter>
- </service>
-
- <service android:name="androidx.browser.customtabs.TestCustomTabsServiceSupportsTwas"
- android:enabled="false">
- <intent-filter>
- <action android:name="android.support.customtabs.action.CustomTabsService" />
- <category android:name="androidx.browser.trusted.category.TrustedWebActivities" />
- <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1" />
- </intent-filter>
- </service>
-
- <service android:name="androidx.browser.customtabs.TestCustomTabsServiceNoSplashScreens"
- android:enabled="false">
- <intent-filter>
- <action android:name="android.support.customtabs.action.CustomTabsService" />
- <category android:name="androidx.browser.trusted.category.TrustedWebActivities" />
- </intent-filter>
- </service>
-
- <activity android:name="androidx.browser.trusted.TestBrowser"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="true"
- android:enabled="false">
+ <activity
+ android:name="androidx.browser.trusted.TestBrowser"
+ android:enabled="false"
+ android:exported="true"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -76,36 +56,77 @@
</intent-filter>
</activity>
- <service android:name="androidx.browser.trusted.TestTrustedWebActivityService"
- android:enabled="false">
- <intent-filter>
- <action android:name="android.support.customtabs.trusted.TRUSTED_WEB_ACTIVITY_SERVICE"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </service>
+ <activity
+ android:name="androidx.browser.trusted.LauncherActivity"
+ android:enabled="false"
+ android:exported="true"
+ android:label="Test Launcher Activity"
+ android:theme="@style/Theme.AppCompat.Light">
- <activity android:name="androidx.browser.trusted.LauncherActivity"
- android:label="Test Launcher Activity"
- android:theme="@style/Theme.AppCompat.Light"
- android:enabled="false">
-
- <meta-data android:name="android.support.customtabs.trusted.DEFAULT_URL"
- android:value="https://www.test.com/default_url/" />
+ <meta-data
+ android:name="android.support.customtabs.trusted.DEFAULT_URL"
+ android:value="https://www.test.com/default_url/" />
<meta-data
android:name="android.support.customtabs.trusted.STATUS_BAR_COLOR"
android:resource="@color/status_bar_color" />
</activity>
- <!-- For TWA splash screens -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="android.support.customtabs.trusted.test_fileprovider"
- android:grantUriPermissions="true"
- android:exported="false">
+ android:exported="false"
+ android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
+
+ <service
+ android:name="androidx.browser.customtabs.TestCustomTabsServiceNoSplashScreens"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.support.customtabs.action.CustomTabsService" />
+ <category android:name="androidx.browser.trusted.category.TrustedWebActivities" />
+ </intent-filter>
+ </service>
+
+ <service
+ android:name="androidx.browser.customtabs.PostMessageService"
+ android:enabled="false"
+ android:exported="true" />
+
+ <service
+ android:name="androidx.browser.trusted.TestTrustedWebActivityService"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.support.customtabs.trusted.TRUSTED_WEB_ACTIVITY_SERVICE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+
+ <service
+ android:name="androidx.browser.customtabs.TestCustomTabsService"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <category android:name="androidx.browser.trusted.category.TrustedWebActivities" />
+ </intent-filter>
+ </service>
+
+ <!-- For TWA splash screens -->
+ <service
+ android:name="androidx.browser.customtabs.TestCustomTabsServiceSupportsTwas"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.support.customtabs.action.CustomTabsService" />
+
+ <category android:name="androidx.browser.trusted.category.TrustedWebActivities" />
+ <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1" />
+ </intent-filter>
+ </service>
</application>
</manifest>
\ No newline at end of file
diff --git a/browser/browser/src/test/resources/robolectric.properties b/browser/browser/src/test/resources/robolectric.properties
index 3f2e0d0..5fad9a0 100644
--- a/browser/browser/src/test/resources/robolectric.properties
+++ b/browser/browser/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
\ No newline at end of file
+sdk=30
\ No newline at end of file
diff --git a/buildSrc/OWNERS b/buildSrc/OWNERS
index 7674fe0..0aa4786 100644
--- a/buildSrc/OWNERS
+++ b/buildSrc/OWNERS
@@ -12,3 +12,4 @@
per-file *build_dependencies.gradle=file://OWNERS
per-file *AndroidXPlaygroundRootPlugin.kt = dustinlam@google.com, rahulrav@google.com, yboyar@google.com
+per-file *LibraryVersions.kt = jnichol@google.com
diff --git a/buildSrc/README.md b/buildSrc/README.md
index 32e6c3d..4d251a3 100644
--- a/buildSrc/README.md
+++ b/buildSrc/README.md
@@ -9,3 +9,7 @@
* https://medium.com/androiddevelopers/configuration-caching-deep-dive-bcb304698070
* https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:requirements:use_project_during_execution
* https://github.com/gradle/gradle/issues/17813
+
+The buildSrc directory is split into multiple projects based on what needs to be available on the classpath when parsing build.gradle files outside of buildSrc. Any classes that Gradle puts on the classpath for parsing build.gradle files can theoretically overwrite the implementation of tasks in those projects. So, if a class is on that classpath and it changes then Gradle is not confident that the task is necessarily up-to-date and Gradle will rerun it. So, we move as many classes as possible off of this classpath by applying them from within a separate .gradle script instead.
+
+See also b/140265324 for more information.
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index ec78e6b..707fd6e 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -88,6 +88,12 @@
apply plugin: "java-gradle-plugin"
sourceSets {
+ ["public", "private", "plugins"].each { subdir ->
+ main.java.srcDirs += "${subdir}/src/main/kotlin"
+ main.resources.srcDirs += "${subdir}/src/main/resources"
+ }
+
+
main.java.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/kotlin"
main.resources.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/resources"
diff --git a/buildSrc/lint.xml b/buildSrc/lint.xml
index 1fb6d32..0d38ee1 100644
--- a/buildSrc/lint.xml
+++ b/buildSrc/lint.xml
@@ -13,6 +13,7 @@
<!-- Required for AppSearch icing tests. -->
<ignore path="**/java/tests/**" />
</issue>
- <!-- Re-enable NewApi for tests (and everything else). -->
+ <!-- Re-enable high-priority checks for tests (and everything else). -->
<issue id="NewApi" severity="fatal" />
+ <issue id="WrongThread" severity="fatal" />
</lint>
diff --git a/buildSrc/plugins/README.md b/buildSrc/plugins/README.md
new file mode 100644
index 0000000..68b1cc4
--- /dev/null
+++ b/buildSrc/plugins/README.md
@@ -0,0 +1,3 @@
+This is the :buildSrc:plugins project
+
+It contains plugins to be applied by various other projects in this repository
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXComposePlugin.kt b/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXComposePlugin.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/AndroidXComposePlugin.kt
rename to buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXComposePlugin.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt b/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
rename to buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt b/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXPlugin.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
rename to buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXPlugin.kt
diff --git a/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt b/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt
new file mode 100644
index 0000000..0c2e98f
--- /dev/null
+++ b/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build
+
+import androidx.build.AndroidXPlugin.Companion.ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK
+import androidx.build.AndroidXPlugin.Companion.ZIP_TEST_CONFIGS_WITH_APKS_TASK
+import androidx.build.dependencyTracker.AffectedModuleDetector
+import androidx.build.gradle.isRoot
+import androidx.build.license.CheckExternalDependencyLicensesTask
+import androidx.build.playground.VerifyPlaygroundGradlePropertiesTask
+import androidx.build.studio.StudioTask.Companion.registerStudioTask
+import androidx.build.testConfiguration.registerOwnersServiceTasks
+import androidx.build.uptodatedness.TaskUpToDateValidator
+import com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
+import com.android.build.gradle.AppPlugin
+import com.android.build.gradle.LibraryPlugin
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.api.artifacts.component.ModuleComponentSelector
+import org.gradle.api.plugins.JavaPlugin
+import org.gradle.api.tasks.bundling.Zip
+import org.gradle.api.tasks.bundling.ZipEntryCompression
+import org.gradle.build.event.BuildEventsListenerRegistry
+import org.gradle.kotlin.dsl.KotlinClosure1
+import org.gradle.kotlin.dsl.extra
+import java.io.File
+import java.util.Locale
+import java.util.concurrent.ConcurrentHashMap
+
+abstract class AndroidXRootPlugin : Plugin<Project> {
+ @Suppress("UnstableApiUsage")
+ @get:javax.inject.Inject
+ abstract val registry: BuildEventsListenerRegistry
+
+ override fun apply(project: Project) {
+ if (!project.isRoot) {
+ throw Exception("This plugin should only be applied to root project")
+ }
+ project.configureRootProject()
+ }
+
+ @OptIn(ExperimentalStdlibApi::class) // string extensions
+ private fun Project.configureRootProject() {
+ project.validateAllAndroidxArgumentsAreRecognized()
+ tasks.register("listAndroidXProperties", ListAndroidXPropertiesTask::class.java)
+ setDependencyVersions()
+ configureKtlintCheckFile()
+ tasks.register(CheckExternalDependencyLicensesTask.TASK_NAME)
+
+ // Validate the Android Gradle Plugin version, if specified.
+ val expectedAgpVersion = System.getenv("EXPECTED_AGP_VERSION")
+ if (expectedAgpVersion != null && expectedAgpVersion != ANDROID_GRADLE_PLUGIN_VERSION) {
+ throw Exception(
+ "Expected AGP version \"$expectedAgpVersion\" does not match actual " +
+ "AGP version \"$ANDROID_GRADLE_PLUGIN_VERSION\". Please close and restart " +
+ "Studio."
+ )
+ }
+
+ val buildOnServerTask = tasks.create(
+ AndroidXPlugin.BUILD_ON_SERVER_TASK,
+ BuildOnServer::class.java
+ )
+ buildOnServerTask.dependsOn(
+ tasks.register(
+ AndroidXPlugin.CREATE_AGGREGATE_BUILD_INFO_FILES_TASK,
+ CreateAggregateLibraryBuildInfoFileTask::class.java
+ )
+ )
+ buildOnServerTask.dependsOn(
+ tasks.register(AndroidXPlugin.CREATE_LIBRARY_BUILD_INFO_FILES_TASK)
+ )
+
+ VerifyPlaygroundGradlePropertiesTask.createIfNecessary(project)?.let {
+ buildOnServerTask.dependsOn(it)
+ }
+
+ val createArchiveTask = Release.getGlobalFullZipTask(this)
+ buildOnServerTask.dependsOn(createArchiveTask)
+ val partiallyDejetifyArchiveTask = partiallyDejetifyArchiveTask(
+ createArchiveTask.flatMap { it.archiveFile }
+ )
+ if (partiallyDejetifyArchiveTask != null)
+ buildOnServerTask.dependsOn(partiallyDejetifyArchiveTask)
+
+ buildOnServerTask.dependsOn(
+ tasks.register(
+ "saveSystemStats",
+ SaveSystemStatsTask::class.java
+ ) { task ->
+ task.outputFile.set(File(project.getDistributionDirectory(), "system_stats.txt"))
+ }
+ )
+
+ extra.set("projects", ConcurrentHashMap<String, String>())
+ buildOnServerTask.dependsOn(tasks.named(CheckExternalDependencyLicensesTask.TASK_NAME))
+ // Anchor task that invokes running all subprojects :validateProperties tasks which ensure that
+ // Android Studio sync is able to succeed.
+ val validateAllProperties = tasks.register("validateAllProperties")
+ subprojects { project ->
+ // Add a method for each sub project where they can declare an optional
+ // dependency on a project or its latest snapshot artifact.
+ // In AndroidX build, this is always enforsed to the project while in Playground
+ // builds, they are converted to the latest SNAPSHOT artifact if the project is
+ // not included in that playground. see: AndroidXPlaygroundRootPlugin
+ project.extra.set(
+ PROJECT_OR_ARTIFACT_EXT_NAME,
+ KotlinClosure1<String, Project>(
+ function = {
+ // this refers to the first parameter of the closure.
+ project.project(this)
+ }
+ )
+ )
+ project.afterEvaluate {
+ if (project.plugins.hasPlugin(LibraryPlugin::class.java) ||
+ project.plugins.hasPlugin(AppPlugin::class.java)
+ ) {
+
+ buildOnServerTask.dependsOn("${project.path}:assembleRelease")
+ if (!project.usingMaxDepVersions()) {
+ project.agpVariants.all { variant ->
+ // in AndroidX, release and debug variants are essentially the same,
+ // so we don't run the lintRelease task on the build server
+ if (!variant.name.lowercase(Locale.getDefault()).contains("release")) {
+ val taskName = "lint${variant.name.replaceFirstChar {
+ if (it.isLowerCase()) {
+ it.titlecase(Locale.getDefault())
+ } else {
+ it.toString()
+ }
+ }}"
+ buildOnServerTask.dependsOn("${project.path}:$taskName")
+ }
+ }
+ }
+ }
+ }
+ project.plugins.withType(JavaPlugin::class.java) {
+ buildOnServerTask.dependsOn("${project.path}:jar")
+ }
+
+ val validateProperties = project.tasks.register(
+ "validateProperties",
+ ValidatePropertiesTask::class.java
+ )
+ validateAllProperties.configure {
+ it.dependsOn(validateProperties)
+ }
+ }
+
+ if (partiallyDejetifyArchiveTask != null) {
+ project(":jetifier:jetifier-standalone").afterEvaluate { standAloneProject ->
+ partiallyDejetifyArchiveTask.configure {
+ it.dependsOn(standAloneProject.tasks.named("installDist"))
+ }
+ createArchiveTask.configure {
+ it.dependsOn(standAloneProject.tasks.named("dist"))
+ }
+ }
+ }
+
+ tasks.register(AndroidXPlugin.BUILD_TEST_APKS_TASK)
+
+ project.tasks.register(
+ ZIP_TEST_CONFIGS_WITH_APKS_TASK, Zip::class.java
+ ) {
+ it.destinationDirectory.set(project.getDistributionDirectory())
+ it.archiveFileName.set("androidTest.zip")
+ it.from(project.getTestConfigDirectory())
+ // We're mostly zipping a bunch of .apk files that are already compressed
+ it.entryCompression = ZipEntryCompression.STORED
+ }
+ project.tasks.register(
+ ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK, Zip::class.java
+ ) {
+ it.destinationDirectory.set(project.getDistributionDirectory())
+ it.archiveFileName.set("constrainedAndroidTest.zip")
+ it.from(project.getConstrainedTestConfigDirectory())
+ // We're mostly zipping a bunch of .apk files that are already compressed
+ it.entryCompression = ZipEntryCompression.STORED
+ }
+
+ AffectedModuleDetector.configure(gradle, this)
+
+ // Needs to be called before evaluationDependsOnChildren in usingMaxDepVersions block
+ publishInspectionArtifacts()
+ registerOwnersServiceTasks()
+
+ // If useMaxDepVersions is set, iterate through all the project and substitute any androidx
+ // artifact dependency with the local tip of tree version of the library.
+ if (project.usingMaxDepVersions()) {
+ // This requires evaluating all sub-projects to create the module:project map
+ // and project dependencies.
+ allprojects { project2 ->
+ // evaluationDependsOnChildren isn't transitive so we must call it on each project
+ project2.evaluationDependsOnChildren()
+ }
+ val projectModules = getProjectsMap()
+ subprojects { subproject ->
+ // TODO(153485458) remove most of these exceptions
+ if (!subproject.name.contains("hilt") &&
+ subproject.name != "docs-public" &&
+ subproject.name != "docs-tip-of-tree" &&
+ subproject.name != "camera-testapp-timing" &&
+ subproject.name != "room-testapp" &&
+ !(
+ subproject.path.contains
+ ("media2:media2-session:version-compat-tests:client-previous")
+ ) &&
+ !(
+ subproject.path.contains
+ ("media2:media2-session:version-compat-tests:service-previous")
+ )
+ ) {
+ subproject.configurations.all { configuration ->
+ configuration.resolutionStrategy.dependencySubstitution.apply {
+ all { dep ->
+ val requested = dep.getRequested()
+ if (requested is ModuleComponentSelector) {
+ val module = requested.group + ":" + requested.module
+ if (projectModules.containsKey(module)) {
+ dep.useTarget(project(projectModules[module]!!))
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ registerStudioTask()
+
+ TaskUpToDateValidator.setup(project, registry)
+
+ project.tasks.register("listTaskOutputs", ListTaskOutputsTask::class.java) { task ->
+ task.setOutput(File(project.getDistributionDirectory(), "task_outputs.txt"))
+ task.removePrefix(project.getCheckoutRoot().path)
+ }
+ }
+
+ @Suppress("UnstableApiUsage")
+ private fun Project.setDependencyVersions() {
+ val libs = project.extensions.getByType(
+ VersionCatalogsExtension::class.java
+ ).find("libs").get()
+ fun getVersion(key: String): String {
+ val version = libs.findVersion(key)
+ return if (version.isPresent) {
+ version.get().requiredVersion
+ } else {
+ throw GradleException("Could not find a version for `$key`")
+ }
+ }
+ androidx.build.dependencies.kotlinVersion = getVersion("kotlin")
+ androidx.build.dependencies.kspVersion = getVersion("ksp")
+ androidx.build.dependencies.agpVersion = getVersion("androidGradlePlugin")
+ androidx.build.dependencies.guavaVersion = getVersion("guavaJre")
+ }
+
+ companion object {
+ const val PROJECT_OR_ARTIFACT_EXT_NAME = "projectOrArtifact"
+ }
+}
diff --git a/buildSrc/plugins/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt b/buildSrc/plugins/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt
new file mode 100644
index 0000000..74fa2ec
--- /dev/null
+++ b/buildSrc/plugins/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt
@@ -0,0 +1,726 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build.docs
+
+import androidx.build.SupportConfig
+import androidx.build.dackka.DackkaTask
+import androidx.build.dependencies.KOTLIN_VERSION
+import androidx.build.doclava.DacOptions
+import androidx.build.doclava.DoclavaTask
+import androidx.build.doclava.GENERATE_DOCS_CONFIG
+import androidx.build.doclava.androidJarFile
+import androidx.build.doclava.createGenerateSdkApiTask
+import androidx.build.dokka.Dokka
+import androidx.build.getBuildId
+import androidx.build.getCheckoutRoot
+import androidx.build.getDistributionDirectory
+import androidx.build.getKeystore
+import com.android.build.api.attributes.BuildTypeAttr
+import com.android.build.gradle.LibraryExtension
+import com.android.build.gradle.LibraryPlugin
+import org.gradle.api.DefaultTask
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.artifacts.ComponentMetadataContext
+import org.gradle.api.artifacts.ComponentMetadataRule
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.attributes.Category
+import org.gradle.api.attributes.DocsType
+import org.gradle.api.attributes.Usage
+import org.gradle.api.file.DuplicatesStrategy
+import org.gradle.api.file.FileCollection
+import org.gradle.api.model.ObjectFactory
+import org.gradle.api.plugins.JavaBasePlugin
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.Sync
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.api.tasks.bundling.Zip
+import org.gradle.api.tasks.testing.Test
+import org.gradle.kotlin.dsl.all
+import org.gradle.kotlin.dsl.getByType
+import org.gradle.kotlin.dsl.named
+import org.gradle.kotlin.dsl.register
+import org.jetbrains.dokka.gradle.DokkaAndroidTask
+import org.jetbrains.dokka.gradle.PackageOptions
+import java.io.File
+import java.io.FileNotFoundException
+import javax.inject.Inject
+
+/**
+ * Plugin that allows to build documentation for a given set of prebuilt and tip of tree projects.
+ */
+class AndroidXDocsPlugin : Plugin<Project> {
+ lateinit var project: Project
+ lateinit var docsType: String
+ lateinit var docsSourcesConfiguration: Configuration
+ lateinit var samplesSourcesConfiguration: Configuration
+ lateinit var dependencyClasspath: FileCollection
+
+ override fun apply(project: Project) {
+ this.project = project
+ docsType = project.name.removePrefix("docs-")
+ project.plugins.all { plugin ->
+ when (plugin) {
+ is LibraryPlugin -> {
+ val libraryExtension = project.extensions.getByType<LibraryExtension>()
+ libraryExtension.compileSdkVersion = SupportConfig.COMPILE_SDK_VERSION
+ libraryExtension.buildToolsVersion = SupportConfig.BUILD_TOOLS_VERSION
+
+ // Use a local debug keystore to avoid build server issues.
+ val debugSigningConfig = libraryExtension.signingConfigs.getByName("debug")
+ debugSigningConfig.storeFile = project.getKeystore()
+ libraryExtension.buildTypes.all { buildType ->
+ // Sign all the builds (including release) with debug key
+ buildType.signingConfig = debugSigningConfig
+ }
+ }
+ }
+ }
+ disableUnneededTasks()
+ createConfigurations()
+ val buildOnServer = project.tasks.register<DocsBuildOnServer>("buildOnServer") {
+ buildId = getBuildId()
+ docsType = this@AndroidXDocsPlugin.docsType
+ distributionDirectory = project.getDistributionDirectory()
+ }
+
+ val unzippedSamplesSources = File(project.buildDir, "unzippedSampleSources")
+ val unzipSamplesTask = configureUnzipTask(
+ "unzipSampleSources",
+ unzippedSamplesSources,
+ samplesSourcesConfiguration
+ )
+ val unzippedDocsSources = File(project.buildDir, "unzippedDocsSources")
+ val unzipDocsTask = configureUnzipTask(
+ "unzipDocsSources",
+ unzippedDocsSources,
+ docsSourcesConfiguration
+ )
+
+ val unzippedSourcesForDackka = File(project.buildDir, "unzippedSourcesForDackka")
+ val unzipSourcesForDackkaTask = configureDackkaUnzipTask(
+ unzippedSourcesForDackka,
+ docsSourcesConfiguration
+ )
+
+ configureDackka(
+ unzippedSourcesForDackka,
+ unzipSourcesForDackkaTask,
+ unzippedSamplesSources,
+ unzipSamplesTask,
+ dependencyClasspath,
+ buildOnServer
+ )
+ configureDokka(
+ unzippedDocsSources,
+ unzipDocsTask,
+ unzippedSamplesSources,
+ unzipSamplesTask,
+ dependencyClasspath,
+ buildOnServer
+ )
+ configureDoclava(
+ unzippedDocsSources,
+ unzipDocsTask,
+ dependencyClasspath,
+ buildOnServer
+ )
+ }
+
+ /**
+ * Creates and configures a task that will build a list of all sources for projects in
+ * [docsConfiguration] configuration, resolve them and put them to [destinationDirectory].
+ */
+ private fun configureUnzipTask(
+ taskName: String,
+ destinationDirectory: File,
+ docsConfiguration: Configuration
+ ): TaskProvider<Sync> {
+ @Suppress("UnstableApiUsage")
+ return project.tasks.register(
+ taskName,
+ Sync::class.java
+ ) { task ->
+ val sources = docsConfiguration.incoming.artifactView { }.files
+ task.from(
+ sources.elements.map { jars ->
+ jars.map {
+ project.zipTree(it).matching {
+ // Filter out files that documentation tools cannot process.
+ it.exclude("**/*.MF")
+ it.exclude("**/*.aidl")
+ it.exclude("**/META-INF/**")
+ it.exclude("**/OWNERS")
+ it.exclude("**/package.html")
+ it.exclude("**/*.md")
+ }
+ }
+ }
+ )
+ task.into(destinationDirectory)
+ // TODO(123020809) remove this filter once it is no longer necessary to prevent Dokka
+ // from failing
+ val regex = Regex("@attr ref ([^*]*)styleable#([^_*]*)_([^*]*)$")
+ task.filter { line ->
+ regex.replace(line, "{@link $1attr#$3}")
+ }
+ }
+ }
+
+ /**
+ * Creates and configures a task that will build a list of select sources from jars and places
+ * them in [destinationDirectory].
+ *
+ * This is a modified version of [configureUnzipTask], customized for Dackka usage.
+ */
+ private fun configureDackkaUnzipTask(
+ destinationDirectory: File,
+ docsConfiguration: Configuration
+ ): TaskProvider<Sync> {
+ return project.tasks.register("unzipSourcesForDackka", Sync::class.java) { task ->
+
+ val sources = docsConfiguration.incoming.artifactView { }.files
+
+ task.from(
+ sources.elements.map { jars ->
+ jars.map {
+ project.zipTree(it)
+ }
+ }
+ )
+ task.into(destinationDirectory)
+ task.duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ }
+ }
+
+ /**
+ * The following configurations are created to build a list of projects that need to be
+ * documented and should be used from build.gradle of docs projects for the following:
+ * - docs(project(":foo:foo") or docs("androidx.foo:foo:1.0.0") for docs sources
+ * - samples(project(":foo:foo-samples") or samples("androidx.foo:foo-samples:1.0.0") for
+ * samples sources
+ * - stubs(project(":foo:foo-stubs")) - stubs needed for a documented library
+ */
+ private fun createConfigurations() {
+ project.dependencies.components.all<SourcesVariantRule>()
+ val docsConfiguration = project.configurations.create("docs") {
+ it.isCanBeResolved = false
+ it.isCanBeConsumed = false
+ }
+ val samplesConfiguration = project.configurations.create("samples") {
+ it.isCanBeResolved = false
+ it.isCanBeConsumed = false
+ }
+ val stubsConfiguration = project.configurations.create("stubs") {
+ it.isCanBeResolved = false
+ it.isCanBeConsumed = false
+ }
+
+ fun Configuration.setResolveSources() {
+ isTransitive = false
+ isCanBeConsumed = false
+ attributes {
+ it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
+ it.attribute(
+ Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION)
+ )
+ it.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.SOURCES))
+ }
+ }
+ docsSourcesConfiguration = project.configurations.create("docs-sources") {
+ it.setResolveSources()
+ it.extendsFrom(docsConfiguration)
+ }
+ samplesSourcesConfiguration = project.configurations.create("samples-sources") {
+ it.setResolveSources()
+ it.extendsFrom(samplesConfiguration)
+ }
+
+ fun Configuration.setResolveClasspathForUsage(usage: String) {
+ isCanBeConsumed = false
+ attributes {
+ it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(usage))
+ it.attribute(
+ Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)
+ )
+ it.attribute(BuildTypeAttr.ATTRIBUTE, project.objects.named("release"))
+ }
+ extendsFrom(docsConfiguration, samplesConfiguration, stubsConfiguration)
+ }
+
+ // Build a compile & runtime classpaths for needed for documenting the libraries
+ // from the configurations above.
+ val docsCompileClasspath = project.configurations.create("docs-compile-classpath") {
+ it.setResolveClasspathForUsage(Usage.JAVA_API)
+ }
+ val docsRuntimeClasspath = project.configurations.create("docs-runtime-classpath") {
+ it.setResolveClasspathForUsage(Usage.JAVA_RUNTIME)
+ }
+ listOf(docsCompileClasspath, docsRuntimeClasspath).forEach { config ->
+ config.resolutionStrategy {
+ it.eachDependency { details ->
+ if (details.requested.group == "org.jetbrains.kotlin") {
+ details.useVersion(KOTLIN_VERSION)
+ }
+ }
+ }
+ }
+ dependencyClasspath = docsCompileClasspath.incoming.artifactView {
+ it.attributes.attribute(
+ Attribute.of("artifactType", String::class.java),
+ "android-classes"
+ )
+ }.files + docsRuntimeClasspath.incoming.artifactView {
+ it.attributes.attribute(
+ Attribute.of("artifactType", String::class.java),
+ "android-classes"
+ )
+ }.files
+ }
+
+ private fun configureDackka(
+ unzippedDocsSources: File,
+ unzipDocsTask: TaskProvider<Sync>,
+ unzippedSamplesSources: File,
+ unzipSamplesTask: TaskProvider<Sync>,
+ dependencyClasspath: FileCollection,
+ buildOnServer: TaskProvider<*>
+ ) {
+ val generatedDocsDir = project.file("${project.buildDir}/dackkaDocs")
+
+ val dackkaConfiguration = project.configurations.create("dackka").apply {
+ dependencies.add(project.dependencies.create(DACKKA_DEPENDENCY))
+ }
+
+ val dackkaTask = project.tasks.register("dackkaDocs", DackkaTask::class.java) { task ->
+ task.apply {
+ dependsOn(dackkaConfiguration)
+ dependsOn(unzipDocsTask)
+ dependsOn(unzipSamplesTask)
+
+ description = "Generates reference documentation using a Google devsite Dokka" +
+ " plugin. Places docs in $generatedDocsDir"
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+
+ dackkaClasspath.from(project.files(dackkaConfiguration))
+ destinationDir = generatedDocsDir
+ frameworkSamplesDir = File(project.rootDir, "samples")
+ samplesDir = unzippedSamplesSources
+ sourcesDir = unzippedDocsSources
+ docsProjectDir = File(project.rootDir, "docs-public")
+ dependenciesClasspath = androidJarFile(project) + dependencyClasspath
+ excludedPackages = hiddenPackages.toSet()
+ excludedPackagesForJava = hiddenPackagesJava
+ excludedPackagesForKotlin = emptySet()
+ }
+ }
+
+ val zipTask = project.tasks.register("zipDackkaDocs", Zip::class.java) { task ->
+ task.apply {
+ dependsOn(dackkaTask)
+ from(generatedDocsDir)
+
+ val baseName = "dackka-$docsType-docs"
+ val buildId = getBuildId()
+ archiveBaseName.set(baseName)
+ archiveVersion.set(buildId)
+ destinationDirectory.set(project.getDistributionDirectory())
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+
+ val filePath = "${project.getDistributionDirectory().canonicalPath}/"
+ val fileName = "$baseName-$buildId.zip"
+ val destinationFile = filePath + fileName
+ description = "Zips Java and Kotlin documentation (generated via Dackka in the" +
+ " style of d.android.com) into $destinationFile"
+ }
+ }
+ buildOnServer.configure { it.dependsOn(zipTask) }
+ }
+
+ private fun configureDokka(
+ unzippedDocsSources: File,
+ unzipDocsTask: TaskProvider<Sync>,
+ unzippedSamplesSources: File,
+ unzipSamplesTask: TaskProvider<Sync>,
+ dependencyClasspath: FileCollection,
+ buildOnServer: TaskProvider<*>
+ ) {
+ val dokkaTask = Dokka.createDokkaTask(
+ project,
+ hiddenPackages,
+ "Kotlin",
+ "dac",
+ "/reference/kotlin"
+ )
+ dokkaTask.configure { task ->
+ task.sourceDirs += unzippedDocsSources
+ task.sourceDirs += unzippedSamplesSources
+ task.dependsOn(unzipDocsTask)
+ task.dependsOn(unzipSamplesTask)
+
+ val androidJar = androidJarFile(project)
+ // DokkaTask tries to resolve DokkaTask#classpath right away for jars that might not
+ // be there yet. Delay the setting of this property to before we run the task.
+ task.inputs.files(androidJar, dependencyClasspath)
+ task.doFirst { dokkaTask ->
+ dokkaTask as DokkaAndroidTask
+ val packages =
+ unzippedSamplesSources.walkTopDown().filter { it.isFile }.mapNotNull { file ->
+ val lines = file.readLines()
+ lines.find { line ->
+ line.startsWith("package ")
+ }?.replace("package ", "")
+ }.distinct()
+
+ packages.forEach { packageName ->
+ val opts = PackageOptions()
+ opts.prefix = packageName
+ opts.suppress = true
+ dokkaTask.perPackageOptions.add(opts)
+ }
+
+ dokkaTask.classpath = project.files(dokkaTask.classpath)
+ .plus(project.files(androidJar))
+ .plus(dependencyClasspath)
+ }
+ }
+ val zipTask = project.tasks.register("zipDokkaDocs", Zip::class.java) {
+ it.apply {
+ it.dependsOn(dokkaTask)
+ from(dokkaTask.map { it.outputDirectory }) { copySpec ->
+ copySpec.into("reference/kotlin")
+ }
+ val baseName = "dokka-$docsType-docs"
+ val buildId = getBuildId()
+ archiveBaseName.set(baseName)
+ archiveVersion.set(buildId)
+ destinationDirectory.set(project.getDistributionDirectory())
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+ val filePath = "${project.getDistributionDirectory().canonicalPath}/"
+ val fileName = "$baseName-$buildId.zip"
+ val destinationFile = filePath + fileName
+ description = "Zips Kotlin documentation (generated via Dokka in the " +
+ "style of d.android.com) into $destinationFile"
+ }
+ }
+ buildOnServer.configure { it.dependsOn(zipTask) }
+ }
+
+ private fun configureDoclava(
+ unzippedDocsSources: File,
+ unzipDocsTask: TaskProvider<Sync>,
+ dependencyClasspath: FileCollection,
+ buildOnServer: TaskProvider<*>
+ ) {
+ // Hack to force tools.jar (required by com.sun.javadoc) to be available on the Doclava
+ // run-time classpath. Note this breaks the ability to use JDK 9+ for compilation.
+ val doclavaConfiguration = project.configurations.create("doclava")
+ doclavaConfiguration.dependencies.add(project.dependencies.create(DOCLAVA_DEPENDENCY))
+ doclavaConfiguration.dependencies.add(
+ project.dependencies.create(
+ project.files(System.getenv("JAVA_TOOLS_JAR"))
+ )
+ )
+
+ val annotationConfiguration = project.configurations.create("annotation")
+ annotationConfiguration.dependencies.add(
+ project.dependencies.project(
+ mapOf("path" to ":fakeannotations")
+ )
+ )
+
+ val generatedSdk = File(project.buildDir, "generatedsdk")
+ val generateSdkApiTask = createGenerateSdkApiTask(
+ project, doclavaConfiguration, annotationConfiguration, generatedSdk
+ )
+
+ val destDir = File(project.buildDir, "javadoc")
+ val offlineOverride = project.findProject("offlineDocs") as String?
+ val offline = if (offlineOverride != null) { offlineOverride == "true" } else false
+ val dacOptions = DacOptions("androidx", "ANDROIDX_DATA")
+
+ val doclavaTask = project.tasks.register("doclavaDocs", DoclavaTask::class.java) {
+ it.apply {
+ dependsOn(unzipDocsTask)
+ dependsOn(generateSdkApiTask)
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+ description = "Generates Java documentation in the style of d.android.com. To " +
+ "generate offline docs use \'-PofflineDocs=true\' parameter. Places the " +
+ "documentation in $destDir"
+ dependsOn(doclavaConfiguration)
+ setDocletpath(doclavaConfiguration)
+ destinationDir = destDir
+ classpath = androidJarFile(project) + dependencyClasspath
+ checksConfig = GENERATE_DOCS_CONFIG
+ extraArgumentsBuilder.apply {
+ addStringOption(
+ "templatedir",
+ "${project.getCheckoutRoot()}/external/doclava/res/assets/templates-sdk"
+ )
+ // Note, this is pointing to the root checkout directory.
+ addStringOption(
+ "samplesdir",
+ "${project.rootDir}/samples"
+ )
+ addStringOption(
+ "federate",
+ listOf("Android", "https://developer.android.com")
+ )
+ addStringOption(
+ "federationapi",
+ listOf(
+ "Android",
+ generateSdkApiTask.get().apiFile?.absolutePath.toString()
+ )
+ )
+ addStringOption("hdf", listOf("android.whichdoc", "online"))
+ addStringOption("hdf", listOf("android.hasSamples", "true"))
+ addStringOption("hdf", listOf("dac", "true"))
+
+ // Specific to reference docs.
+ if (!offline) {
+ addStringOption("toroot", "/")
+ addOption("devsite")
+ addOption("yamlV2")
+ addStringOption("dac_libraryroot", dacOptions.libraryroot)
+ addStringOption("dac_dataname", dacOptions.dataname)
+ }
+ }
+ it.source(project.fileTree(unzippedDocsSources))
+ }
+ }
+ val zipTask = project.tasks.register("zipDoclavaDocs", Zip::class.java) {
+ it.apply {
+ it.dependsOn(doclavaTask)
+ from(doclavaTask.map { it.destinationDir!! })
+ val baseName = "doclava-$docsType-docs"
+ val buildId = getBuildId()
+ archiveBaseName.set(baseName)
+ archiveVersion.set(buildId)
+ destinationDirectory.set(project.getDistributionDirectory())
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+ val filePath = "${project.getDistributionDirectory().canonicalPath}/"
+ val fileName = "$baseName-$buildId.zip"
+ val destinationFile = filePath + fileName
+ description = "Zips Java documentation (generated via Doclava in the " +
+ "style of d.android.com) into $destinationFile"
+ }
+ }
+ buildOnServer.configure { it.dependsOn(zipTask) }
+ }
+
+ /**
+ * Replace all tests etc with empty task, so we don't run anything
+ * it is more effective then task.enabled = false, because we avoid executing deps as well
+ */
+ private fun disableUnneededTasks() {
+ var reentrance = false
+ project.tasks.whenTaskAdded { task ->
+ if (task is Test || task.name.startsWith("assemble") ||
+ task.name == "lint" ||
+ task.name == "transformDexArchiveWithExternalLibsDexMergerForPublicDebug" ||
+ task.name == "transformResourcesWithMergeJavaResForPublicDebug" ||
+ task.name == "checkPublicDebugDuplicateClasses"
+ ) {
+ if (!reentrance) {
+ reentrance = true
+ project.tasks.named(task.name) {
+ it.actions = emptyList()
+ it.dependsOn(emptyList<Task>())
+ }
+ reentrance = false
+ }
+ }
+ }
+ }
+}
+
+open class DocsBuildOnServer : DefaultTask() {
+ @Internal
+ lateinit var docsType: String
+ @Internal
+ lateinit var buildId: String
+ @Internal
+ lateinit var distributionDirectory: File
+
+ @InputFiles
+ fun getRequiredFiles(): List<File> {
+ return listOf(
+ File(distributionDirectory, "dackka-$docsType-docs-$buildId.zip"),
+ File(distributionDirectory, "doclava-$docsType-docs-$buildId.zip"),
+ File(distributionDirectory, "dokka-$docsType-docs-$buildId.zip")
+ )
+ }
+
+ @TaskAction
+ fun checkAllBuildOutputs() {
+ val missingFiles = mutableListOf<String>()
+ getRequiredFiles().forEach { file ->
+ if (!file.exists()) {
+ missingFiles.add(file.path)
+ }
+ }
+
+ if (missingFiles.isNotEmpty()) {
+ val missingFileString = missingFiles.reduce { acc, s -> "$acc, $s" }
+ throw FileNotFoundException("buildOnServer required output missing: $missingFileString")
+ }
+ }
+}
+
+/**
+ * Adapter rule to handles prebuilt dependencies that do not use Gradle Metadata (only pom).
+ * We create a new variant sources that we can later use in the same way we do for tip of tree
+ * projects and prebuilts with Gradle Metadata.
+ */
+abstract class SourcesVariantRule : ComponentMetadataRule {
+ @get:Inject
+ abstract val objects: ObjectFactory
+ override fun execute(context: ComponentMetadataContext) {
+ context.details.maybeAddVariant("sources", "runtime") {
+ it.attributes {
+ it.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
+ it.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
+ it.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
+ }
+ it.withFiles {
+ it.removeAllFiles()
+ it.addFile("${context.details.id.name}-${context.details.id.version}-sources.jar")
+ }
+ }
+ }
+}
+
+private const val DACKKA_DEPENDENCY = "com.google.devsite:dackka:0.0.9"
+private const val DOCLAVA_DEPENDENCY = "com.android:doclava:1.0.6"
+
+// List of packages to exclude from both Java and Kotlin refdoc generation
+private val hiddenPackages = listOf(
+ "androidx.camera.camera2.impl",
+ "androidx.camera.camera2.internal",
+ "androidx.camera.camera2.internal.compat",
+ "androidx.camera.camera2.internal.compat.params",
+ "androidx.camera.core.impl",
+ "androidx.camera.core.impl.annotation",
+ "androidx.camera.core.impl.utils",
+ "androidx.camera.core.impl.utils.executor",
+ "androidx.camera.core.impl.utils.futures",
+ "androidx.camera.core.internal",
+ "androidx.camera.core.internal.utils",
+ "androidx.core.internal",
+ "androidx.preference.internal",
+ "androidx.wear.internal.widget.drawer",
+ "androidx.webkit.internal",
+ "androidx.work.impl",
+ "androidx.work.impl.background",
+ "androidx.work.impl.background.gcm",
+ "androidx.work.impl.background.systemalarm",
+ "androidx.work.impl.background.systemjob",
+ "androidx.work.impl.constraints",
+ "androidx.work.impl.constraints.controllers",
+ "androidx.work.impl.constraints.trackers",
+ "androidx.work.impl.model",
+ "androidx.work.impl.utils",
+ "androidx.work.impl.utils.futures",
+ "androidx.work.impl.utils.taskexecutor"
+)
+
+// Set of packages to exclude from Java refdoc generation
+private val hiddenPackagesJava = setOf(
+ "androidx.compose.animation",
+ "androidx.compose.animation.core",
+ "androidx.compose.animation.graphics",
+ "androidx.compose.animation.graphics.res",
+ "androidx.compose.animation.graphics.vector",
+ "androidx.compose.animation.graphics.vector.compat",
+ "androidx.compose.foundation",
+ "androidx.compose.foundation.gestures",
+ "androidx.compose.foundation.interaction",
+ "androidx.compose.foundation.layout",
+ "androidx.compose.foundation.lazy",
+ "androidx.compose.foundation.selection",
+ "androidx.compose.foundation.shape",
+ "androidx.compose.foundation.text",
+ "androidx.compose.foundation.text.selection",
+ "androidx.compose.material",
+ "androidx.compose.material.icons",
+ "androidx.compose.material.icons.filled",
+ "androidx.compose.material.icons.outlined",
+ "androidx.compose.material.icons.rounded",
+ "androidx.compose.material.icons.sharp",
+ "androidx.compose.material.icons.twotone",
+ "androidx.compose.material.ripple",
+ "androidx.compose.runtime",
+ "androidx.compose.runtime.collection",
+ "androidx.compose.runtime.internal",
+ "androidx.compose.runtime.livedata",
+ "androidx.compose.runtime.rxjava2",
+ "androidx.compose.runtime.rxjava3",
+ "androidx.compose.runtime.saveable",
+ "androidx.compose.runtime.snapshots",
+ "androidx.compose.runtime.tooling",
+ "androidx.compose.ui",
+ "androidx.compose.ui.autofill",
+ "androidx.compose.ui.draw",
+ "androidx.compose.ui.focus",
+ "androidx.compose.ui.geometry",
+ "androidx.compose.ui.graphics",
+ "androidx.compose.ui.graphics.colorspace",
+ "androidx.compose.ui.graphics.drawscope",
+ "androidx.compose.ui.graphics.painter",
+ "androidx.compose.ui.graphics.vector",
+ "androidx.compose.ui.hapticfeedback",
+ "androidx.compose.ui.input.key",
+ "androidx.compose.ui.input.nestedscroll",
+ "androidx.compose.ui.input.pointer",
+ "androidx.compose.ui.input.pointer.util",
+ "androidx.compose.ui.layout",
+ "androidx.compose.ui.node",
+ "androidx.compose.ui.platform",
+ "androidx.compose.ui.res",
+ "androidx.compose.ui.semantics",
+ "androidx.compose.ui.state",
+ "androidx.compose.ui.test",
+ "androidx.compose.ui.test.junit4",
+ "androidx.compose.ui.test.junit4.android",
+ "androidx.compose.ui.text",
+ "androidx.compose.ui.text.android",
+ "androidx.compose.ui.text.font",
+ "androidx.compose.ui.text.input",
+ "androidx.compose.ui.text.intl",
+ "androidx.compose.ui.text.platform.extensions",
+ "androidx.compose.ui.text.style",
+ "androidx.compose.ui.tooling",
+ "androidx.compose.ui.tooling.data",
+ "androidx.compose.ui.tooling.preview",
+ "androidx.compose.ui.tooling.preview.datasource",
+ "androidx.compose.ui.unit",
+ "androidx.compose.ui.util",
+ "androidx.compose.ui.viewinterop",
+ "androidx.compose.ui.window",
+ "androidx.activity.compose",
+ "androidx.hilt.navigation.compose",
+ "androidx.navigation.compose",
+ "androidx.paging.compose",
+ "androidx.wear.compose",
+ "androidx.wear.compose.foundation",
+ "androidx.wear.compose.material",
+)
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXComposePlugin.properties b/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXComposePlugin.properties
similarity index 100%
rename from buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXComposePlugin.properties
rename to buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXComposePlugin.properties
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXDocsPlugin.properties b/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXDocsPlugin.properties
similarity index 100%
rename from buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXDocsPlugin.properties
rename to buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXDocsPlugin.properties
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXPlugin.properties b/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXPlugin.properties
similarity index 100%
rename from buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXPlugin.properties
rename to buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXPlugin.properties
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXRootPlugin.properties b/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXRootPlugin.properties
similarity index 100%
rename from buildSrc/src/main/resources/META-INF/gradle-plugins/AndroidXRootPlugin.properties
rename to buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXRootPlugin.properties
diff --git a/buildSrc/private/README.md b/buildSrc/private/README.md
new file mode 100644
index 0000000..97ac616
--- /dev/null
+++ b/buildSrc/private/README.md
@@ -0,0 +1,7 @@
+This is the :buildSrc:impl project
+
+It contains code that is used to configure other projects in this repository but that does not need to be added to the classpaths of the build scripts of those projects.
+
+This means that if code in this project is changed, it should not necessarily modify the classpath of those projects and should not automatically invalidate the up-to-datedness of tasks applied in those projects.
+
+See b/140265324 for more information
diff --git a/buildSrc/src/main/kotlin/androidx/build/AgpExtensions.kt b/buildSrc/private/src/main/kotlin/androidx/build/AgpExtensions.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/AgpExtensions.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/AgpExtensions.kt
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
new file mode 100644
index 0000000..35cbbb7
--- /dev/null
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build
+
+import androidx.build.checkapi.shouldConfigureApiTasks
+import groovy.lang.Closure
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.provider.Property
+import java.util.ArrayList
+
+/**
+ * Extension for [AndroidXPlugin] that's responsible for holding configuration options.
+ */
+open class AndroidXExtension(val project: Project) {
+
+ var name: Property<String?> = project.objects.property(String::class.java)
+ fun setName(newName: String) { name.set(newName) }
+ var mavenVersion: Version? = null
+ set(value) {
+ field = value
+ chooseProjectVersion()
+ }
+ var mavenGroup: LibraryGroup? = null
+ set(value) {
+ field = value
+ chooseProjectVersion()
+ }
+ private val ALLOWED_EXTRA_PREFIXES = listOf("-alpha", "-beta", "-rc", "-dev", "-SNAPSHOT")
+
+ private fun chooseProjectVersion() {
+ val version: Version
+ val group: String? = mavenGroup?.group
+ val groupVersion: Version? = mavenGroup?.forcedVersion
+ val mavenVersion: Version? = mavenVersion
+ if (mavenVersion != null) {
+ if (groupVersion != null && !isGroupVersionOverrideAllowed()) {
+ throw GradleException(
+ "Cannot set mavenVersion (" + mavenVersion +
+ ") for a project (" + project +
+ ") whose mavenGroup already specifies forcedVersion (" + groupVersion +
+ ")"
+ )
+ } else {
+ verifyVersionExtraFormat(mavenVersion)
+ version = mavenVersion
+ }
+ } else {
+ if (groupVersion != null) {
+ verifyVersionExtraFormat(groupVersion)
+ version = groupVersion
+ } else {
+ return
+ }
+ }
+ if (group != null) {
+ project.group = group
+ }
+ project.version = if (isSnapshotBuild()) version.copy(extra = "-SNAPSHOT") else version
+ versionIsSet = true
+ }
+
+ private fun verifyVersionExtraFormat(version: Version) {
+ val extra = version.extra
+ if (extra != null) {
+ if (!version.isSnapshot() && project.isVersionExtraCheckEnabled()) {
+ if (ALLOWED_EXTRA_PREFIXES.any { extra.startsWith(it) }) {
+ for (potentialPrefix in ALLOWED_EXTRA_PREFIXES) {
+ if (extra.startsWith(potentialPrefix)) {
+ val secondExtraPart = extra.removePrefix(
+ potentialPrefix
+ )
+ if (secondExtraPart.toIntOrNull() == null) {
+ throw IllegalArgumentException(
+ "Version $version is not" +
+ " a properly formatted version, please ensure that " +
+ "$potentialPrefix is followed by a number only"
+ )
+ }
+ }
+ }
+ } else {
+ throw IllegalArgumentException(
+ "Version $version is not a proper " +
+ "version, version suffixes following major.minor.patch should " +
+ "be one of ${ALLOWED_EXTRA_PREFIXES.joinToString(", ")}"
+ )
+ }
+ }
+ }
+ }
+
+ private fun isGroupVersionOverrideAllowed(): Boolean {
+ // Grant an exception to the same-version-group policy for artifacts that haven't shipped a
+ // stable API surface, e.g. 1.0.0-alphaXX, to allow for rapid early-stage development.
+ val version = mavenVersion
+ return version != null && version.major == 1 && version.minor == 0 && version.patch == 0 &&
+ version.isAlpha()
+ }
+
+ private var versionIsSet = false
+ fun isVersionSet(): Boolean {
+ return versionIsSet
+ }
+ var description: String? = null
+ var inceptionYear: String? = null
+ /**
+ * targetsJavaConsumers = true, if project is intended to be accessed from Java-language
+ * source code.
+ */
+ var targetsJavaConsumers = true
+ get() {
+ when (project.path) {
+ // add per-project overrides here
+ // for example
+ // the following project is intended to be accessed from Java
+ // ":compose:lint:internal-lint-checks" -> return true
+ // the following project is not intended to be accessed from Java
+ // ":annotation:annotation" -> return false
+ }
+ // TODO: rework this to use LibraryType. Fork Library and KolinOnlyLibrary?
+ if (project.path.contains("-ktx")) return false
+ if (project.path.contains("compose")) return false
+ if (project.path.startsWith(":ui")) return false
+ return field
+ }
+ private var licenses: MutableCollection<License> = ArrayList()
+
+ // Should only be used to override LibraryType.publish, if a library isn't ready to publish yet
+ var publish: Publish = Publish.UNSET
+ // Allow gradual transition from publish to library type
+ get() = if (field == Publish.UNSET && type != LibraryType.UNSET) type.publish else field
+ /**
+ * Whether to run API tasks such as tracking and linting. The default value is
+ * [RunApiTasks.Auto], which automatically picks based on the project's properties.
+ */
+ // TODO: decide whether we want to support overriding runApiTasks
+ // @Deprecated("Replaced with AndroidXExtension.type: LibraryType.runApiTasks")
+ var runApiTasks: RunApiTasks = RunApiTasks.Auto
+ get() = if (field == RunApiTasks.Auto && type != LibraryType.UNSET) type.checkApi else field
+ var type: LibraryType = LibraryType.UNSET
+ var failOnDeprecationWarnings = true
+
+ var legacyDisableKotlinStrictApiMode = false
+
+ var benchmarkRunAlsoInterpreted = false
+
+ fun shouldEnforceKotlinStrictApiMode(): Boolean {
+ return !legacyDisableKotlinStrictApiMode &&
+ shouldConfigureApiTasks()
+ }
+
+ fun license(closure: Closure<Any>): License {
+ val license = project.configure(License(), closure) as License
+ licenses.add(license)
+ return license
+ }
+
+ fun getLicenses(): Collection<License> {
+ return licenses
+ }
+
+ companion object {
+ const val DEFAULT_UNSPECIFIED_VERSION = "unspecified"
+ }
+}
+
+class License {
+ var name: String? = null
+ var url: String? = null
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/CreateAggregateLibraryBuildInfoFileTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/CreateAggregateLibraryBuildInfoFileTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/CreateAggregateLibraryBuildInfoFileTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/CreateAggregateLibraryBuildInfoFileTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/CreateLibraryBuildInfoFileTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/CreateLibraryBuildInfoFileTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/CreateLibraryBuildInfoFileTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/CreateLibraryBuildInfoFileTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/InspectionRelease.kt b/buildSrc/private/src/main/kotlin/androidx/build/InspectionRelease.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/InspectionRelease.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/InspectionRelease.kt
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/Jetify.kt b/buildSrc/private/src/main/kotlin/androidx/build/Jetify.kt
new file mode 100644
index 0000000..85faa23
--- /dev/null
+++ b/buildSrc/private/src/main/kotlin/androidx/build/Jetify.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build
+
+import org.gradle.api.Project
+import org.gradle.api.file.RegularFile
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Exec
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.api.tasks.bundling.Zip
+
+val archivesToDejetify = listOf(
+ "m2repository/androidx/activity/**",
+ "m2repository/androidx/ads/identifier/**",
+ "m2repository/androidx/annotation/**",
+ "m2repository/androidx/autofill/**",
+ "m2repository/androidx/appcompat/**",
+ "m2repository/androidx/arch/**",
+ "m2repository/androidx/arch/core/**",
+ "m2repository/androidx/asynclayoutinflater/**",
+ "m2repository/androidx/benchmark/**",
+ "m2repository/androidx/biometric/**",
+ "m2repository/androidx/browser/**",
+ "m2repository/androidx/camera/**",
+ "m2repository/androidx/car/**",
+ "m2repository/androidx/cardview/**",
+ "m2repository/androidx/collection/collection/**",
+ "m2repository/androidx/collection/collection-ktx/**",
+ "m2repository/androidx/contentpager/**",
+ "m2repository/androidx/coordinatorlayout/**",
+ "m2repository/androidx/core/core/**",
+ "m2repository/androidx/core/core-ktx/**",
+ "m2repository/androidx/cursoradapter/**",
+ "m2repository/androidx/customview/**",
+ "m2repository/androidx/documentfile/**",
+ "m2repository/androidx/drawerlayout/**",
+ "m2repository/androidx/dynamicanimation/**",
+ "m2repository/androidx/emoji/**",
+ "m2repository/androidx/exifinterface/**",
+ "m2repository/androidx/fragment/fragment/**",
+ "m2repository/androidx/fragment/fragment-ktx/**",
+ "m2repository/androidx/fragment/fragment-testing/**",
+ "m2repository/androidx/gridlayout/**",
+ "m2repository/androidx/heifwriter/**",
+ "m2repository/androidx/interpolator/**",
+ "m2repository/androidx/leanback/**",
+ "m2repository/androidx/legacy/**",
+ "m2repository/androidx/lifecycle/**",
+ "m2repository/androidx/loader/**",
+ "m2repository/androidx/localbroadcastmanager/**",
+ "m2repository/androidx/media/media/**",
+ "m2repository/androidx/mediarouter/**",
+ "m2repository/androidx/navigation/**",
+ "m2repository/androidx/palette/palette/**",
+ "m2repository/androidx/percentlayout/**",
+ "m2repository/androidx/preference/preference/**",
+ "m2repository/androidx/print/**",
+ "m2repository/androidx/paging/**",
+ "m2repository/androidx/room/**",
+ "m2repository/androidx/work/**",
+ "m2repository/androidx/recommendation/**",
+ "m2repository/androidx/recyclerview/**",
+ "m2repository/androidx/remotecallback/**",
+ "m2repository/androidx/savedstate/**",
+ "m2repository/androidx/slice/slice-builders/**",
+ "m2repository/androidx/slice/slice-core/**",
+ "m2repository/androidx/slice/slice-view/**",
+ "m2repository/androidx/slidingpanelayout/**",
+ "m2repository/androidx/swiperefreshlayout/**",
+ "m2repository/androidx/sqlite/**",
+ "m2repository/androidx/textclassifier/**",
+ "m2repository/androidx/transition/**",
+ "m2repository/androidx/tvprovider/**",
+ "m2repository/androidx/vectordrawable/**",
+ "m2repository/androidx/versionedparcelable/**",
+ "m2repository/androidx/viewpager/**",
+ "m2repository/androidx/viewpager2/**",
+ "m2repository/androidx/wear/**",
+ "m2repository/androidx/webkit/**",
+ "m2repository/androidx/media2/**",
+ "m2repository/androidx/concurrent/**",
+ "m2repository/androidx/sharetarget/**"
+)
+
+fun Project.partiallyDejetifyArchiveTask(
+ archiveFile: Provider<RegularFile>
+): TaskProvider<Exec>? {
+ return findProject(":jetifier:jetifier-standalone")?.let { standaloneProject ->
+ val stripTask = stripArchiveForPartialDejetificationTask(archiveFile)
+
+ tasks.register("partiallyDejetifyArchive", Exec::class.java) {
+ val outputFileName = "${getDistributionDirectory().absolutePath}/" +
+ "top-of-tree-m2repository-partially-dejetified-${getBuildId()}.zip"
+ val jetifierBin = "${standaloneProject.buildDir}/install/jetifier-standalone/bin/" +
+ "jetifier-standalone"
+ val migrationConfig = "${standaloneProject.projectDir.parentFile}/migration.config"
+
+ it.dependsOn(stripTask)
+ it.inputs.file(stripTask.flatMap { it.archiveFile })
+ it.outputs.file(outputFileName)
+
+ it.commandLine = listOf(
+ jetifierBin,
+ "-i", "${it.inputs.files.singleFile}",
+ "-o", "${it.outputs.files.singleFile}",
+ "-c", migrationConfig,
+ "--log", "warning",
+ "--reversed",
+ "--rebuildTopOfTree"
+ )
+ }
+ }
+}
+
+fun Project.stripArchiveForPartialDejetificationTask(
+ archiveFile: Provider<RegularFile>
+): TaskProvider<Zip> {
+ return tasks.register("stripArchiveForPartialDejetification", Zip::class.java) {
+ it.dependsOn(rootProject.tasks.named(Release.FULL_ARCHIVE_TASK_NAME))
+ it.from(zipTree(archiveFile))
+ it.destinationDirectory.set(rootProject.buildDir)
+ it.archiveFileName.set("stripped_archive_partial.zip")
+ it.include(archivesToDejetify)
+ }
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/Ktlint.kt b/buildSrc/private/src/main/kotlin/androidx/build/Ktlint.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/Ktlint.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/Ktlint.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/ListAndroidXPropertiesTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ListAndroidXPropertiesTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/ListAndroidXPropertiesTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/ListAndroidXPropertiesTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
new file mode 100644
index 0000000..9bc6e49
--- /dev/null
+++ b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build
+
+import androidx.build.AndroidXComposePlugin.Companion.isMultiplatformEnabled
+import com.android.build.gradle.LibraryPlugin
+import groovy.util.Node
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.XmlProvider
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.api.component.SoftwareComponent
+import org.gradle.api.publish.PublishingExtension
+import org.gradle.api.publish.maven.MavenPom
+import org.gradle.api.publish.maven.MavenPublication
+import org.gradle.api.publish.tasks.GenerateModuleMetadata
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.create
+import org.gradle.kotlin.dsl.findByType
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
+import java.io.File
+
+fun Project.configureMavenArtifactUpload(extension: AndroidXExtension) {
+ apply(mapOf("plugin" to "maven-publish"))
+
+ afterEvaluate {
+ components.all { component ->
+ configureComponent(extension, component)
+ }
+ }
+}
+
+private fun Project.configureComponent(
+ extension: AndroidXExtension,
+ component: SoftwareComponent
+) {
+ if (extension.publish.shouldPublish() && component.isAndroidOrJavaReleaseComponent()) {
+ val androidxGroup = validateCoordinatesAndGetGroup(extension)
+ val projectArchiveDir = File(
+ getRepositoryDirectory(),
+ "${androidxGroup.group.replace('.', '/')}/$name"
+ )
+ group = androidxGroup.group
+ configure<PublishingExtension> {
+ repositories {
+ it.maven { repo ->
+ repo.setUrl(getRepositoryDirectory())
+ }
+ }
+ publications {
+ if (appliesJavaGradlePluginPlugin()) {
+ // The 'java-gradle-plugin' will also add to the 'pluginMaven' publication
+ it.create<MavenPublication>("pluginMaven")
+ tasks.getByName("publishPluginMavenPublicationToMavenRepository").doFirst {
+ removePreviouslyUploadedArchives(projectArchiveDir)
+ }
+ } else {
+ it.create<MavenPublication>("maven") {
+ from(component)
+ }
+ tasks.getByName("publishMavenPublicationToMavenRepository").doFirst {
+ removePreviouslyUploadedArchives(projectArchiveDir)
+ }
+ }
+ }
+ publications.withType(MavenPublication::class.java).all {
+ it.pom { pom ->
+ addInformativeMetadata(extension, pom)
+ tweakDependenciesMetadata(androidxGroup, pom)
+ }
+ }
+ }
+
+ // Register it as part of release so that we create a Zip file for it
+ Release.register(this, extension)
+
+ // Workaround for https://github.com/gradle/gradle/issues/11717
+ project.tasks.withType(GenerateModuleMetadata::class.java).configureEach { task ->
+ task.doLast {
+ val metadata = task.outputFile.asFile.get()
+ var text = metadata.readText()
+ metadata.writeText(
+ text.replace(
+ "\"buildId\": .*".toRegex(),
+ "\"buildId:\": \"${getBuildId()}\""
+ )
+ )
+ }
+ }
+
+ if (isMultiplatformEnabled()) {
+ configureMultiplatformPublication()
+ }
+ }
+}
+
+private fun Project.configureMultiplatformPublication() {
+ val multiplatformExtension = extensions.findByType<KotlinMultiplatformExtension>() ?: return
+
+ // publishMavenPublicationToMavenRepository will produce conflicting artifacts with the same
+ // name as the artifacts producing by publishKotlinMultiplatformPublicationToMavenRepository
+ project.tasks.findByName("publishMavenPublicationToMavenRepository")?.enabled = false
+
+ multiplatformExtension.targets.all { target ->
+ if (target is KotlinAndroidTarget) {
+ target.publishAllLibraryVariants()
+ }
+ }
+}
+
+private fun SoftwareComponent.isAndroidOrJavaReleaseComponent() =
+ name == "release" || name == "java"
+
+private fun Project.validateCoordinatesAndGetGroup(extension: AndroidXExtension): LibraryGroup {
+ val mavenGroup = extension.mavenGroup
+ ?: throw Exception("You must specify mavenGroup for $name project")
+ val strippedGroupId = mavenGroup.group.substringAfterLast(".")
+ if (mavenGroup.group.startsWith("androidx") && !name.startsWith(strippedGroupId)) {
+ throw Exception("Your artifactId must start with '$strippedGroupId'. (currently is $name)")
+ }
+ return mavenGroup
+}
+
+/**
+ * Delete any existing archives, so that developers don't get
+ * confused/surprised by the presence of old versions.
+ * Additionally, deleting old versions makes it more convenient to iterate
+ * over all existing archives without visiting archives having old versions too
+ */
+private fun removePreviouslyUploadedArchives(projectArchiveDir: File) {
+ projectArchiveDir.deleteRecursively()
+}
+
+private fun Project.addInformativeMetadata(extension: AndroidXExtension, pom: MavenPom) {
+ pom.name.set(extension.name)
+ pom.description.set(provider { extension.description })
+ pom.url.set(
+ provider {
+ fun defaultUrl() = "https://developer.android.com/jetpack/androidx/releases/" +
+ extension.mavenGroup!!.group.removePrefix("androidx.")
+ .replace(".", "-") +
+ "#" + extension.project.version()
+ getAlternativeProjectUrl() ?: defaultUrl()
+ }
+ )
+ pom.inceptionYear.set(provider { extension.inceptionYear })
+ pom.licenses { licenses ->
+ licenses.license { license ->
+ license.name.set("The Apache Software License, Version 2.0")
+ license.url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
+ license.distribution.set("repo")
+ }
+ for (extraLicense in extension.getLicenses()) {
+ licenses.license { license ->
+ license.name.set(provider { extraLicense.name })
+ license.url.set(provider { extraLicense.url })
+ license.distribution.set("repo")
+ }
+ }
+ }
+ pom.scm { scm ->
+ scm.url.set("https://cs.android.com/androidx/platform/frameworks/support")
+ scm.connection.set(ANDROID_GIT_URL)
+ }
+ pom.developers { devs ->
+ devs.developer { dev ->
+ dev.name.set("The Android Open Source Project")
+ }
+ }
+}
+
+private fun Project.tweakDependenciesMetadata(
+ mavenGroup: LibraryGroup,
+ pom: MavenPom
+) {
+ pom.withXml { xml ->
+ // The following code depends on getProjectsMap which is only available late in
+ // configuration at which point Java Library plugin's variants are not allowed to be
+ // modified. TODO remove the use of getProjectsMap and move to earlier configuration.
+ // For more context see:
+ // https://android-review.googlesource.com/c/platform/frameworks/support/+/1144664/8/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt#177
+ assignSingleVersionDependenciesInGroupForPom(xml, mavenGroup)
+ assignAarTypes(xml)
+ }
+}
+
+// TODO(aurimas): remove this when Gradle bug is fixed.
+// https://github.com/gradle/gradle/issues/3170
+private fun Project.assignAarTypes(xml: XmlProvider) {
+ val androidxDependencies = HashSet<Dependency>()
+ collectDependenciesForConfiguration(androidxDependencies, "api")
+ collectDependenciesForConfiguration(androidxDependencies, "implementation")
+ collectDependenciesForConfiguration(androidxDependencies, "compile")
+
+ val dependencies = xml.asNode().children().find {
+ it is Node && it.name().toString().endsWith("dependencies")
+ } as Node?
+
+ dependencies?.children()?.forEach { dep ->
+ if (dep !is Node) {
+ return@forEach
+ }
+ val groupId = dep.children().first {
+ it is Node && it.name().toString().endsWith("groupId")
+ } as Node
+ val artifactId = dep.children().first {
+ it is Node && it.name().toString().endsWith("artifactId")
+ } as Node
+ if (isAndroidProject(
+ groupId.children()[0] as String,
+ artifactId.children()[0] as String, androidxDependencies
+ )
+ ) {
+ dep.appendNode("type", "aar")
+ }
+ }
+}
+
+/**
+ * Modifies the given .pom to specify that every dependency in <group> refers to a single version
+ * and can't be automatically promoted to a new version.
+ * This will replace, for example, a version string of "1.0" with a version string of "[1.0]"
+ *
+ * Note: this is not enforced in Gradle nor in plain Maven (without the Enforcer plugin)
+ * (https://github.com/gradle/gradle/issues/8297)
+ */
+private fun assignSingleVersionDependenciesInGroupForPom(
+ xml: XmlProvider,
+ mavenGroup: LibraryGroup
+) {
+ if (!mavenGroup.requireSameVersion) {
+ return
+ }
+
+ val dependencies = xml.asNode().children().find {
+ it is Node && it.name().toString().endsWith("dependencies")
+ } as Node?
+ dependencies?.children()?.forEach { dep ->
+ if (dep !is Node) {
+ return@forEach
+ }
+ val groupId = dep.children().first {
+ it is Node && it.name().toString().endsWith("groupId")
+ } as Node
+ if (groupId.children()[0].toString() == mavenGroup.group) {
+ val versionNode = dep.children().first {
+ it is Node && it.name().toString().endsWith("version")
+ } as Node
+ val declaredVersion = versionNode.children()[0].toString()
+ if (isVersionRange(declaredVersion)) {
+ throw GradleException(
+ "Unsupported version '$declaredVersion': " +
+ "already is a version range"
+ )
+ }
+ val pinnedVersion = "[$declaredVersion]"
+ versionNode.setValue(pinnedVersion)
+ }
+ }
+}
+
+private fun isVersionRange(text: String): Boolean {
+ return text.contains("[") ||
+ text.contains("]") ||
+ text.contains("(") ||
+ text.contains(")") ||
+ text.contains(",")
+}
+
+private fun Project.collectDependenciesForConfiguration(
+ androidxDependencies: MutableSet<Dependency>,
+ name: String
+) {
+ val config = configurations.findByName(name)
+ config?.dependencies?.forEach { dep ->
+ if (dep.group?.startsWith("androidx.") == true) {
+ androidxDependencies.add(dep)
+ }
+ }
+}
+
+private fun Project.isAndroidProject(
+ groupId: String,
+ artifactId: String,
+ deps: Set<Dependency>
+): Boolean {
+ for (dep in deps) {
+ if (dep is ProjectDependency) {
+ if (dep.group == groupId && dep.name == artifactId) {
+ return dep.dependencyProject.plugins.hasPlugin(LibraryPlugin::class.java)
+ }
+ }
+ }
+ val projectModules = project.getProjectsMap()
+ projectModules["$groupId:$artifactId"]?.let { module ->
+ return project.findProject(module)?.plugins?.hasPlugin(LibraryPlugin::class.java) ?: false
+ }
+ return false
+}
+
+private fun Project.appliesJavaGradlePluginPlugin() = pluginManager.hasPlugin("java-gradle-plugin")
+
+private const val ANDROID_GIT_URL =
+ "scm:git:https://android.googlesource.com/platform/frameworks/support"
diff --git a/buildSrc/src/main/kotlin/androidx/build/ProjectExt.kt b/buildSrc/private/src/main/kotlin/androidx/build/ProjectExt.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/ProjectExt.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/ProjectExt.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/Release.kt b/buildSrc/private/src/main/kotlin/androidx/build/Release.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/Release.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/Release.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/ReportLibraryMetricsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ReportLibraryMetricsTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/ReportLibraryMetricsTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/ReportLibraryMetricsTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/SaveSystemStatsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/SaveSystemStatsTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/SaveSystemStatsTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/SaveSystemStatsTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/SingleFileCopy.kt b/buildSrc/private/src/main/kotlin/androidx/build/SingleFileCopy.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/SingleFileCopy.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/SingleFileCopy.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt b/buildSrc/private/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/ValidateProjectStructureTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ValidateProjectStructureTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/ValidateProjectStructureTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/ValidateProjectStructureTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/ValidatePropertiesTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ValidatePropertiesTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/ValidatePropertiesTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/ValidatePropertiesTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiLocation.kt b/buildSrc/private/src/main/kotlin/androidx/build/checkapi/ApiLocation.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/checkapi/ApiLocation.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/checkapi/ApiLocation.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt b/buildSrc/private/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApi.kt b/buildSrc/private/src/main/kotlin/androidx/build/checkapi/CheckApi.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApi.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/checkapi/CheckApi.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dackka/DackkaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dackka/OWNERS b/buildSrc/private/src/main/kotlin/androidx/build/dackka/OWNERS
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dackka/OWNERS
rename to buildSrc/private/src/main/kotlin/androidx/build/dackka/OWNERS
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/BuildPropParser.kt b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/BuildPropParser.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dependencyTracker/BuildPropParser.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/BuildPropParser.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/DependencyTracker.kt b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/DependencyTracker.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dependencyTracker/DependencyTracker.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/DependencyTracker.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/FileLogger.kt b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/FileLogger.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dependencyTracker/FileLogger.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/FileLogger.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/ProjectGraph.kt b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/ProjectGraph.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dependencyTracker/ProjectGraph.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/ProjectGraph.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/ToStringLogger.kt b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/ToStringLogger.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dependencyTracker/ToStringLogger.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/ToStringLogger.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/doclava/ChecksConfig.kt b/buildSrc/private/src/main/kotlin/androidx/build/doclava/ChecksConfig.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/doclava/ChecksConfig.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/doclava/ChecksConfig.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/doclava/Doclava.kt b/buildSrc/private/src/main/kotlin/androidx/build/doclava/Doclava.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/doclava/Doclava.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/doclava/Doclava.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/doclava/OWNERS b/buildSrc/private/src/main/kotlin/androidx/build/doclava/OWNERS
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/doclava/OWNERS
rename to buildSrc/private/src/main/kotlin/androidx/build/doclava/OWNERS
diff --git a/buildSrc/src/main/kotlin/androidx/build/docs/OWNERS b/buildSrc/private/src/main/kotlin/androidx/build/docs/OWNERS
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/docs/OWNERS
rename to buildSrc/private/src/main/kotlin/androidx/build/docs/OWNERS
diff --git a/buildSrc/src/main/kotlin/androidx/build/dokka/Dokka.kt b/buildSrc/private/src/main/kotlin/androidx/build/dokka/Dokka.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dokka/Dokka.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/dokka/Dokka.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dokka/OWNERS b/buildSrc/private/src/main/kotlin/androidx/build/dokka/OWNERS
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dokka/OWNERS
rename to buildSrc/private/src/main/kotlin/androidx/build/dokka/OWNERS
diff --git a/buildSrc/src/main/kotlin/androidx/build/gitclient/GitClient.kt b/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitClient.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/gitclient/GitClient.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitClient.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt b/buildSrc/private/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/logging/logging.kt b/buildSrc/private/src/main/kotlin/androidx/build/logging/logging.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/logging/logging.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/logging/logging.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/CheckApiCompatibilityTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/CheckApiCompatibilityTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/CheckApiCompatibilityTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/CheckApiCompatibilityTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/CheckApiEquivalenceTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/CheckApiEquivalenceTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/CheckApiEquivalenceTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/CheckApiEquivalenceTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/GenerateApiStubClassesTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiStubClassesTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/GenerateApiStubClassesTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiStubClassesTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/UpdateApiTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateApiTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/metalava/UpdateApiTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateApiTask.kt
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt
new file mode 100644
index 0000000..74b98ec
--- /dev/null
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build.metalava
+
+import androidx.build.checkapi.ApiBaselinesLocation
+import androidx.build.checkapi.ApiLocation
+import org.gradle.api.file.FileCollection
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.OutputFiles
+import org.gradle.api.tasks.TaskAction
+import org.gradle.workers.WorkerExecutor
+import java.io.File
+import javax.inject.Inject
+
+abstract class UpdateApiLintBaselineTask @Inject constructor(
+ workerExecutor: WorkerExecutor
+) : MetalavaTask(workerExecutor) {
+ init {
+ group = "API"
+ description = "Updates an API lint baseline file (api/api_lint.ignore) to match the " +
+ "current set of violations. Only use a baseline " +
+ "if you are in a library without Android dependencies, or when enabling a new " +
+ "lint check, and it is prohibitively expensive / not possible to fix the errors " +
+ "generated by enabling this lint check. "
+ }
+
+ @get:Input
+ abstract val baselines: Property<ApiBaselinesLocation>
+
+ @get:Input
+ abstract val targetsJavaConsumers: Property<Boolean>
+
+ @OutputFile
+ fun getApiLintBaseline(): File = baselines.get().apiLintFile
+
+ @TaskAction
+ fun updateBaseline() {
+ check(bootClasspath.files.isNotEmpty()) { "Android boot classpath not set." }
+ val baselineFile = baselines.get().apiLintFile
+ val checkArgs = getGenerateApiArgs(
+ bootClasspath, dependencyClasspath,
+ sourcePaths.files.filter { it.exists() }, null, GenerateApiMode.PublicApi,
+ ApiLintMode.CheckBaseline(baselineFile, targetsJavaConsumers.get()),
+ manifestPath.orNull?.asFile?.absolutePath
+ )
+ val args = checkArgs + getCommonBaselineUpdateArgs(baselineFile)
+
+ runWithArgs(args)
+ }
+}
+
+abstract class IgnoreApiChangesTask @Inject constructor(
+ workerExecutor: WorkerExecutor
+) : MetalavaTask(workerExecutor) {
+ init {
+ description = "Updates an API tracking baseline file (api/X.Y.Z.ignore) to match the " +
+ "current set of violations"
+ }
+
+ // The API that the library is supposed to be compatible with
+ @get:Input
+ abstract val referenceApi: Property<ApiLocation>
+
+ @get:Input
+ abstract val api: Property<ApiLocation>
+
+ // The baseline files (api/*.*.*.ignore) to update
+ @get:Input
+ abstract val baselines: Property<ApiBaselinesLocation>
+
+ @InputFiles
+ fun getTaskInputs(): List<File> {
+ val referenceApiLocation = referenceApi.get()
+ return listOf(
+ referenceApiLocation.publicApiFile,
+ referenceApiLocation.restrictedApiFile
+ )
+ }
+
+ // Declaring outputs prevents Gradle from rerunning this task if the inputs haven't changed
+ @OutputFiles
+ fun getTaskOutputs(): List<File>? {
+ val apiBaselinesLocation = baselines.get()
+ return listOf(
+ apiBaselinesLocation.publicApiFile,
+ apiBaselinesLocation.restrictedApiFile
+ )
+ }
+
+ @TaskAction
+ fun exec() {
+ check(bootClasspath.files.isNotEmpty()) { "Android boot classpath not set." }
+
+ updateBaseline(
+ api.get().publicApiFile,
+ referenceApi.get().publicApiFile,
+ baselines.get().publicApiFile,
+ false
+ )
+ if (referenceApi.get().restrictedApiFile.exists()) {
+ updateBaseline(
+ api.get().restrictedApiFile,
+ referenceApi.get().restrictedApiFile,
+ baselines.get().restrictedApiFile,
+ true
+ )
+ }
+ }
+
+ // Updates the contents of baselineFile to specify an exception for every API present in apiFile but not
+ // present in the current source path
+ private fun updateBaseline(
+ api: File,
+ prevApi: File,
+ baselineFile: File,
+ processRestrictedApis: Boolean
+ ) {
+ val args = getCommonBaselineUpdateArgs(
+ bootClasspath,
+ dependencyClasspath,
+ baselineFile
+ )
+ args += listOf(
+ "--baseline",
+ baselineFile.toString(),
+ "--check-compatibility:api:released",
+ prevApi.toString(),
+ "--source-files",
+ api.toString()
+ )
+ if (processRestrictedApis) {
+ args += listOf(
+ "--show-annotation",
+ "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope." +
+ "LIBRARY_GROUP)",
+ "--show-annotation",
+ "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope." +
+ "LIBRARY_GROUP_PREFIX)",
+ "--show-unannotated"
+ )
+ }
+ runWithArgs(args)
+ }
+}
+
+private fun getCommonBaselineUpdateArgs(
+ bootClasspath: FileCollection,
+ dependencyClasspath: FileCollection,
+ baselineFile: File
+): MutableList<String> {
+ val args = mutableListOf(
+ "--classpath",
+ (bootClasspath.files + dependencyClasspath.files).joinToString(File.pathSeparator)
+ )
+ args += getCommonBaselineUpdateArgs(baselineFile)
+ return args
+}
+
+private fun getCommonBaselineUpdateArgs(baselineFile: File): List<String> {
+ // Create the baseline file if it does exist, as Metalava cannot handle non-existent files.
+ baselineFile.createNewFile()
+ return mutableListOf(
+ "--update-baseline",
+ baselineFile.toString(),
+ "--pass-baseline-updates",
+ "--delete-empty-baselines",
+ "--format=v4"
+ )
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/playground/FindAffectedModulesTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/playground/FindAffectedModulesTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/playground/FindAffectedModulesTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/playground/FindAffectedModulesTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/playground/OWNERS b/buildSrc/private/src/main/kotlin/androidx/build/playground/OWNERS
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/playground/OWNERS
rename to buildSrc/private/src/main/kotlin/androidx/build/playground/OWNERS
diff --git a/buildSrc/src/main/kotlin/androidx/build/playground/VerifyPlaygroundGradlePropertiesTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/playground/VerifyPlaygroundGradlePropertiesTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/playground/VerifyPlaygroundGradlePropertiesTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/playground/VerifyPlaygroundGradlePropertiesTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/releasenotes/Markdown.kt b/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/Markdown.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/releasenotes/Markdown.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/releasenotes/Markdown.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/releasenotes/ReleaseNoteMarkdown.kt b/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/ReleaseNoteMarkdown.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/releasenotes/ReleaseNoteMarkdown.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/releasenotes/ReleaseNoteMarkdown.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/resources/CheckResourceApiReleaseTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/resources/CheckResourceApiReleaseTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/resources/CheckResourceApiReleaseTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/resources/CheckResourceApiReleaseTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/resources/CheckResourceApiTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/resources/CheckResourceApiTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/resources/CheckResourceApiTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/resources/CheckResourceApiTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/resources/GenerateResourceApiTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/resources/GenerateResourceApiTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/resources/GenerateResourceApiTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/resources/GenerateResourceApiTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/resources/PublicResourcesStubHelper.kt b/buildSrc/private/src/main/kotlin/androidx/build/resources/PublicResourcesStubHelper.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/resources/PublicResourcesStubHelper.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/resources/PublicResourcesStubHelper.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/resources/ResourceTasks.kt b/buildSrc/private/src/main/kotlin/androidx/build/resources/ResourceTasks.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/resources/ResourceTasks.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/resources/ResourceTasks.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/resources/UpdateResourceApiTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/resources/UpdateResourceApiTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/resources/UpdateResourceApiTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/resources/UpdateResourceApiTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/studio/StudioArchiveCreator.kt b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioArchiveCreator.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/studio/StudioArchiveCreator.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/studio/StudioArchiveCreator.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/studio/StudioPatcher.kt b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioPatcher.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/studio/StudioPatcher.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/studio/StudioPatcher.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/studio/StudioPlatformUtilities.kt b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioPlatformUtilities.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/studio/StudioPlatformUtilities.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/studio/StudioPlatformUtilities.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/studio/StudioTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/studio/StudioTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioVersions.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/studio/StudioVersions.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateMediaTestConfigurationTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateMediaTestConfigurationTask.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateMediaTestConfigurationTask.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateMediaTestConfigurationTask.kt
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
new file mode 100644
index 0000000..cd54a5c
--- /dev/null
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build.testConfiguration
+
+import androidx.build.dependencyTracker.ProjectSubset
+import androidx.build.isPresubmitBuild
+import androidx.build.renameApkForTesting
+import com.android.build.api.variant.BuiltArtifactsLoader
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.Optional
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+
+/**
+ * Writes a configuration file in
+ * <a href=https://source.android.com/devices/tech/test_infra/tradefed/testing/through-suite/android-test-structure>AndroidTest.xml</a>
+ * format that gets zipped alongside the APKs to be tested.
+ * This config gets ingested by Tradefed.
+ */
+abstract class GenerateTestConfigurationTask : DefaultTask() {
+
+ @get:InputFiles
+ @get:Optional
+ abstract val appFolder: DirectoryProperty
+
+ @get:Internal
+ abstract val appLoader: Property<BuiltArtifactsLoader>
+
+ @get:Input
+ @get:Optional
+ abstract val appProjectPath: Property<String>
+
+ @get:InputFiles
+ abstract val testFolder: DirectoryProperty
+
+ @get:Internal
+ abstract val testLoader: Property<BuiltArtifactsLoader>
+
+ @get:Input
+ abstract val testProjectPath: Property<String>
+
+ @get:Input
+ abstract val minSdk: Property<Int>
+
+ @get:Input
+ abstract val hasBenchmarkPlugin: Property<Boolean>
+
+ @get:Input
+ @get:Optional
+ abstract val benchmarkRunAlsoInterpreted: Property<Boolean>
+
+ @get:Input
+ abstract val testRunner: Property<String>
+
+ @get:Input
+ abstract val affectedModuleDetectorSubset: Property<ProjectSubset>
+
+ @get:OutputFile
+ abstract val outputXml: RegularFileProperty
+
+ @get:OutputFile
+ abstract val constrainedOutputXml: RegularFileProperty
+
+ @TaskAction
+ fun generateAndroidTestZip() {
+ writeConfigFileContent(constrainedOutputXml, true)
+ writeConfigFileContent(outputXml)
+ }
+
+ private fun writeConfigFileContent(
+ outputFile: RegularFileProperty,
+ isConstrained: Boolean = false
+ ) {
+ /*
+ Testing an Android Application project involves 2 APKS: an application to be instrumented,
+ and a test APK. Testing an Android Library project involves only 1 APK, since the library
+ is bundled inside the test APK, meaning it is self instrumenting. We add extra data to
+ configurations testing Android Application projects, so that both APKs get installed.
+ */
+ val configBuilder = ConfigBuilder()
+ if (appLoader.isPresent) {
+ val appApk = appLoader.get().load(appFolder.get())
+ ?: throw RuntimeException("Cannot load required APK for task: $name")
+ // We don't need to check hasBenchmarkPlugin because benchmarks shouldn't have test apps
+ val appName = appApk.elements.single().outputFile.substringAfterLast("/")
+ .renameApkForTesting(appProjectPath.get(), hasBenchmarkPlugin = false)
+ // TODO(b/178776319): Clean up this hardcoded hack
+ if (appProjectPath.get().contains("macrobenchmark-target")) {
+ configBuilder.appApkName(appName.replace("debug-androidTest", "release"))
+ } else {
+ configBuilder.appApkName(appName)
+ }
+ }
+ val isPresubmit = isPresubmitBuild()
+ configBuilder.isPostsubmit(!isPresubmit)
+ when (affectedModuleDetectorSubset.get()) {
+ ProjectSubset.DEPENDENT_PROJECTS -> {
+ // Don't ever run full tests of RV if it is dependent, since they take > 45 minutes
+ if (isConstrained || testProjectPath.get().contains("recyclerview")) {
+ configBuilder.runAllTests(false)
+ } else {
+ configBuilder.runAllTests(true)
+ }
+ }
+ ProjectSubset.NONE -> {
+ if (isPresubmit) {
+ configBuilder.runAllTests(false)
+ } else {
+ configBuilder.runAllTests(true)
+ }
+ }
+ // in all other cases, if we are building this config we want to run all the tests
+ else -> {
+ configBuilder.runAllTests(true)
+ }
+ }
+ // This section adds metadata tags that will help filter runners to specific modules.
+ if (hasBenchmarkPlugin.get()) {
+ configBuilder.isBenchmark(true)
+ if (configBuilder.isPostsubmit) {
+ if (benchmarkRunAlsoInterpreted.get()) {
+ configBuilder.tag("microbenchmarks_interpreted")
+ }
+ configBuilder.tag("microbenchmarks")
+ } else {
+ // in presubmit, we treat micro benchmarks as regular correctness tests as
+ // they run with dryRunMode to check crashes don't happen, without measurement
+ configBuilder.tag("androidx_unit_tests")
+ }
+ } else if (testProjectPath.get().endsWith("macrobenchmark")) {
+ // macro benchmarks do not have a dryRunMode, so we don't run them in presubmit
+ configBuilder.tag("macrobenchmarks")
+ } else {
+ configBuilder.tag("androidx_unit_tests")
+ if (testProjectPath.get().startsWith(":compose:")) {
+ configBuilder.tag("compose")
+ } else if (testProjectPath.get().startsWith(":wear:")) {
+ configBuilder.tag("wear")
+ }
+ }
+ val testApk = testLoader.get().load(testFolder.get())
+ ?: throw RuntimeException("Cannot load required APK for task: $name")
+ val testName = testApk.elements.single().outputFile
+ .substringAfterLast("/")
+ .renameApkForTesting(testProjectPath.get(), hasBenchmarkPlugin.get())
+ configBuilder.testApkName(testName)
+ .applicationId(testApk.applicationId)
+ .minSdk(minSdk.get().toString())
+ .testRunner(testRunner.get())
+
+ val resolvedOutputFile: File = outputFile.asFile.get()
+ if (!resolvedOutputFile.exists()) {
+ if (!resolvedOutputFile.createNewFile()) {
+ throw RuntimeException(
+ "Failed to create test configuration file: $resolvedOutputFile"
+ )
+ }
+ }
+ resolvedOutputFile.writeText(configBuilder.build())
+ }
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/OwnersService.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/OwnersService.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/testConfiguration/OwnersService.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/OwnersService.kt
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
new file mode 100644
index 0000000..3b21fc6
--- /dev/null
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("UnstableApiUsage") // Incubating AGP APIs
+
+package androidx.build.testConfiguration
+
+import androidx.build.AndroidXExtension
+import androidx.build.AndroidXPlugin
+import androidx.build.AndroidXPlugin.Companion.ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK
+import androidx.build.AndroidXPlugin.Companion.ZIP_TEST_CONFIGS_WITH_APKS_TASK
+import androidx.build.asFilenamePrefix
+import androidx.build.dependencyTracker.AffectedModuleDetector
+import androidx.build.getConstrainedTestConfigDirectory
+import androidx.build.getSupportRootFolder
+import androidx.build.getTestConfigDirectory
+import androidx.build.hasAndroidTestSourceCode
+import androidx.build.hasBenchmarkPlugin
+import androidx.build.renameApkForTesting
+import com.android.build.api.artifact.Artifacts
+import com.android.build.api.artifact.SingleArtifact
+import com.android.build.api.variant.AndroidComponentsExtension
+import com.android.build.api.variant.ApplicationAndroidComponentsExtension
+import com.android.build.api.variant.HasAndroidTest
+import com.android.build.gradle.BaseExtension
+import com.android.build.gradle.tasks.PackageAndroidArtifact
+import org.gradle.api.Project
+import org.gradle.api.file.DuplicatesStrategy
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.api.tasks.bundling.Zip
+import org.gradle.kotlin.dsl.getByType
+import java.io.File
+
+/**
+ * Creates and configures the test config generation task for a project. Configuration includes
+ * populating the task with relevant data from the first 4 params, and setting whether the task
+ * is enabled.
+ *
+ * @param overrideProject Allows the config task for one project to get registered to an
+ * alternative project. Default is for the project to register the new config task to itself
+ */
+fun Project.createTestConfigurationGenerationTask(
+ variantName: String,
+ artifacts: Artifacts,
+ minSdk: Int,
+ testRunner: String,
+ overrideProject: Project = this
+) {
+ val xmlName = "${path.asFilenamePrefix()}$variantName.xml"
+ rootProject.tasks.named("createModuleInfo").configure {
+ it as ModuleInfoGenerator
+ it.testModules.add(
+ TestModule(
+ name = xmlName,
+ path = listOf(projectDir.toRelativeString(getSupportRootFolder()))
+ )
+ )
+ }
+ val generateTestConfigurationTask = overrideProject.tasks.register(
+ "${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}$variantName",
+ GenerateTestConfigurationTask::class.java
+ ) { task ->
+ task.testFolder.set(artifacts.get(SingleArtifact.APK))
+ task.testLoader.set(artifacts.getBuiltArtifactsLoader())
+ task.outputXml.fileValue(File(getTestConfigDirectory(), xmlName))
+ task.constrainedOutputXml.fileValue(File(getConstrainedTestConfigDirectory(), xmlName))
+ // Disable work tests on < API 18: b/178127496
+ if (path.startsWith(":work:")) {
+ task.minSdk.set(maxOf(18, minSdk))
+ } else {
+ task.minSdk.set(minSdk)
+ }
+ val hasBenchmarkPlugin = hasBenchmarkPlugin()
+ task.hasBenchmarkPlugin.set(hasBenchmarkPlugin)
+ if (hasBenchmarkPlugin) {
+ task.benchmarkRunAlsoInterpreted.set(
+ extensions.getByType<AndroidXExtension>().benchmarkRunAlsoInterpreted
+ )
+ }
+ task.testRunner.set(testRunner)
+ task.testProjectPath.set(path)
+ val detector = AffectedModuleDetector.getInstance(project)
+ task.affectedModuleDetectorSubset.set(
+ project.provider {
+ detector.getSubset(task)
+ }
+ )
+ AffectedModuleDetector.configureTaskGuard(task)
+ }
+ // Disable xml generation for projects that have no test sources
+ this.afterEvaluate {
+ generateTestConfigurationTask.configure {
+ it.enabled = this.hasAndroidTestSourceCode()
+ }
+ }
+ this.rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
+ .dependsOn(generateTestConfigurationTask)
+ this.rootProject.tasks.findByName(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK)!!
+ .dependsOn(generateTestConfigurationTask)
+}
+
+/**
+ * Further configures the test config generation task for a project. This only gets called when
+ * there is a test app in addition to the instrumentation app, and the only thing it configures is
+ * the location of the testapp.
+ *
+ * @param overrideProject Allows the config task for one project to get registered to an
+ * alternative project. Default is for the project to register the new config task to itself
+ */
+fun Project.addAppApkToTestConfigGeneration(overrideProject: Project = this) {
+ if (project.isMacrobenchmarkTarget()) {
+ return
+ }
+
+ extensions.getByType<ApplicationAndroidComponentsExtension>().apply {
+ onVariants(selector().withBuildType("debug")) { appVariant ->
+ overrideProject.tasks.named(
+ "${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}${appVariant.name}AndroidTest"
+ ) { configTask ->
+ configTask as GenerateTestConfigurationTask
+ configTask.appFolder.set(appVariant.artifacts.get(SingleArtifact.APK))
+ configTask.appLoader.set(appVariant.artifacts.getBuiltArtifactsLoader())
+ configTask.appProjectPath.set(overrideProject.path)
+ }
+ }
+ }
+}
+
+/**
+ * Configures the test zip task to include the project's apk
+ */
+fun addToTestZips(project: Project, packageTask: PackageAndroidArtifact) {
+ project.rootProject.tasks.named(ZIP_TEST_CONFIGS_WITH_APKS_TASK) { task ->
+ task as Zip
+ val projectPath = project.path
+ val hasBenchmarkPlugin = project.providers.provider { project.hasBenchmarkPlugin() }
+ task.from(packageTask.outputDirectory) {
+ it.include("*.apk")
+ it.duplicatesStrategy = DuplicatesStrategy.FAIL
+ it.rename { fileName ->
+ fileName.renameApkForTesting(projectPath, hasBenchmarkPlugin.get())
+ }
+ }
+ task.dependsOn(packageTask)
+ }
+ project.rootProject.tasks.named(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK) { task ->
+ task as Zip
+ val projectPath = project.path
+ val hasBenchmarkPlugin = project.providers.provider { project.hasBenchmarkPlugin() }
+ task.from(packageTask.outputDirectory) {
+ it.include("*.apk")
+ it.duplicatesStrategy = DuplicatesStrategy.FAIL
+ it.rename { fileName ->
+ fileName.renameApkForTesting(projectPath, hasBenchmarkPlugin.get())
+ }
+ }
+ task.dependsOn(packageTask)
+ }
+}
+
+private fun getOrCreateMediaTestConfigTask(project: Project, isMedia2: Boolean):
+ TaskProvider<GenerateMediaTestConfigurationTask> {
+ val mediaPrefix = getMediaConfigTaskPrefix(isMedia2)
+ val parentProject = project.parent!!
+ if (!parentProject.tasks.withType(GenerateMediaTestConfigurationTask::class.java)
+ .names.contains(
+ "support-$mediaPrefix-test${
+ AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK
+ }"
+ )
+ ) {
+ val task = parentProject.tasks.register(
+ "support-$mediaPrefix-test${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}",
+ GenerateMediaTestConfigurationTask::class.java
+ ) { task ->
+ AffectedModuleDetector.configureTaskGuard(task)
+ val detector = AffectedModuleDetector.getInstance(project)
+ task.affectedModuleDetectorSubset.set(
+ project.provider {
+ detector.getSubset(task)
+ }
+ )
+ }
+ project.rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
+ .dependsOn(task)
+ project.rootProject.tasks.findByName(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK)!!
+
+ .dependsOn(task)
+ return task
+ } else {
+ return parentProject.tasks.withType(GenerateMediaTestConfigurationTask::class.java)
+ .named(
+ "support-$mediaPrefix-test${
+ AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK
+ }"
+ )
+ }
+ }
+
+private fun getMediaConfigTaskPrefix(isMedia2: Boolean): String {
+ return if (isMedia2) "media2" else "media"
+}
+
+fun Project.createOrUpdateMediaTestConfigurationGenerationTask(
+ variantName: String,
+ artifacts: Artifacts,
+ minSdk: Int,
+ testRunner: String,
+ isMedia2: Boolean
+) {
+ val mediaPrefix = getMediaConfigTaskPrefix(isMedia2)
+ val mediaTask = getOrCreateMediaTestConfigTask(this, isMedia2)
+ mediaTask.configure {
+ it as GenerateMediaTestConfigurationTask
+ if (this.name.contains("client")) {
+ if (this.name.contains("previous")) {
+ it.clientPreviousFolder.set(artifacts.get(SingleArtifact.APK))
+ it.clientPreviousLoader.set(artifacts.getBuiltArtifactsLoader())
+ it.clientPreviousPath.set(this.path)
+ } else {
+ it.clientToTFolder.set(artifacts.get(SingleArtifact.APK))
+ it.clientToTLoader.set(artifacts.getBuiltArtifactsLoader())
+ it.clientToTPath.set(this.path)
+ }
+ } else {
+ if (this.name.contains("previous")) {
+ it.servicePreviousFolder.set(artifacts.get(SingleArtifact.APK))
+ it.servicePreviousLoader.set(artifacts.getBuiltArtifactsLoader())
+ it.servicePreviousPath.set(this.path)
+ } else {
+ it.serviceToTFolder.set(artifacts.get(SingleArtifact.APK))
+ it.serviceToTLoader.set(artifacts.getBuiltArtifactsLoader())
+ it.serviceToTPath.set(this.path)
+ }
+ }
+ it.clientPreviousServiceToT.fileValue(
+ File(
+ this.getTestConfigDirectory(),
+ "${mediaPrefix}ClientPreviousServiceToT$variantName.xml"
+ )
+ )
+ it.clientToTServicePrevious.fileValue(
+ File(
+ this.getTestConfigDirectory(),
+ "${mediaPrefix}ClientToTServicePrevious$variantName.xml"
+ )
+ )
+ it.clientToTServiceToT.fileValue(
+ File(
+ this.getTestConfigDirectory(),
+ "${mediaPrefix}ClientToTServiceToT$variantName.xml"
+ )
+ )
+ it.constrainedClientPreviousServiceToT.fileValue(
+ File(
+ this.getConstrainedTestConfigDirectory(),
+ "${mediaPrefix}ClientPreviousServiceToT$variantName.xml"
+ )
+ )
+ it.constrainedClientToTServicePrevious.fileValue(
+ File(
+ this.getConstrainedTestConfigDirectory(),
+ "${mediaPrefix}ClientToTServicePrevious$variantName.xml"
+ )
+ )
+ it.constrainedClientToTServiceToT.fileValue(
+ File(
+ this.getConstrainedTestConfigDirectory(),
+ "${mediaPrefix}ClientToTServiceToT$variantName.xml"
+ )
+ )
+ it.minSdk.set(minSdk)
+ it.testRunner.set(testRunner)
+ AffectedModuleDetector.configureTaskGuard(it)
+ }
+}
+
+private fun Project.getOrCreateMacrobenchmarkConfigTask(variantName: String):
+ TaskProvider<GenerateTestConfigurationTask> {
+ val parentProject = this.parent!!
+ return if (
+ parentProject.tasks.withType(GenerateTestConfigurationTask::class.java).isEmpty()
+ ) {
+ parentProject.tasks.register(
+ "${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}$variantName",
+ GenerateTestConfigurationTask::class.java
+ )
+ } else {
+ parentProject.tasks.withType(GenerateTestConfigurationTask::class.java)
+ .named("${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}$variantName")
+ }
+ }
+
+private fun Project.configureMacrobenchmarkConfigTask(
+ variantName: String,
+ artifacts: Artifacts,
+ minSdk: Int,
+ testRunner: String
+) {
+ val configTask = getOrCreateMacrobenchmarkConfigTask(variantName)
+ if (path.endsWith("macrobenchmark")) {
+ configTask.configure { task ->
+ task.testFolder.set(artifacts.get(SingleArtifact.APK))
+ task.testLoader.set(artifacts.getBuiltArtifactsLoader())
+ task.outputXml.fileValue(
+ File(
+ this.getTestConfigDirectory(),
+ "${this.path.asFilenamePrefix()}$variantName.xml"
+ )
+ )
+ task.constrainedOutputXml.fileValue(
+ File(
+ this.getTestConfigDirectory(),
+ "${this.path.asFilenamePrefix()}$variantName.xml"
+ )
+ )
+ task.minSdk.set(minSdk)
+ task.hasBenchmarkPlugin.set(this.hasBenchmarkPlugin())
+ task.testRunner.set(testRunner)
+ task.testProjectPath.set(this.path)
+ val detector = AffectedModuleDetector.getInstance(project)
+ task.affectedModuleDetectorSubset.set(
+ project.provider {
+ detector.getSubset(task)
+ }
+ )
+
+ AffectedModuleDetector.configureTaskGuard(task)
+ }
+ // Disable xml generation for projects that have no test sources
+ this.afterEvaluate {
+ configTask.configure {
+ it.enabled = this.hasAndroidTestSourceCode()
+ }
+ }
+ this.rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
+ .dependsOn(configTask)
+ this.rootProject.tasks.findByName(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK)!!
+ .dependsOn(configTask)
+ } else if (isMacrobenchmarkTarget()) {
+ configTask.configure { task ->
+ task.appFolder.set(artifacts.get(SingleArtifact.APK))
+ task.appLoader.set(artifacts.getBuiltArtifactsLoader())
+ task.appProjectPath.set(path)
+ }
+ }
+}
+
+/**
+ * Tells whether this project is the macrobenchmark-target project
+ */
+fun Project.isMacrobenchmarkTarget(): Boolean {
+ return path.endsWith("macrobenchmark-target")
+}
+
+fun Project.configureTestConfigGeneration(baseExtension: BaseExtension) {
+ extensions.getByType(AndroidComponentsExtension::class.java).apply {
+ onVariants { variant ->
+ val androidTest = when (variant) {
+ is HasAndroidTest -> variant.androidTest
+ else -> return@onVariants
+ } ?: return@onVariants
+ when {
+ path.contains("media2:media2-session:version-compat-tests:") -> {
+ createOrUpdateMediaTestConfigurationGenerationTask(
+ androidTest.name,
+ androidTest.artifacts,
+ baseExtension.defaultConfig.minSdk!!,
+ baseExtension.defaultConfig.testInstrumentationRunner!!,
+ isMedia2 = true
+ )
+ }
+ path.contains("media:version-compat-tests:") -> {
+ createOrUpdateMediaTestConfigurationGenerationTask(
+ androidTest.name,
+ androidTest.artifacts,
+ baseExtension.defaultConfig.minSdk!!,
+ baseExtension.defaultConfig.testInstrumentationRunner!!,
+ isMedia2 = false
+ )
+ }
+ path.endsWith("macrobenchmark") ||
+ isMacrobenchmarkTarget() -> {
+ configureMacrobenchmarkConfigTask(
+ androidTest.name,
+ androidTest.artifacts,
+ baseExtension.defaultConfig.minSdk!!,
+ baseExtension.defaultConfig.testInstrumentationRunner!!
+ )
+ }
+ else -> {
+ createTestConfigurationGenerationTask(
+ androidTest.name,
+ androidTest.artifacts,
+ baseExtension.defaultConfig.minSdk!!,
+ baseExtension.defaultConfig.testInstrumentationRunner!!
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/uptodatedness/EnableCaching.kt b/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/EnableCaching.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/uptodatedness/EnableCaching.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/EnableCaching.kt
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt b/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
new file mode 100644
index 0000000..7ead4b5
--- /dev/null
+++ b/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build.uptodatedness
+
+import androidx.build.VERIFY_UP_TO_DATE
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.provider.Provider
+import org.gradle.api.services.BuildService
+import org.gradle.api.services.BuildServiceParameters
+import org.gradle.build.event.BuildEventsListenerRegistry
+import org.gradle.tooling.events.FinishEvent
+import org.gradle.tooling.events.OperationCompletionListener
+import org.gradle.tooling.events.task.TaskExecutionResult
+
+/**
+ * Validates that all tasks (except a temporary exception list) are considered up-to-date.
+ * The expected usage of this is that the user will invoke a build with the
+ * TaskUpToDateValidator disabled, and then reinvoke the same build with the TaskUpToDateValidator
+ * enabled. If the second build actually runs any tasks, then some tasks don't have the correct
+ * inputs/outputs declared and are running more often than necessary.
+ */
+
+const val DISALLOW_TASK_EXECUTION_FLAG_NAME = "disallowExecution"
+
+private const val ENABLE_FLAG_NAME = VERIFY_UP_TO_DATE
+
+// Temporary set of exempt tasks that are known to still be out-of-date after running once
+// Entries in this set may be task names (like assembleRelease) or task paths
+// (like :core:core:assembleRelease)
+// Entries in this set do still get rerun because they might produce files that are needed by
+// subsequent tasks
+val ALLOW_RERUNNING_TASKS = setOf(
+ "buildOnServer",
+ "checkExternalLicenses",
+ "createArchive",
+ "createDiffArchiveForAll",
+ "createProjectZip",
+ "externalNativeBuildDebug",
+ "externalNativeBuildRelease",
+ "generateDebugUnitTestConfig",
+ "generateJsonModelDebug",
+ "generateJsonModelRelease",
+ "generateMetadataFileForAndroidDebugPublication",
+ "generateMetadataFileForAndroidReleasePublication",
+ "generateMetadataFileForDesktopPublication",
+ "generateMetadataFileForJvmPublication",
+ "generateMetadataFileForJvmlinux-x64Publication",
+ "generateMetadataFileForJvmlinux-arm64Publication",
+ "generateMetadataFileForJvmmacos-x64Publication",
+ "generateMetadataFileForJvmmacos-arm64Publication",
+ "generateMetadataFileForJvmwindows-x64Publication",
+ "generateMetadataFileForJvmallPublication",
+ "generateMetadataFileForMavenPublication",
+ "generateMetadataFileForMetadataPublication",
+ "generateMetadataFileForKotlinMultiplatformPublication",
+ "generateMetadataFileForPluginMavenPublication",
+ "generatePomFileForBenchmarkPluginMarkerMavenPublication",
+ "generatePomFileForAndroidDebugPublication",
+ "generatePomFileForAndroidReleasePublication",
+ "generatePomFileForDesktopPublication",
+ "generatePomFileForJvmlinux-x64Publication",
+ "generatePomFileForJvmlinux-arm64Publication",
+ "generatePomFileForJvmmacos-x64Publication",
+ "generatePomFileForJvmmacos-arm64Publication",
+ "generatePomFileForJvmwindows-x64Publication",
+ "generatePomFileForJvmallPublication",
+ "generatePomFileForJvmPublication",
+ "generatePomFileForKotlinMultiplatformPublication",
+ "generatePomFileForMavenPublication",
+ "generatePomFileForPluginMavenPublication",
+ "generatePomFileForMetadataPublication",
+ "generatePomFileForSafeargsJavaPluginMarkerMavenPublication",
+ "generatePomFileForSafeargsKotlinPluginMarkerMavenPublication",
+ "partiallyDejetifyArchive",
+ "publishBenchmarkPluginMarkerMavenPublicationToMavenRepository",
+ "publishAndroidDebugPublicationToMavenRepository",
+ "publishAndroidReleasePublicationToMavenRepository",
+ "publishDesktopPublicationToMavenRepository",
+ "publishJvmPublicationToMavenRepository",
+ "publishJvmlinux-x64PublicationToMavenRepository",
+ "publishJvmlinux-arm64PublicationToMavenRepository",
+ "publishJvmmacos-x64PublicationToMavenRepository",
+ "publishJvmmacos-arm64PublicationToMavenRepository",
+ "publishJvmwindows-x64PublicationToMavenRepository",
+ "publishJvmallPublicationToMavenRepository",
+ "publishKotlinMultiplatformPublicationToMavenRepository",
+ "publishMavenPublicationToMavenRepository",
+ "publishMetadataPublicationToMavenRepository",
+ "publishPluginMavenPublicationToMavenRepository",
+ "publishSafeargsJavaPluginMarkerMavenPublicationToMavenRepository",
+ "publishSafeargsKotlinPluginMarkerMavenPublicationToMavenRepository",
+ /**
+ * relocateShadowJar is used to configure the ShadowJar hence it does not have any outputs.
+ * https://github.com/johnrengelman/shadow/issues/561
+ */
+ "relocateShadowJar",
+ "testDebugUnitTest",
+ "stripArchiveForPartialDejetification",
+ "verifyDependencyVersions",
+ "zipConstrainedTestConfigsWithApks",
+ "zipTestConfigsWithApks",
+ "zipHtmlResultsOfTestDebugUnitTest",
+ "zipXmlResultsOfTestDebugUnitTest",
+
+ ":camera:integration-tests:camera-testapp-core:mergeLibDexDebug",
+ ":camera:integration-tests:camera-testapp-core:packageDebug",
+ ":camera:integration-tests:camera-testapp-extensions:mergeLibDexDebug",
+ ":camera:integration-tests:camera-testapp-extensions:packageDebug",
+ ":camera:integration-tests:camera-testapp-extensions:GenerateTestConfigurationdebugAndroidTest",
+ ":camera:integration-tests:camera-testapp-uiwidgets:mergeLibDexDebug",
+ ":camera:integration-tests:camera-testapp-uiwidgets:packageDebug",
+ ":camera:integration-tests:camera-testapp-core:GenerateTestConfigurationdebug",
+ ":camera:integration-tests:camera-testapp-core:GenerateTestConfigurationdebugAndroidTest",
+ ":camera:integration-tests:camera-testapp-view:GenerateTestConfigurationdebug",
+ ":camera:integration-tests:camera-testapp-view:GenerateTestConfigurationdebugAndroidTest",
+ ":camera:integration-tests:camera-testapp-view:mergeLibDexDebug",
+ ":camera:integration-tests:camera-testapp-view:packageDebug",
+ "configureCMakeDebug",
+ "buildCMakeDebug",
+ "configureCMakeRelWithDebInfo",
+ "buildCMakeRelWithDebInfo",
+ ":appsearch:appsearch-local-storage:buildCMakeDebug[icing]",
+ ":appsearch:appsearch-local-storage:buildCMakeRelWithDebInfo[icing]",
+ ":external:libyuv:buildCMakeDebug[yuv]",
+ ":external:libyuv:buildCMakeRelWithDebInfo[yuv]",
+ ":hilt:hilt-navigation-compose:kaptGenerateStubsDebugKotlin",
+ ":hilt:hilt-navigation-compose:kaptGenerateStubsReleaseKotlin",
+ ":lint-checks:integration-tests:copyDebugAndroidLintReports",
+
+ // https://github.com/gradle/gradle/issues/17262
+ ":doclava:compileJava",
+ ":doclava:processResources",
+ ":doclava:jar"
+)
+
+// Additional tasks that are expected to be temporarily out-of-date after running once
+// Tasks in this set we don't even try to rerun, because they're known to be unnecessary
+val DONT_TRY_RERUNNING_TASKS = setOf(
+ ":buildSrc-tests:project-subsets:test",
+ "listTaskOutputs",
+ "validateProperties",
+ "tasks",
+
+ ":benchmark:benchmark-common:generateReleaseProtos",
+ ":benchmark:benchmark-common:generateDebugProtos",
+ ":benchmark:benchmark-common:compileReleaseKotlin",
+ ":benchmark:benchmark-common:compileDebugKotlin",
+ ":benchmark:benchmark-common:compileReleaseJavaWithJavac",
+ ":benchmark:benchmark-common:compileDebugJavaWithJavac",
+ ":benchmark:benchmark-common:extractReleaseAnnotations",
+ ":benchmark:benchmark-common:extractDebugAnnotations",
+ ":benchmark:benchmark-common:generateApi",
+ ":benchmark:benchmark-common:runErrorProne",
+ ":benchmark:benchmark-common:lintAnalyzeDebug",
+ ":benchmark:benchmark-common:lintDebug",
+
+ // More information about the fact that these dokka tasks rerun can be found at b/167569304
+ "dokkaKotlinDocs",
+ "zipDokkaDocs",
+ "dackkaDocs",
+
+ // Flakily not up-to-date, b/176120659
+ "doclavaDocs",
+
+ // We should be able to remove these entries when b/160392650 is fixed
+ "lint",
+ "lintAnalyzeDebug",
+ "lintDebug",
+ "lintVitalRelease",
+ "lintWithExpandProjectionDebug",
+ "lintWithoutExpandProjectionDebug",
+)
+
+abstract class TaskUpToDateValidator :
+ BuildService<TaskUpToDateValidator.Parameters>, OperationCompletionListener {
+ interface Parameters : BuildServiceParameters {
+ // We check <validate> during task execution rather than during project configuration
+ // so that any configuration cache created during the first build can be reused during the
+ // second build, saving build time
+ var validate: Provider<Boolean>
+ }
+
+ override fun onFinish(event: FinishEvent) {
+ if (!getParameters().validate.get()) {
+ return
+ }
+ val result = event.result
+ if (result is TaskExecutionResult) {
+ val name = event.descriptor.name
+ val executionReasons = result.executionReasons
+ if (executionReasons.isNullOrEmpty()) {
+ // empty list means task was actually up-to-date, see docs for
+ // TaskExecutionResult.executionReasons
+ // null list means the task already failed, so we'll skip emitting our error
+ return
+ }
+ if (!isAllowedToRerunTask(name)) {
+ throw GradleException(
+ "Ran two consecutive builds of the same tasks, and in the " +
+ "second build, observed:\n" +
+ "task $name not UP-TO-DATE. It was out-of-date because:\n" +
+ "${result.executionReasons}"
+ )
+ }
+ }
+ }
+
+ companion object {
+ // Tells whether to create a TaskUpToDateValidator listener
+ private fun shouldEnable(project: Project): Boolean {
+ return project.providers.gradleProperty(ENABLE_FLAG_NAME)
+ .forUseAtConfigurationTime().isPresent()
+ }
+
+ private fun isAllowedToRerunTask(taskPath: String): Boolean {
+ if (ALLOW_RERUNNING_TASKS.contains(taskPath)) {
+ return true
+ }
+ val colonIndex = taskPath.lastIndexOf(":")
+ if (colonIndex >= 0) {
+ val taskName = taskPath.substring(colonIndex + 1)
+ if (ALLOW_RERUNNING_TASKS.contains(taskName)) {
+ return true
+ }
+ }
+ return false
+ }
+
+ private fun shouldTryRerunningTask(task: Task): Boolean {
+ return !(
+ DONT_TRY_RERUNNING_TASKS.contains(task.name) ||
+ DONT_TRY_RERUNNING_TASKS.contains(task.path)
+ )
+ }
+
+ fun setup(rootProject: Project, registry: BuildEventsListenerRegistry) {
+ if (!shouldEnable(rootProject)) {
+ return
+ }
+ val validate = rootProject.providers.gradleProperty(DISALLOW_TASK_EXECUTION_FLAG_NAME)
+ .map({ _ -> true }).orElse(false)
+ // create listener for validating that any task that reran was expected to rerun
+ val validatorProvider = rootProject.getGradle().getSharedServices()
+ .registerIfAbsent(
+ "TaskUpToDateValidator",
+ TaskUpToDateValidator::class.java,
+ { spec -> spec.getParameters().validate = validate }
+ )
+ registry.onTaskCompletion(validatorProvider)
+
+ // skip rerunning tasks that are known to be unnecessary to rerun
+ rootProject.allprojects { subproject ->
+ subproject.tasks.configureEach { task ->
+ task.onlyIf {
+ shouldTryRerunningTask(task) || !validate.get()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/buildSrc/public/README.md b/buildSrc/public/README.md
new file mode 100644
index 0000000..17062a3
--- /dev/null
+++ b/buildSrc/public/README.md
@@ -0,0 +1,3 @@
+This is the :buildSrc:public project
+
+It contains code that other projects in this repository expect to be able to import and reference from their build.gradle files
diff --git a/buildSrc/src/main/kotlin/androidx/build/BuildOnServer.kt b/buildSrc/public/src/main/kotlin/androidx/build/BuildOnServer.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/BuildOnServer.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/BuildOnServer.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/BuildServerConfiguration.kt b/buildSrc/public/src/main/kotlin/androidx/build/BuildServerConfiguration.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/BuildServerConfiguration.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/BuildServerConfiguration.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/BundleInsideHelper.kt b/buildSrc/public/src/main/kotlin/androidx/build/BundleInsideHelper.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/BundleInsideHelper.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/BundleInsideHelper.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt b/buildSrc/public/src/main/kotlin/androidx/build/LibraryGroups.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/LibraryGroups.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryType.kt b/buildSrc/public/src/main/kotlin/androidx/build/LibraryType.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/LibraryType.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/LibraryType.kt
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/public/src/main/kotlin/androidx/build/LibraryVersions.kt
new file mode 100644
index 0000000..d79352a
--- /dev/null
+++ b/buildSrc/public/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build
+
+/**
+ * The list of versions codes of all the libraries in this project.
+ */
+object LibraryVersions {
+ val ACTIVITY = Version("1.4.0-alpha01")
+ val ADS_IDENTIFIER = Version("1.0.0-alpha05")
+ val ANNOTATION = Version("1.3.0-alpha01")
+ val ANNOTATION_EXPERIMENTAL = Version("1.2.0-alpha01")
+ val APPCOMPAT = Version("1.4.0-alpha03")
+ val APPSEARCH = Version("1.0.0-alpha03")
+ val ARCH_CORE = Version("2.2.0-alpha01")
+ val ASYNCLAYOUTINFLATER = Version("1.1.0-alpha01")
+ val AUTOFILL = Version("1.2.0-beta02")
+ val BENCHMARK = Version("1.1.0-alpha07")
+ val BIOMETRIC = Version("1.2.0-alpha03")
+ val BROWSER = Version("1.4.0-alpha01")
+ val BUILDSRC_TESTS = Version("1.0.0-alpha01")
+ val CAMERA = Version("1.1.0-alpha09")
+ val CAMERA_EXTENSIONS = Version("1.0.0-alpha29")
+ val CAMERA_PIPE = Version("1.0.0-alpha01")
+ val CAMERA_VIDEO = Version("1.0.0-alpha01")
+ val CAMERA_VIEW = Version("1.0.0-alpha29")
+ val CARDVIEW = Version("1.1.0-alpha01")
+ val CAR_APP = Version("1.1.0-alpha03")
+ val COLLECTION = Version("1.2.0-alpha02")
+ val CONTENTPAGER = Version("1.1.0-alpha01")
+ val COMPOSE_MATERIAL3 = Version(System.getenv("COMPOSE_CUSTOM_VERSION") ?: "1.1.0-alpha01")
+ val COMPOSE = Version(System.getenv("COMPOSE_CUSTOM_VERSION") ?: "1.1.0-alpha03")
+ val COORDINATORLAYOUT = Version("1.2.0-alpha01")
+ val CORE = Version("1.7.0-alpha01")
+ val CORE_ANIMATION = Version("1.0.0-alpha03")
+ val CORE_ANIMATION_TESTING = Version("1.0.0-alpha03")
+ val CORE_APPDIGEST = Version("1.0.0-alpha01")
+ val CORE_GOOGLE_SHORTCUTS = Version("1.1.0-alpha02")
+ val CORE_ROLE = Version("1.1.0-alpha02")
+ val CORE_SPLASHSCREEN = Version("1.0.0-alpha01")
+ val CURSORADAPTER = Version("1.1.0-alpha01")
+ val CUSTOMVIEW = Version("1.2.0-alpha01")
+ val DATASTORE = Version("1.1.0-alpha01")
+ val DOCUMENTFILE = Version("1.1.0-alpha02")
+ val DRAWERLAYOUT = Version("1.2.0-alpha01")
+ val DYNAMICANIMATION = Version("1.1.0-alpha04")
+ val DYNAMICANIMATION_KTX = Version("1.0.0-alpha04")
+ val EMOJI = Version("1.2.0-alpha03")
+ val EMOJI2 = Version("1.0.0-alpha03")
+ val ENTERPRISE = Version("1.1.0-rc01")
+ val EXIFINTERFACE = Version("1.4.0-alpha01")
+ val FRAGMENT = Version("1.4.0-alpha08")
+ val FUTURES = Version("1.2.0-alpha01")
+ val GLANCE = Version("1.0.0-alpha01")
+ val GRIDLAYOUT = Version("1.1.0-alpha01")
+ val HEALTH_SERVICES_CLIENT = Version("1.0.0-alpha02")
+ val HEIFWRITER = Version("1.1.0-alpha02")
+ val HILT = Version("1.1.0-alpha01")
+ val HILT_NAVIGATION_COMPOSE = Version("1.0.0-alpha04")
+ val INSPECTION = Version("1.0.0")
+ val INTERPOLATOR = Version("1.1.0-alpha01")
+ val JETIFIER = Version("1.0.0-beta11")
+ val LEANBACK = Version("1.2.0-alpha02")
+ val LEANBACK_PAGING = Version("1.1.0-alpha09")
+ val LEANBACK_PREFERENCE = Version("1.2.0-alpha02")
+ val LEANBACK_TAB = Version("1.1.0-beta01")
+ val LEGACY = Version("1.1.0-alpha01")
+ val LOCALBROADCASTMANAGER = Version("1.1.0-alpha02")
+ val LIFECYCLE = Version("2.4.0-alpha04")
+ val LIFECYCLE_VIEWMODEL_COMPOSE = Version("1.0.0-alpha08")
+ val LIFECYCLE_EXTENSIONS = Version("2.2.0")
+ val LOADER = Version("1.2.0-alpha01")
+ val MEDIA = Version("1.5.0-alpha01")
+ val MEDIA2 = Version("1.2.0-beta01")
+ val MEDIAROUTER = Version("1.3.0-alpha01")
+ val NAVIGATION = Version("2.4.0-alpha08")
+ val PAGING = Version("3.1.0-alpha05")
+ val PAGING_COMPOSE = Version("1.0.0-alpha14")
+ val PALETTE = Version("1.1.0-alpha01")
+ val PRINT = Version("1.1.0-beta01")
+ val PERCENTLAYOUT = Version("1.1.0-alpha01")
+ val PREFERENCE = Version("1.2.0-alpha01")
+ val PROFILEINSTALLER = Version("1.1.0-alpha04")
+ val RECOMMENDATION = Version("1.1.0-alpha01")
+ val RECYCLERVIEW = Version("1.3.0-alpha01")
+ val RECYCLERVIEW_SELECTION = Version("1.2.0-alpha02")
+ val REMOTECALLBACK = Version("1.0.0-alpha02")
+ val RESOURCEINSPECTION = Version("1.0.0-alpha03")
+ val ROOM = Version("2.4.0-alpha05")
+ val SAVEDSTATE = Version("1.2.0-alpha01")
+ val SECURITY = Version("1.1.0-alpha04")
+ val SECURITY_APP_AUTHENTICATOR = Version("1.0.0-alpha03")
+ val SECURITY_APP_AUTHENTICATOR_TESTING = Version("1.0.0-alpha02")
+ val SECURITY_BIOMETRIC = Version("1.0.0-alpha01")
+ val SECURITY_IDENTITY_CREDENTIAL = Version("1.0.0-alpha02")
+ val SHARETARGET = Version("1.2.0-alpha02")
+ val SLICE = Version("1.1.0-alpha02")
+ val SLICE_BENCHMARK = Version("1.1.0-alpha02")
+ val SLICE_BUILDERS_KTX = Version("1.0.0-alpha08")
+ val SLICE_REMOTECALLBACK = Version("1.0.0-alpha01")
+ val SLIDINGPANELAYOUT = Version("1.2.0-alpha05")
+ val STARTUP = Version("1.2.0-alpha01")
+ val SQLITE = Version("2.2.0-alpha03")
+ val SQLITE_INSPECTOR = Version("2.1.0-alpha01")
+ val SWIPEREFRESHLAYOUT = Version("1.2.0-alpha01")
+ val TESTSCREENSHOT = Version("1.0.0-alpha01")
+ val TEXT = Version("1.0.0-alpha01")
+ val TEXTCLASSIFIER = Version("1.0.0-alpha03")
+ val TRACING = Version("1.1.0-alpha01")
+ val TRANSITION = Version("1.5.0-alpha01")
+ val TVPROVIDER = Version("1.1.0-alpha02")
+ val VECTORDRAWABLE = Version("1.2.0-alpha03")
+ val VECTORDRAWABLE_ANIMATED = Version("1.2.0-alpha01")
+ val VECTORDRAWABLE_SEEKABLE = Version("1.0.0-alpha03")
+ val VERSIONED_PARCELABLE = Version("1.2.0-alpha01")
+ val VIEWPAGER = Version("1.1.0-alpha01")
+ val VIEWPAGER2 = Version("1.1.0-beta02")
+ val WEAR = Version("1.2.0-beta02")
+ val WEAR_COMPLICATIONS_DATA = Version("1.0.0-alpha21")
+ val WEAR_COMPLICATIONS_DATA_SOURCE = Version("1.0.0-alpha21")
+ val WEAR_COMPLICATIONS_DATA_SOURCE_KTX = Version("1.0.0-alpha21")
+ val WEAR_COMPOSE = Version("1.0.0-alpha05")
+ val WEAR_INPUT = Version("1.2.0-alpha01")
+ val WEAR_INPUT_TESTING = WEAR_INPUT
+ val WEAR_ONGOING = Version("1.1.0-alpha01")
+ val WEAR_PHONE_INTERACTIONS = Version("1.0.0-beta02")
+ val WEAR_REMOTE_INTERACTIONS = Version("1.0.0-beta02")
+ val WEAR_TILES = Version("1.0.0-alpha11")
+ val WEAR_WATCHFACE = Version("1.0.0-alpha21")
+ val WEAR_WATCHFACE_CLIENT = Version("1.0.0-alpha21")
+ val WEAR_WATCHFACE_CLIENT_GUAVA = WEAR_WATCHFACE_CLIENT
+ val WEAR_WATCHFACE_COMPLICATIONS_RENDERING = Version("1.0.0-alpha21")
+ val WEAR_WATCHFACE_DATA = Version("1.0.0-alpha21")
+ val WEAR_WATCHFACE_EDITOR = Version("1.0.0-alpha21")
+ val WEAR_WATCHFACE_EDITOR_GUAVA = WEAR_WATCHFACE_EDITOR
+ val WEAR_WATCHFACE_STYLE = Version("1.0.0-alpha21")
+ val WEBKIT = Version("1.5.0-alpha01")
+ val WINDOW = Version("1.0.0-beta01")
+ val WINDOW_EXTENSIONS = Version("1.0.0-alpha01")
+ val WINDOW_SIDECAR = Version("0.1.0-beta01")
+ val WORK = Version("2.7.0-beta01")
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/OperatingSystem.kt b/buildSrc/public/src/main/kotlin/androidx/build/OperatingSystem.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/OperatingSystem.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/OperatingSystem.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/SdkHelper.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/SdkHelper.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/SdkResourceGenerator.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
new file mode 100644
index 0000000..301071b
--- /dev/null
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 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.build
+
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.plugins.ExtraPropertiesExtension
+import java.io.File
+
+object SupportConfig {
+ const val DEFAULT_MIN_SDK_VERSION = 14
+ const val INSTRUMENTATION_RUNNER = "androidx.test.runner.AndroidJUnitRunner"
+ const val BUILD_TOOLS_VERSION = "30.0.3"
+ val NDK_VERSION by lazy {
+ // TODO(aurimas) b/173737578 remove when we no longer have divergent versions
+ when (getOperatingSystem()) {
+ OperatingSystem.LINUX -> "21.0.6113669"
+ else -> "21.3.6528147"
+ }
+ }
+
+ /**
+ * The Android SDK version to use for compilation.
+ * <p>
+ * Either an integer value or a pre-release platform code, prefixed with "android-" (ex.
+ * "android-28" or "android-Q") as you would see within the SDK's platforms directory.
+ */
+ const val COMPILE_SDK_VERSION = "android-31"
+
+ /**
+ * The Android SDK version to use for targetSdkVersion meta-data.
+ * <p>
+ * Either an integer value (ex. 28), a pre-release platform code (ex. "Q") as you would see
+ * within the SDK's platforms directory as android-<version>, or a released platform version
+ * code as you would see within Build.VERSIONS.VERSION_CODE (ex. "HONEYCOMB" or "P").
+ * <p>
+ * <strong>Note:</strong> This must be set to an integer value or released platform version in
+ * order for tests to run on devices running released versions of the Android OS. If this is
+ * set to a pre-release version, tests will only be able to run on pre-release devices.
+ */
+ const val TARGET_SDK_VERSION = 31
+}
+
+fun Project.getExternalProjectPath(): File {
+ val path = if (System.getenv("COMPOSE_DESKTOP_GITHUB_BUILD") != null)
+ File(System.getenv("OUT_DIR")).also {
+ if (!File(it, "doclava").isDirectory()) {
+ throw GradleException("Please checkout doclava to $it")
+ }
+ }
+ else
+ File(rootProject.projectDir, "../../external")
+ return path.getCanonicalFile()
+}
+
+fun Project.getKeystore(): File {
+ return File(project.getSupportRootFolder(), "development/keystore/debug.keystore")
+}
+
+fun Project.getPrebuiltsRoot(): File {
+ val ext = project.rootProject.property("ext") as ExtraPropertiesExtension
+ val reposProperties = ext.get("repos") as Map<*, *>
+ return File(reposProperties["prebuiltsRoot"].toString())
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/Version.kt b/buildSrc/public/src/main/kotlin/androidx/build/Version.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/Version.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/Version.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/public/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/gradle/Extensions.kt b/buildSrc/public/src/main/kotlin/androidx/build/gradle/Extensions.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/gradle/Extensions.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/gradle/Extensions.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/shadow/AndroidXDontIncludeResourceTransformer.kt b/buildSrc/public/src/main/kotlin/androidx/build/shadow/AndroidXDontIncludeResourceTransformer.kt
similarity index 100%
rename from buildSrc/src/main/kotlin/androidx/build/shadow/AndroidXDontIncludeResourceTransformer.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/shadow/AndroidXDontIncludeResourceTransformer.kt
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
deleted file mode 100644
index c17b7b7..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build
-
-import androidx.build.checkapi.shouldConfigureApiTasks
-import groovy.lang.Closure
-import org.gradle.api.GradleException
-import org.gradle.api.Project
-import java.util.ArrayList
-
-/**
- * Extension for [AndroidXPlugin] that's responsible for holding configuration options.
- */
-open class AndroidXExtension(val project: Project) {
-
- var name: String? = null
- var mavenVersion: Version? = null
- set(value) {
- field = value
- chooseProjectVersion()
- }
- var mavenGroup: LibraryGroup? = null
- set(value) {
- field = value
- chooseProjectVersion()
- }
- private val ALLOWED_EXTRA_PREFIXES = listOf("-alpha", "-beta", "-rc", "-dev", "-SNAPSHOT")
-
- private fun chooseProjectVersion() {
- val version: Version
- val group: String? = mavenGroup?.group
- val groupVersion: Version? = mavenGroup?.forcedVersion
- val mavenVersion: Version? = mavenVersion
- if (mavenVersion != null) {
- if (groupVersion != null && !isGroupVersionOverrideAllowed()) {
- throw GradleException(
- "Cannot set mavenVersion (" + mavenVersion +
- ") for a project (" + project +
- ") whose mavenGroup already specifies forcedVersion (" + groupVersion +
- ")"
- )
- } else {
- verifyVersionExtraFormat(mavenVersion)
- version = mavenVersion
- }
- } else {
- if (groupVersion != null) {
- verifyVersionExtraFormat(groupVersion)
- version = groupVersion
- } else {
- return
- }
- }
- if (group != null) {
- project.group = group
- }
- project.version = if (isSnapshotBuild()) version.copy(extra = "-SNAPSHOT") else version
- versionIsSet = true
- }
-
- private fun verifyVersionExtraFormat(version: Version) {
- val extra = version.extra
- if (extra != null) {
- if (!version.isSnapshot() && project.isVersionExtraCheckEnabled()) {
- if (ALLOWED_EXTRA_PREFIXES.any { extra.startsWith(it) }) {
- for (potentialPrefix in ALLOWED_EXTRA_PREFIXES) {
- if (extra.startsWith(potentialPrefix)) {
- val secondExtraPart = extra.removePrefix(
- potentialPrefix
- )
- if (secondExtraPart.toIntOrNull() == null) {
- throw IllegalArgumentException(
- "Version $version is not" +
- " a properly formatted version, please ensure that " +
- "$potentialPrefix is followed by a number only"
- )
- }
- }
- }
- } else {
- throw IllegalArgumentException(
- "Version $version is not a proper " +
- "version, version suffixes following major.minor.patch should " +
- "be one of ${ALLOWED_EXTRA_PREFIXES.joinToString(", ")}"
- )
- }
- }
- }
- }
-
- private fun isGroupVersionOverrideAllowed(): Boolean {
- // Grant an exception to the same-version-group policy for artifacts that haven't shipped a
- // stable API surface, e.g. 1.0.0-alphaXX, to allow for rapid early-stage development.
- val version = mavenVersion
- return version != null && version.major == 1 && version.minor == 0 && version.patch == 0 &&
- version.isAlpha()
- }
-
- private var versionIsSet = false
- fun isVersionSet(): Boolean {
- return versionIsSet
- }
- var description: String? = null
- var inceptionYear: String? = null
- /**
- * targetsJavaConsumers = true, if project is intended to be accessed from Java-language
- * source code.
- */
- var targetsJavaConsumers = true
- get() {
- when (project.path) {
- // add per-project overrides here
- // for example
- // the following project is intended to be accessed from Java
- // ":compose:lint:internal-lint-checks" -> return true
- // the following project is not intended to be accessed from Java
- // ":annotation:annotation" -> return false
- }
- // TODO: rework this to use LibraryType. Fork Library and KolinOnlyLibrary?
- if (project.path.contains("-ktx")) return false
- if (project.path.contains("compose")) return false
- if (project.path.startsWith(":ui")) return false
- return field
- }
- private var licenses: MutableCollection<License> = ArrayList()
-
- // Should only be used to override LibraryType.publish, if a library isn't ready to publish yet
- var publish: Publish = Publish.UNSET
- // Allow gradual transition from publish to library type
- get() = if (field == Publish.UNSET && type != LibraryType.UNSET) type.publish else field
- /**
- * Whether to run API tasks such as tracking and linting. The default value is
- * [RunApiTasks.Auto], which automatically picks based on the project's properties.
- */
- // TODO: decide whether we want to support overriding runApiTasks
- // @Deprecated("Replaced with AndroidXExtension.type: LibraryType.runApiTasks")
- var runApiTasks: RunApiTasks = RunApiTasks.Auto
- get() = if (field == RunApiTasks.Auto && type != LibraryType.UNSET) type.checkApi else field
- var type: LibraryType = LibraryType.UNSET
- var failOnDeprecationWarnings = true
-
- var legacyDisableKotlinStrictApiMode = false
-
- var benchmarkRunAlsoInterpreted = false
-
- fun shouldEnforceKotlinStrictApiMode(): Boolean {
- return !legacyDisableKotlinStrictApiMode &&
- shouldConfigureApiTasks()
- }
-
- fun license(closure: Closure<Any>): License {
- val license = project.configure(License(), closure) as License
- licenses.add(license)
- return license
- }
-
- fun getLicenses(): Collection<License> {
- return licenses
- }
-
- companion object {
- const val DEFAULT_UNSPECIFIED_VERSION = "unspecified"
- }
-}
-
-class License {
- var name: String? = null
- var url: String? = null
-}
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt
deleted file mode 100644
index 2e1a200..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build
-
-import androidx.build.AndroidXPlugin.Companion.ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK
-import androidx.build.AndroidXPlugin.Companion.ZIP_TEST_CONFIGS_WITH_APKS_TASK
-import androidx.build.dependencyTracker.AffectedModuleDetector
-import androidx.build.gradle.isRoot
-import androidx.build.license.CheckExternalDependencyLicensesTask
-import androidx.build.playground.VerifyPlaygroundGradlePropertiesTask
-import androidx.build.studio.StudioTask.Companion.registerStudioTask
-import androidx.build.testConfiguration.registerOwnersServiceTasks
-import androidx.build.uptodatedness.TaskUpToDateValidator
-import com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
-import com.android.build.gradle.AppPlugin
-import com.android.build.gradle.LibraryPlugin
-import org.gradle.api.GradleException
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.api.artifacts.component.ModuleComponentSelector
-import org.gradle.api.plugins.JavaPlugin
-import org.gradle.api.tasks.bundling.Zip
-import org.gradle.api.tasks.bundling.ZipEntryCompression
-import org.gradle.build.event.BuildEventsListenerRegistry
-import org.gradle.kotlin.dsl.KotlinClosure1
-import org.gradle.kotlin.dsl.extra
-import java.io.File
-import java.util.Locale
-import java.util.concurrent.ConcurrentHashMap
-
-abstract class AndroidXRootPlugin : Plugin<Project> {
- @Suppress("UnstableApiUsage")
- @get:javax.inject.Inject
- abstract val registry: BuildEventsListenerRegistry
-
- override fun apply(project: Project) {
- if (!project.isRoot) {
- throw Exception("This plugin should only be applied to root project")
- }
- project.configureRootProject()
- }
-
- @OptIn(ExperimentalStdlibApi::class) // string extensions
- private fun Project.configureRootProject() {
- project.validateAllAndroidxArgumentsAreRecognized()
- tasks.register("listAndroidXProperties", ListAndroidXPropertiesTask::class.java)
- setDependencyVersions()
- configureKtlintCheckFile()
- tasks.register(CheckExternalDependencyLicensesTask.TASK_NAME)
-
- // Validate the Android Gradle Plugin version, if specified.
- val expectedAgpVersion = System.getenv("EXPECTED_AGP_VERSION")
- if (expectedAgpVersion != null && expectedAgpVersion != ANDROID_GRADLE_PLUGIN_VERSION) {
- throw Exception(
- "Expected AGP version \"$expectedAgpVersion\" does not match actual " +
- "AGP version \"$ANDROID_GRADLE_PLUGIN_VERSION\". Please close and restart " +
- "Studio."
- )
- }
-
- val buildOnServerTask = tasks.create(
- AndroidXPlugin.BUILD_ON_SERVER_TASK,
- BuildOnServer::class.java
- )
- buildOnServerTask.dependsOn(
- tasks.register(
- AndroidXPlugin.CREATE_AGGREGATE_BUILD_INFO_FILES_TASK,
- CreateAggregateLibraryBuildInfoFileTask::class.java
- )
- )
- buildOnServerTask.dependsOn(
- tasks.register(AndroidXPlugin.CREATE_LIBRARY_BUILD_INFO_FILES_TASK)
- )
-
- VerifyPlaygroundGradlePropertiesTask.createIfNecessary(project)?.let {
- buildOnServerTask.dependsOn(it)
- }
-
- val createArchiveTask = Release.getGlobalFullZipTask(this)
- buildOnServerTask.dependsOn(createArchiveTask)
- val partiallyDejetifyArchiveTask = partiallyDejetifyArchiveTask(
- createArchiveTask.get().archiveFile
- )
- if (partiallyDejetifyArchiveTask != null)
- buildOnServerTask.dependsOn(partiallyDejetifyArchiveTask)
-
- buildOnServerTask.dependsOn(
- tasks.register(
- "saveSystemStats",
- SaveSystemStatsTask::class.java
- ) { task ->
- task.outputFile.set(File(project.getDistributionDirectory(), "system_stats.txt"))
- }
- )
-
- extra.set("projects", ConcurrentHashMap<String, String>())
- buildOnServerTask.dependsOn(tasks.named(CheckExternalDependencyLicensesTask.TASK_NAME))
- // Anchor task that invokes running all subprojects :validateProperties tasks which ensure that
- // Android Studio sync is able to succeed.
- val validateAllProperties = tasks.register("validateAllProperties")
- subprojects { project ->
- // Add a method for each sub project where they can declare an optional
- // dependency on a project or its latest snapshot artifact.
- // In AndroidX build, this is always enforsed to the project while in Playground
- // builds, they are converted to the latest SNAPSHOT artifact if the project is
- // not included in that playground. see: AndroidXPlaygroundRootPlugin
- project.extra.set(
- PROJECT_OR_ARTIFACT_EXT_NAME,
- KotlinClosure1<String, Project>(
- function = {
- // this refers to the first parameter of the closure.
- project.project(this)
- }
- )
- )
- project.afterEvaluate {
- if (project.plugins.hasPlugin(LibraryPlugin::class.java) ||
- project.plugins.hasPlugin(AppPlugin::class.java)
- ) {
-
- buildOnServerTask.dependsOn("${project.path}:assembleRelease")
- if (!project.usingMaxDepVersions()) {
- project.agpVariants.all { variant ->
- // in AndroidX, release and debug variants are essentially the same,
- // so we don't run the lintRelease task on the build server
- if (!variant.name.lowercase(Locale.getDefault()).contains("release")) {
- val taskName = "lint${variant.name.replaceFirstChar {
- if (it.isLowerCase()) {
- it.titlecase(Locale.getDefault())
- } else {
- it.toString()
- }
- }}"
- buildOnServerTask.dependsOn("${project.path}:$taskName")
- }
- }
- }
- }
- }
- project.plugins.withType(JavaPlugin::class.java) {
- buildOnServerTask.dependsOn("${project.path}:jar")
- }
-
- val validateProperties = project.tasks.register(
- "validateProperties",
- ValidatePropertiesTask::class.java
- )
- validateAllProperties.configure {
- it.dependsOn(validateProperties)
- }
- }
-
- if (partiallyDejetifyArchiveTask != null) {
- project(":jetifier:jetifier-standalone").afterEvaluate { standAloneProject ->
- partiallyDejetifyArchiveTask.configure {
- it.dependsOn(standAloneProject.tasks.named("installDist"))
- }
- createArchiveTask.configure {
- it.dependsOn(standAloneProject.tasks.named("dist"))
- }
- }
- }
-
- tasks.register(AndroidXPlugin.BUILD_TEST_APKS_TASK)
-
- project.tasks.register(
- ZIP_TEST_CONFIGS_WITH_APKS_TASK, Zip::class.java
- ) {
- it.destinationDirectory.set(project.getDistributionDirectory())
- it.archiveFileName.set("androidTest.zip")
- it.from(project.getTestConfigDirectory())
- // We're mostly zipping a bunch of .apk files that are already compressed
- it.entryCompression = ZipEntryCompression.STORED
- }
- project.tasks.register(
- ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK, Zip::class.java
- ) {
- it.destinationDirectory.set(project.getDistributionDirectory())
- it.archiveFileName.set("constrainedAndroidTest.zip")
- it.from(project.getConstrainedTestConfigDirectory())
- // We're mostly zipping a bunch of .apk files that are already compressed
- it.entryCompression = ZipEntryCompression.STORED
- }
-
- AffectedModuleDetector.configure(gradle, this)
-
- // Needs to be called before evaluationDependsOnChildren in usingMaxDepVersions block
- publishInspectionArtifacts()
- registerOwnersServiceTasks()
-
- // If useMaxDepVersions is set, iterate through all the project and substitute any androidx
- // artifact dependency with the local tip of tree version of the library.
- if (project.usingMaxDepVersions()) {
- // This requires evaluating all sub-projects to create the module:project map
- // and project dependencies.
- allprojects { project2 ->
- // evaluationDependsOnChildren isn't transitive so we must call it on each project
- project2.evaluationDependsOnChildren()
- }
- val projectModules = getProjectsMap()
- subprojects { subproject ->
- // TODO(153485458) remove most of these exceptions
- if (!subproject.name.contains("hilt") &&
- subproject.name != "docs-public" &&
- subproject.name != "docs-tip-of-tree" &&
- subproject.name != "camera-testapp-timing" &&
- subproject.name != "room-testapp" &&
- !(
- subproject.path.contains
- ("media2:media2-session:version-compat-tests:client-previous")
- ) &&
- !(
- subproject.path.contains
- ("media2:media2-session:version-compat-tests:service-previous")
- )
- ) {
- subproject.configurations.all { configuration ->
- configuration.resolutionStrategy.dependencySubstitution.apply {
- all { dep ->
- val requested = dep.getRequested()
- if (requested is ModuleComponentSelector) {
- val module = requested.group + ":" + requested.module
- if (projectModules.containsKey(module)) {
- dep.useTarget(project(projectModules[module]!!))
- }
- }
- }
- }
- }
- }
- }
- }
-
- registerStudioTask()
-
- TaskUpToDateValidator.setup(project, registry)
-
- project.tasks.register("listTaskOutputs", ListTaskOutputsTask::class.java) { task ->
- task.setOutput(File(project.getDistributionDirectory(), "task_outputs.txt"))
- task.removePrefix(project.getCheckoutRoot().path)
- }
- }
-
- @Suppress("UnstableApiUsage")
- private fun Project.setDependencyVersions() {
- val libs = project.extensions.getByType(
- VersionCatalogsExtension::class.java
- ).find("libs").get()
- fun getVersion(key: String): String {
- val version = libs.findVersion(key)
- return if (version.isPresent) {
- version.get().requiredVersion
- } else {
- throw GradleException("Could not find a version for `$key`")
- }
- }
- androidx.build.dependencies.kotlinVersion = getVersion("kotlin")
- androidx.build.dependencies.kspVersion = getVersion("ksp")
- androidx.build.dependencies.agpVersion = getVersion("androidGradlePlugin")
- androidx.build.dependencies.guavaVersion = getVersion("guavaJre")
- }
-
- companion object {
- const val PROJECT_OR_ARTIFACT_EXT_NAME = "projectOrArtifact"
- }
-}
diff --git a/buildSrc/src/main/kotlin/androidx/build/Jetify.kt b/buildSrc/src/main/kotlin/androidx/build/Jetify.kt
deleted file mode 100644
index f2e5dde..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/Jetify.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build
-
-import org.gradle.api.Project
-import org.gradle.api.file.RegularFile
-import org.gradle.api.provider.Provider
-import org.gradle.api.tasks.Exec
-import org.gradle.api.tasks.TaskProvider
-import org.gradle.api.tasks.bundling.Zip
-
-val archivesToDejetify = listOf(
- "m2repository/androidx/activity/**",
- "m2repository/androidx/ads/identifier/**",
- "m2repository/androidx/annotation/**",
- "m2repository/androidx/autofill/**",
- "m2repository/androidx/appcompat/**",
- "m2repository/androidx/arch/**",
- "m2repository/androidx/arch/core/**",
- "m2repository/androidx/asynclayoutinflater/**",
- "m2repository/androidx/benchmark/**",
- "m2repository/androidx/biometric/**",
- "m2repository/androidx/browser/**",
- "m2repository/androidx/camera/**",
- "m2repository/androidx/car/**",
- "m2repository/androidx/cardview/**",
- "m2repository/androidx/collection/collection/**",
- "m2repository/androidx/collection/collection-ktx/**",
- "m2repository/androidx/contentpager/**",
- "m2repository/androidx/coordinatorlayout/**",
- "m2repository/androidx/core/core/**",
- "m2repository/androidx/core/core-ktx/**",
- "m2repository/androidx/cursoradapter/**",
- "m2repository/androidx/customview/**",
- "m2repository/androidx/documentfile/**",
- "m2repository/androidx/drawerlayout/**",
- "m2repository/androidx/dynamicanimation/**",
- "m2repository/androidx/emoji/**",
- "m2repository/androidx/exifinterface/**",
- "m2repository/androidx/fragment/fragment/**",
- "m2repository/androidx/fragment/fragment-ktx/**",
- "m2repository/androidx/fragment/fragment-testing/**",
- "m2repository/androidx/gridlayout/**",
- "m2repository/androidx/heifwriter/**",
- "m2repository/androidx/interpolator/**",
- "m2repository/androidx/leanback/**",
- "m2repository/androidx/legacy/**",
- "m2repository/androidx/lifecycle/**",
- "m2repository/androidx/loader/**",
- "m2repository/androidx/localbroadcastmanager/**",
- "m2repository/androidx/media/media/**",
- "m2repository/androidx/mediarouter/**",
- "m2repository/androidx/navigation/**",
- "m2repository/androidx/palette/palette/**",
- "m2repository/androidx/percentlayout/**",
- "m2repository/androidx/preference/preference/**",
- "m2repository/androidx/print/**",
- "m2repository/androidx/paging/**",
- "m2repository/androidx/room/**",
- "m2repository/androidx/work/**",
- "m2repository/androidx/recommendation/**",
- "m2repository/androidx/recyclerview/**",
- "m2repository/androidx/remotecallback/**",
- "m2repository/androidx/savedstate/**",
- "m2repository/androidx/slice/slice-builders/**",
- "m2repository/androidx/slice/slice-core/**",
- "m2repository/androidx/slice/slice-view/**",
- "m2repository/androidx/slidingpanelayout/**",
- "m2repository/androidx/swiperefreshlayout/**",
- "m2repository/androidx/sqlite/**",
- "m2repository/androidx/textclassifier/**",
- "m2repository/androidx/transition/**",
- "m2repository/androidx/tvprovider/**",
- "m2repository/androidx/vectordrawable/**",
- "m2repository/androidx/versionedparcelable/**",
- "m2repository/androidx/viewpager/**",
- "m2repository/androidx/viewpager2/**",
- "m2repository/androidx/wear/**",
- "m2repository/androidx/webkit/**",
- "m2repository/androidx/media2/**",
- "m2repository/androidx/concurrent/**",
- "m2repository/androidx/sharetarget/**"
-)
-
-fun Project.partiallyDejetifyArchiveTask(archiveFile: Provider<RegularFile>): TaskProvider<Exec>? {
- return findProject(":jetifier:jetifier-standalone")?.let { standaloneProject ->
- val stripTask = stripArchiveForPartialDejetificationTask(archiveFile)
-
- tasks.register("partiallyDejetifyArchive", Exec::class.java) {
- val outputFileName = "${getDistributionDirectory().absolutePath}/" +
- "top-of-tree-m2repository-partially-dejetified-${getBuildId()}.zip"
- val jetifierBin = "${standaloneProject.buildDir}/install/jetifier-standalone/bin/" +
- "jetifier-standalone"
- val migrationConfig = "${standaloneProject.projectDir.getParentFile()}/migration.config"
-
- it.dependsOn(stripTask)
- it.inputs.file(stripTask.get().archiveFile)
- it.outputs.file(outputFileName)
-
- it.commandLine = listOf(
- jetifierBin,
- "-i", "${it.inputs.files.singleFile}",
- "-o", "${it.outputs.files.singleFile}",
- "-c", migrationConfig,
- "--log", "warning",
- "--reversed",
- "--rebuildTopOfTree"
- )
- }
- }
-}
-
-fun Project.stripArchiveForPartialDejetificationTask(archiveFile: Provider<RegularFile>):
- TaskProvider<Zip> {
- return tasks.register("stripArchiveForPartialDejetification", Zip::class.java) {
- it.dependsOn(rootProject.tasks.named(Release.FULL_ARCHIVE_TASK_NAME))
- it.from(zipTree(archiveFile))
- it.destinationDirectory.set(rootProject.buildDir)
- it.archiveFileName.set("stripped_archive_partial.zip")
- it.include(archivesToDejetify)
- }
- }
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
deleted file mode 100644
index 0461a12..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build
-
-/**
- * The list of versions codes of all the libraries in this project.
- */
-object LibraryVersions {
- val ACTIVITY = Version("1.4.0-alpha01")
- val ADS_IDENTIFIER = Version("1.0.0-alpha05")
- val ANNOTATION = Version("1.3.0-alpha01")
- val ANNOTATION_EXPERIMENTAL = Version("1.2.0-alpha01")
- val APPCOMPAT = Version("1.4.0-alpha03")
- val APPSEARCH = Version("1.0.0-alpha01")
- val ARCH_CORE = Version("2.2.0-alpha01")
- val ASYNCLAYOUTINFLATER = Version("1.1.0-alpha01")
- val AUTOFILL = Version("1.2.0-beta02")
- val BENCHMARK = Version("1.1.0-alpha06")
- val BIOMETRIC = Version("1.2.0-alpha03")
- val BROWSER = Version("1.4.0-alpha01")
- val BUILDSRC_TESTS = Version("1.0.0-alpha01")
- val CAMERA = Version("1.1.0-alpha08")
- val CAMERA_EXTENSIONS = Version("1.0.0-alpha28")
- val CAMERA_PIPE = Version("1.0.0-alpha01")
- val CAMERA_VIDEO = Version("1.0.0-alpha01")
- val CAMERA_VIEW = Version("1.0.0-alpha28")
- val CARDVIEW = Version("1.1.0-alpha01")
- val CAR_APP = Version("1.1.0-alpha03")
- val COLLECTION = Version("1.2.0-alpha02")
- val CONTENTPAGER = Version("1.1.0-alpha01")
- val COMPOSE_MATERIAL3 = Version(System.getenv("COMPOSE_CUSTOM_VERSION") ?: "1.1.0-alpha01")
- val COMPOSE = Version(System.getenv("COMPOSE_CUSTOM_VERSION") ?: "1.1.0-alpha02")
- val COORDINATORLAYOUT = Version("1.2.0-alpha01")
- val CORE = Version("1.7.0-alpha01")
- val CORE_ANIMATION = Version("1.0.0-alpha03")
- val CORE_ANIMATION_TESTING = Version("1.0.0-alpha03")
- val CORE_APPDIGEST = Version("1.0.0-alpha01")
- val CORE_GOOGLE_SHORTCUTS = Version("1.1.0-alpha02")
- val CORE_ROLE = Version("1.1.0-alpha02")
- val CURSORADAPTER = Version("1.1.0-alpha01")
- val CUSTOMVIEW = Version("1.2.0-alpha01")
- val DATASTORE = Version("1.1.0-alpha01")
- val DOCUMENTFILE = Version("1.1.0-alpha01")
- val DRAWERLAYOUT = Version("1.2.0-alpha01")
- val DYNAMICANIMATION = Version("1.1.0-alpha04")
- val DYNAMICANIMATION_KTX = Version("1.0.0-alpha04")
- val EMOJI = Version("1.2.0-alpha03")
- val EMOJI2 = Version("1.0.0-alpha03")
- val ENTERPRISE = Version("1.1.0-rc01")
- val EXIFINTERFACE = Version("1.4.0-alpha01")
- val FRAGMENT = Version("1.4.0-alpha07")
- val FUTURES = Version("1.2.0-alpha01")
- val GLANCE = Version("1.0.0-alpha01")
- val GRIDLAYOUT = Version("1.1.0-alpha01")
- val HEALTH_SERVICES_CLIENT = Version("1.0.0-alpha02")
- val HEIFWRITER = Version("1.1.0-alpha02")
- val HILT = Version("1.1.0-alpha01")
- val HILT_NAVIGATION_COMPOSE = Version("1.0.0-alpha04")
- val INSPECTION = Version("1.0.0")
- val INTERPOLATOR = Version("1.1.0-alpha01")
- val JETIFIER = Version("1.0.0-beta11")
- val LEANBACK = Version("1.2.0-alpha02")
- val LEANBACK_PAGING = Version("1.1.0-alpha09")
- val LEANBACK_PREFERENCE = Version("1.2.0-alpha02")
- val LEANBACK_TAB = Version("1.1.0-beta01")
- val LEGACY = Version("1.1.0-alpha01")
- val LOCALBROADCASTMANAGER = Version("1.1.0-alpha02")
- val LIFECYCLE = Version("2.4.0-alpha04")
- val LIFECYCLE_VIEWMODEL_COMPOSE = Version("1.0.0-alpha08")
- val LIFECYCLE_EXTENSIONS = Version("2.2.0")
- val LOADER = Version("1.2.0-alpha01")
- val MEDIA = Version("1.5.0-alpha01")
- val MEDIA2 = Version("1.2.0-beta01")
- val MEDIAROUTER = Version("1.3.0-alpha01")
- val NAVIGATION = Version("2.4.0-alpha07")
- val PAGING = Version("3.1.0-alpha04")
- val PAGING_COMPOSE = Version("1.0.0-alpha13")
- val PALETTE = Version("1.1.0-alpha01")
- val PRINT = Version("1.1.0-beta01")
- val PERCENTLAYOUT = Version("1.1.0-alpha01")
- val PREFERENCE = Version("1.2.0-alpha01")
- val PROFILEINSTALLER = Version("1.1.0-alpha03")
- val RECOMMENDATION = Version("1.1.0-alpha01")
- val RECYCLERVIEW = Version("1.3.0-alpha01")
- val RECYCLERVIEW_SELECTION = Version("1.2.0-alpha02")
- val REMOTECALLBACK = Version("1.0.0-alpha02")
- val RESOURCEINSPECTION = Version("1.0.0-alpha03")
- val ROOM = Version("2.4.0-alpha05")
- val SAVEDSTATE = Version("1.2.0-alpha01")
- val SECURITY = Version("1.1.0-alpha04")
- val SECURITY_APP_AUTHENTICATOR = Version("1.0.0-alpha03")
- val SECURITY_APP_AUTHENTICATOR_TESTING = Version("1.0.0-alpha02")
- val SECURITY_BIOMETRIC = Version("1.0.0-alpha01")
- val SECURITY_IDENTITY_CREDENTIAL = Version("1.0.0-alpha02")
- val SHARETARGET = Version("1.2.0-alpha02")
- val SLICE = Version("1.1.0-alpha02")
- val SLICE_BENCHMARK = Version("1.1.0-alpha02")
- val SLICE_BUILDERS_KTX = Version("1.0.0-alpha08")
- val SLICE_REMOTECALLBACK = Version("1.0.0-alpha01")
- val SLIDINGPANELAYOUT = Version("1.2.0-alpha03")
- val STARTUP = Version("1.2.0-alpha01")
- val SQLITE = Version("2.2.0-alpha03")
- val SQLITE_INSPECTOR = Version("2.1.0-alpha01")
- val SWIPEREFRESHLAYOUT = Version("1.2.0-alpha01")
- val TESTSCREENSHOT = Version("1.0.0-alpha01")
- val TEXT = Version("1.0.0-alpha01")
- val TEXTCLASSIFIER = Version("1.0.0-alpha03")
- val TRACING = Version("1.1.0-alpha01")
- val TRANSITION = Version("1.5.0-alpha01")
- val TVPROVIDER = Version("1.1.0-alpha02")
- val VECTORDRAWABLE = Version("1.2.0-alpha03")
- val VECTORDRAWABLE_ANIMATED = Version("1.2.0-alpha01")
- val VECTORDRAWABLE_SEEKABLE = Version("1.0.0-alpha03")
- val VERSIONED_PARCELABLE = Version("1.2.0-alpha01")
- val VIEWPAGER = Version("1.1.0-alpha01")
- val VIEWPAGER2 = Version("1.1.0-beta02")
- val WEAR = Version("1.2.0-alpha14")
- val WEAR_COMPLICATIONS_DATA = Version("1.0.0-alpha20")
- val WEAR_COMPLICATIONS_DATA_SOURCE = Version("1.0.0-alpha20")
- val WEAR_COMPLICATIONS_DATA_SOURCE_KTX = Version("1.0.0-alpha19")
- val WEAR_COMPOSE = Version("1.0.0-alpha04")
- val WEAR_INPUT = Version("1.2.0-alpha01")
- val WEAR_INPUT_TESTING = WEAR_INPUT
- val WEAR_ONGOING = Version("1.0.0-beta02")
- val WEAR_PHONE_INTERACTIONS = Version("1.0.0-alpha08")
- val WEAR_REMOTE_INTERACTIONS = Version("1.0.0-beta01")
- val WEAR_TILES = Version("1.0.0-alpha11")
- val WEAR_WATCHFACE = Version("1.0.0-alpha20")
- val WEAR_WATCHFACE_CLIENT = Version("1.0.0-alpha20")
- val WEAR_WATCHFACE_CLIENT_GUAVA = WEAR_WATCHFACE_CLIENT
- val WEAR_WATCHFACE_COMPLICATIONS_RENDERING = Version("1.0.0-alpha20")
- val WEAR_WATCHFACE_DATA = Version("1.0.0-alpha20")
- val WEAR_WATCHFACE_EDITOR = Version("1.0.0-alpha20")
- val WEAR_WATCHFACE_EDITOR_GUAVA = WEAR_WATCHFACE_EDITOR
- val WEAR_WATCHFACE_STYLE = Version("1.0.0-alpha20")
- val WEBKIT = Version("1.5.0-alpha01")
- val WINDOW = Version("1.0.0-alpha11")
- val WINDOW_EXTENSIONS = Version("1.0.0-alpha01")
- val WINDOW_SIDECAR = Version("0.1.0-alpha01")
- val WORK = Version("2.6.0-beta02")
-}
diff --git a/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt b/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
deleted file mode 100644
index b390ae9..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build
-
-import androidx.build.AndroidXComposePlugin.Companion.isMultiplatformEnabled
-import com.android.build.gradle.LibraryPlugin
-import groovy.util.Node
-import org.gradle.api.GradleException
-import org.gradle.api.Project
-import org.gradle.api.XmlProvider
-import org.gradle.api.artifacts.Dependency
-import org.gradle.api.artifacts.ProjectDependency
-import org.gradle.api.component.SoftwareComponent
-import org.gradle.api.publish.PublishingExtension
-import org.gradle.api.publish.maven.MavenPom
-import org.gradle.api.publish.maven.MavenPublication
-import org.gradle.api.publish.tasks.GenerateModuleMetadata
-import org.gradle.kotlin.dsl.configure
-import org.gradle.kotlin.dsl.create
-import org.gradle.kotlin.dsl.findByType
-import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
-import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
-import java.io.File
-
-fun Project.configureMavenArtifactUpload(extension: AndroidXExtension) {
- apply(mapOf("plugin" to "maven-publish"))
-
- afterEvaluate {
- components.all { component ->
- configureComponent(extension, component)
- }
- }
-}
-
-private fun Project.configureComponent(
- extension: AndroidXExtension,
- component: SoftwareComponent
-) {
- if (extension.publish.shouldPublish() && component.isAndroidOrJavaReleaseComponent()) {
- val androidxGroup = validateCoordinatesAndGetGroup(extension)
- group = androidxGroup
- configure<PublishingExtension> {
- repositories {
- it.maven { repo ->
- repo.setUrl(getRepositoryDirectory())
- }
- }
- publications {
- if (appliesJavaGradlePluginPlugin()) {
- // The 'java-gradle-plugin' will also add to the 'pluginMaven' publication
- it.create<MavenPublication>("pluginMaven")
- tasks.getByName("publishPluginMavenPublicationToMavenRepository").doFirst {
- removePreviouslyUploadedArchives(androidxGroup)
- }
- } else {
- it.create<MavenPublication>("maven") {
- from(component)
- }
- tasks.getByName("publishMavenPublicationToMavenRepository").doFirst {
- removePreviouslyUploadedArchives(androidxGroup)
- }
- }
- }
- publications.withType(MavenPublication::class.java).all {
- it.pom { pom ->
- addInformativeMetadata(extension, pom)
- tweakDependenciesMetadata(extension, pom)
- }
- }
- }
-
- // Register it as part of release so that we create a Zip file for it
- Release.register(this, extension)
-
- // Workaround for https://github.com/gradle/gradle/issues/11717
- project.tasks.withType(GenerateModuleMetadata::class.java).configureEach { task ->
- task.doLast {
- val metadata = task.outputFile.asFile.get()
- var text = metadata.readText()
- metadata.writeText(
- text.replace(
- "\"buildId\": .*".toRegex(),
- "\"buildId:\": \"${getBuildId()}\""
- )
- )
- }
- }
-
- if (isMultiplatformEnabled()) {
- configureMultiplatformPublication()
- }
- }
-}
-
-private fun Project.configureMultiplatformPublication() {
- val multiplatformExtension = extensions.findByType<KotlinMultiplatformExtension>() ?: return
-
- // publishMavenPublicationToMavenRepository will produce conflicting artifacts with the same
- // name as the artifacts producing by publishKotlinMultiplatformPublicationToMavenRepository
- project.tasks.findByName("publishMavenPublicationToMavenRepository")?.enabled = false
-
- multiplatformExtension.targets.all { target ->
- if (target is KotlinAndroidTarget) {
- target.publishAllLibraryVariants()
- }
- }
-}
-
-private fun SoftwareComponent.isAndroidOrJavaReleaseComponent() =
- name == "release" || name == "java"
-
-private fun Project.validateCoordinatesAndGetGroup(extension: AndroidXExtension): String {
- val mavenGroup = extension.mavenGroup?.group
- ?: throw Exception("You must specify mavenGroup for $name project")
- val strippedGroupId = mavenGroup.substringAfterLast(".")
- if (mavenGroup.startsWith("androidx") && !name.startsWith(strippedGroupId)) {
- throw Exception("Your artifactId must start with '$strippedGroupId'. (currently is $name)")
- }
- return mavenGroup
-}
-
-/**
- * Delete any existing archives, so that developers don't get
- * confused/surprised by the presence of old versions.
- * Additionally, deleting old versions makes it more convenient to iterate
- * over all existing archives without visiting archives having old versions too
- */
-private fun Project.removePreviouslyUploadedArchives(group: String) {
- val projectArchiveDir = File(
- getRepositoryDirectory(),
- "${group.replace('.', '/')}/${project.name}"
- )
- projectArchiveDir.deleteRecursively()
-}
-
-private fun Project.addInformativeMetadata(extension: AndroidXExtension, pom: MavenPom) {
- pom.name.set(provider { extension.name })
- pom.description.set(provider { extension.description })
- pom.url.set(
- provider {
- fun defaultUrl() = "https://developer.android.com/jetpack/androidx/releases/" +
- extension.mavenGroup!!.group.removePrefix("androidx.")
- .replace(".", "-") +
- "#" + extension.project.version()
- getAlternativeProjectUrl() ?: defaultUrl()
- }
- )
- pom.inceptionYear.set(provider { extension.inceptionYear })
- pom.licenses { licenses ->
- licenses.license { license ->
- license.name.set("The Apache Software License, Version 2.0")
- license.url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
- license.distribution.set("repo")
- }
- for (extraLicense in extension.getLicenses()) {
- licenses.license { license ->
- license.name.set(provider { extraLicense.name })
- license.url.set(provider { extraLicense.url })
- license.distribution.set("repo")
- }
- }
- }
- pom.scm { scm ->
- scm.url.set("https://cs.android.com/androidx/platform/frameworks/support")
- scm.connection.set(ANDROID_GIT_URL)
- }
- pom.developers { devs ->
- devs.developer { dev ->
- dev.name.set("The Android Open Source Project")
- }
- }
-}
-
-private fun Project.tweakDependenciesMetadata(extension: AndroidXExtension, pom: MavenPom) {
- pom.withXml { xml ->
- // The following code depends on getProjectsMap which is only available late in
- // configuration at which point Java Library plugin's variants are not allowed to be
- // modified. TODO remove the use of getProjectsMap and move to earlier configuration.
- // For more context see:
- // https://android-review.googlesource.com/c/platform/frameworks/support/+/1144664/8/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt#177
- assignSingleVersionDependenciesInGroupForPom(xml, extension)
- assignAarTypes(xml)
- }
-}
-
-// TODO(aurimas): remove this when Gradle bug is fixed.
-// https://github.com/gradle/gradle/issues/3170
-private fun Project.assignAarTypes(xml: XmlProvider) {
- val androidxDependencies = HashSet<Dependency>()
- collectDependenciesForConfiguration(androidxDependencies, "api")
- collectDependenciesForConfiguration(androidxDependencies, "implementation")
- collectDependenciesForConfiguration(androidxDependencies, "compile")
-
- val dependencies = xml.asNode().children().find {
- it is Node && it.name().toString().endsWith("dependencies")
- } as Node?
-
- dependencies?.children()?.forEach { dep ->
- if (dep !is Node) {
- return@forEach
- }
- val groupId = dep.children().first {
- it is Node && it.name().toString().endsWith("groupId")
- } as Node
- val artifactId = dep.children().first {
- it is Node && it.name().toString().endsWith("artifactId")
- } as Node
- if (isAndroidProject(
- groupId.children()[0] as String,
- artifactId.children()[0] as String, androidxDependencies
- )
- ) {
- dep.appendNode("type", "aar")
- }
- }
-}
-
-/**
- * Modifies the given .pom to specify that every dependency in <group> refers to a single version
- * and can't be automatically promoted to a new version.
- * This will replace, for example, a version string of "1.0" with a version string of "[1.0]"
- *
- * Note: this is not enforced in Gradle nor in plain Maven (without the Enforcer plugin)
- * (https://github.com/gradle/gradle/issues/8297)
- */
-private fun assignSingleVersionDependenciesInGroupForPom(
- xml: XmlProvider,
- extension: AndroidXExtension
-) {
- val group = extension.mavenGroup
- if (group == null || !group.requireSameVersion) {
- return
- }
-
- val dependencies = xml.asNode().children().find {
- it is Node && it.name().toString().endsWith("dependencies")
- } as Node?
- dependencies?.children()?.forEach { dep ->
- if (dep !is Node) {
- return@forEach
- }
- val groupId = dep.children().first {
- it is Node && it.name().toString().endsWith("groupId")
- } as Node
- if (groupId.children()[0].toString() == group.group) {
- val versionNode = dep.children().first {
- it is Node && it.name().toString().endsWith("version")
- } as Node
- val declaredVersion = versionNode.children()[0].toString()
- if (isVersionRange(declaredVersion)) {
- throw GradleException(
- "Unsupported version '$declaredVersion': " +
- "already is a version range"
- )
- }
- val pinnedVersion = "[$declaredVersion]"
- versionNode.setValue(pinnedVersion)
- }
- }
-}
-
-private fun isVersionRange(text: String): Boolean {
- return text.contains("[") ||
- text.contains("]") ||
- text.contains("(") ||
- text.contains(")") ||
- text.contains(",")
-}
-
-private fun Project.collectDependenciesForConfiguration(
- androidxDependencies: MutableSet<Dependency>,
- name: String
-) {
- val config = configurations.findByName(name)
- config?.dependencies?.forEach { dep ->
- if (dep.group?.startsWith("androidx.") == true) {
- androidxDependencies.add(dep)
- }
- }
-}
-
-private fun Project.isAndroidProject(
- groupId: String,
- artifactId: String,
- deps: Set<Dependency>
-): Boolean {
- for (dep in deps) {
- if (dep is ProjectDependency) {
- if (dep.group == groupId && dep.name == artifactId) {
- return dep.dependencyProject.plugins.hasPlugin(LibraryPlugin::class.java)
- }
- }
- }
- val projectModules = project.getProjectsMap()
- projectModules["$groupId:$artifactId"]?.let { module ->
- return project.findProject(module)?.plugins?.hasPlugin(LibraryPlugin::class.java) ?: false
- }
- return false
-}
-
-private fun Project.appliesJavaGradlePluginPlugin() = pluginManager.hasPlugin("java-gradle-plugin")
-
-private const val ANDROID_GIT_URL =
- "scm:git:https://android.googlesource.com/platform/frameworks/support"
diff --git a/buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt b/buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
deleted file mode 100644
index 95df021..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 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.build
-
-import org.gradle.api.GradleException
-import org.gradle.api.Project
-import org.gradle.api.plugins.ExtraPropertiesExtension
-import java.io.File
-
-object SupportConfig {
- const val DEFAULT_MIN_SDK_VERSION = 14
- const val INSTRUMENTATION_RUNNER = "androidx.test.runner.AndroidJUnitRunner"
- const val BUILD_TOOLS_VERSION = "30.0.3"
- val NDK_VERSION by lazy {
- // TODO(aurimas) b/173737578 remove when we no longer have divergent versions
- when (getOperatingSystem()) {
- OperatingSystem.LINUX -> "21.0.6113669"
- else -> "21.3.6528147"
- }
- }
-
- /**
- * The Android SDK version to use for compilation.
- * <p>
- * Either an integer value or a pre-release platform code, prefixed with "android-" (ex.
- * "android-28" or "android-Q") as you would see within the SDK's platforms directory.
- */
- const val COMPILE_SDK_VERSION = "android-30"
-
- /**
- * The Android SDK version to use for targetSdkVersion meta-data.
- * <p>
- * Either an integer value (ex. 28), a pre-release platform code (ex. "Q") as you would see
- * within the SDK's platforms directory as android-<version>, or a released platform version
- * code as you would see within Build.VERSIONS.VERSION_CODE (ex. "HONEYCOMB" or "P").
- * <p>
- * <strong>Note:</strong> This must be set to an integer value or released platform version in
- * order for tests to run on devices running released versions of the Android OS. If this is
- * set to a pre-release version, tests will only be able to run on pre-release devices.
- */
- const val TARGET_SDK_VERSION = 30
-}
-
-fun Project.getExternalProjectPath(): File {
- val path = if (System.getenv("COMPOSE_DESKTOP_GITHUB_BUILD") != null)
- File(System.getenv("OUT_DIR")).also {
- if (!File(it, "doclava").isDirectory()) {
- throw GradleException("Please checkout doclava to $it")
- }
- }
- else
- File(rootProject.projectDir, "../../external")
- return path.getCanonicalFile()
-}
-
-fun Project.getKeystore(): File {
- return File(project.getSupportRootFolder(), "development/keystore/debug.keystore")
-}
-
-fun Project.getPrebuiltsRoot(): File {
- val ext = project.rootProject.property("ext") as ExtraPropertiesExtension
- val reposProperties = ext.get("repos") as Map<*, *>
- return File(reposProperties["prebuiltsRoot"].toString())
-}
diff --git a/buildSrc/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt
deleted file mode 100644
index ede9cd3..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build.docs
-
-import androidx.build.SupportConfig
-import androidx.build.dackka.DackkaTask
-import androidx.build.dependencies.KOTLIN_VERSION
-import androidx.build.doclava.DacOptions
-import androidx.build.doclava.DoclavaTask
-import androidx.build.doclava.GENERATE_DOCS_CONFIG
-import androidx.build.doclava.androidJarFile
-import androidx.build.doclava.createGenerateSdkApiTask
-import androidx.build.dokka.Dokka
-import androidx.build.getBuildId
-import androidx.build.getCheckoutRoot
-import androidx.build.getDistributionDirectory
-import androidx.build.getKeystore
-import com.android.build.api.attributes.BuildTypeAttr
-import com.android.build.gradle.LibraryExtension
-import com.android.build.gradle.LibraryPlugin
-import org.gradle.api.DefaultTask
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.Task
-import org.gradle.api.artifacts.ComponentMetadataContext
-import org.gradle.api.artifacts.ComponentMetadataRule
-import org.gradle.api.artifacts.Configuration
-import org.gradle.api.attributes.Attribute
-import org.gradle.api.attributes.Category
-import org.gradle.api.attributes.DocsType
-import org.gradle.api.attributes.Usage
-import org.gradle.api.file.FileCollection
-import org.gradle.api.model.ObjectFactory
-import org.gradle.api.plugins.JavaBasePlugin
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.Internal
-import org.gradle.api.tasks.Sync
-import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.TaskProvider
-import org.gradle.api.tasks.bundling.Zip
-import org.gradle.api.tasks.testing.Test
-import org.gradle.kotlin.dsl.all
-import org.gradle.kotlin.dsl.getByType
-import org.gradle.kotlin.dsl.named
-import org.gradle.kotlin.dsl.register
-import org.jetbrains.dokka.gradle.DokkaAndroidTask
-import org.jetbrains.dokka.gradle.PackageOptions
-import java.io.File
-import java.io.FileNotFoundException
-import javax.inject.Inject
-
-/**
- * Plugin that allows to build documentation for a given set of prebuilt and tip of tree projects.
- */
-class AndroidXDocsPlugin : Plugin<Project> {
- lateinit var project: Project
- lateinit var docsType: String
- lateinit var docsSourcesConfiguration: Configuration
- lateinit var samplesSourcesConfiguration: Configuration
- lateinit var dependencyClasspath: FileCollection
-
- override fun apply(project: Project) {
- this.project = project
- docsType = project.name.removePrefix("docs-")
- project.plugins.all { plugin ->
- when (plugin) {
- is LibraryPlugin -> {
- val libraryExtension = project.extensions.getByType<LibraryExtension>()
- libraryExtension.compileSdkVersion = SupportConfig.COMPILE_SDK_VERSION
- libraryExtension.buildToolsVersion = SupportConfig.BUILD_TOOLS_VERSION
-
- // Use a local debug keystore to avoid build server issues.
- val debugSigningConfig = libraryExtension.signingConfigs.getByName("debug")
- debugSigningConfig.storeFile = project.getKeystore()
- libraryExtension.buildTypes.all { buildType ->
- // Sign all the builds (including release) with debug key
- buildType.signingConfig = debugSigningConfig
- }
- }
- }
- }
- disableUnneededTasks()
- createConfigurations()
- val buildOnServer = project.tasks.register<DocsBuildOnServer>("buildOnServer") {
- buildId = getBuildId()
- docsType = this@AndroidXDocsPlugin.docsType
- distributionDirectory = project.getDistributionDirectory()
- }
-
- val unzippedSamplesSources = File(project.buildDir, "unzippedSampleSources")
- val unzipSamplesTask = configureUnzipTask(
- "unzipSampleSources",
- unzippedSamplesSources,
- samplesSourcesConfiguration
- )
- val unzippedDocsSources = File(project.buildDir, "unzippedDocsSources")
- val unzipDocsTask = configureUnzipTask(
- "unzipDocsSources",
- unzippedDocsSources,
- docsSourcesConfiguration
- )
-
- configureDackka(
- unzippedDocsSources,
- unzipDocsTask,
- unzippedSamplesSources,
- unzipSamplesTask,
- dependencyClasspath,
- buildOnServer
- )
- configureDokka(
- unzippedDocsSources,
- unzipDocsTask,
- unzippedSamplesSources,
- unzipSamplesTask,
- dependencyClasspath,
- buildOnServer
- )
- configureDoclava(
- unzippedDocsSources,
- unzipDocsTask,
- dependencyClasspath,
- buildOnServer
- )
- }
-
- /**
- * Creates and configures a task that will build a list of all sources for projects in
- * [docsConfiguration] configuration, resolve them and put them to [destinationDirectory].
- */
- private fun configureUnzipTask(
- taskName: String,
- destinationDirectory: File,
- docsConfiguration: Configuration
- ): TaskProvider<Sync> {
- @Suppress("UnstableApiUsage")
- return project.tasks.register(
- taskName,
- Sync::class.java
- ) { task ->
- val sources = docsConfiguration.incoming.artifactView { }.files
- task.from(
- sources.elements.map { jars ->
- jars.map {
- project.zipTree(it).matching {
- // Filter out files that documentation tools cannot process.
- it.exclude("**/*.MF")
- it.exclude("**/*.aidl")
- it.exclude("**/META-INF/**")
- it.exclude("**/OWNERS")
- it.exclude("**/package.html")
- it.exclude("**/*.md")
- }
- }
- }
- )
- task.into(destinationDirectory)
- // TODO(123020809) remove this filter once it is no longer necessary to prevent Dokka
- // from failing
- val regex = Regex("@attr ref ([^*]*)styleable#([^_*]*)_([^*]*)$")
- task.filter { line ->
- regex.replace(line, "{@link $1attr#$3}")
- }
- }
- }
-
- /**
- * The following configurations are created to build a list of projects that need to be
- * documented and should be used from build.gradle of docs projects for the following:
- * - docs(project(":foo:foo") or docs("androidx.foo:foo:1.0.0") for docs sources
- * - samples(project(":foo:foo-samples") or samples("androidx.foo:foo-samples:1.0.0") for
- * samples sources
- * - stubs(project(":foo:foo-stubs")) - stubs needed for a documented library
- */
- private fun createConfigurations() {
- project.dependencies.components.all<SourcesVariantRule>()
- val docsConfiguration = project.configurations.create("docs") {
- it.isCanBeResolved = false
- it.isCanBeConsumed = false
- }
- val samplesConfiguration = project.configurations.create("samples") {
- it.isCanBeResolved = false
- it.isCanBeConsumed = false
- }
- val stubsConfiguration = project.configurations.create("stubs") {
- it.isCanBeResolved = false
- it.isCanBeConsumed = false
- }
-
- fun Configuration.setResolveSources() {
- isTransitive = false
- isCanBeConsumed = false
- attributes {
- it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
- it.attribute(
- Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION)
- )
- it.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.SOURCES))
- }
- }
- docsSourcesConfiguration = project.configurations.create("docs-sources") {
- it.setResolveSources()
- it.extendsFrom(docsConfiguration)
- }
- samplesSourcesConfiguration = project.configurations.create("samples-sources") {
- it.setResolveSources()
- it.extendsFrom(samplesConfiguration)
- }
-
- fun Configuration.setResolveClasspathForUsage(usage: String) {
- isCanBeConsumed = false
- attributes {
- it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(usage))
- it.attribute(
- Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)
- )
- it.attribute(BuildTypeAttr.ATTRIBUTE, project.objects.named("release"))
- }
- extendsFrom(docsConfiguration, samplesConfiguration, stubsConfiguration)
- }
-
- // Build a compile & runtime classpaths for needed for documenting the libraries
- // from the configurations above.
- val docsCompileClasspath = project.configurations.create("docs-compile-classpath") {
- it.setResolveClasspathForUsage(Usage.JAVA_API)
- }
- val docsRuntimeClasspath = project.configurations.create("docs-runtime-classpath") {
- it.setResolveClasspathForUsage(Usage.JAVA_RUNTIME)
- }
- listOf(docsCompileClasspath, docsRuntimeClasspath).forEach { config ->
- config.resolutionStrategy {
- it.eachDependency { details ->
- if (details.requested.group == "org.jetbrains.kotlin") {
- details.useVersion(KOTLIN_VERSION)
- }
- }
- }
- }
- dependencyClasspath = docsCompileClasspath.incoming.artifactView {
- it.attributes.attribute(
- Attribute.of("artifactType", String::class.java),
- "android-classes"
- )
- }.files + docsRuntimeClasspath.incoming.artifactView {
- it.attributes.attribute(
- Attribute.of("artifactType", String::class.java),
- "android-classes"
- )
- }.files
- }
-
- private fun configureDackka(
- unzippedDocsSources: File,
- unzipDocsTask: TaskProvider<Sync>,
- unzippedSamplesSources: File,
- unzipSamplesTask: TaskProvider<Sync>,
- dependencyClasspath: FileCollection,
- buildOnServer: TaskProvider<*>
- ) {
- val generatedDocsDir = project.file("${project.buildDir}/dackkaDocs")
-
- val dackkaConfiguration = project.configurations.create("dackka").apply {
- dependencies.add(project.dependencies.create(DACKKA_DEPENDENCY))
- }
-
- val dackkaTask = project.tasks.register("dackkaDocs", DackkaTask::class.java) { task ->
- task.apply {
- dependsOn(dackkaConfiguration)
- dependsOn(unzipDocsTask)
- dependsOn(unzipSamplesTask)
-
- description = "Generates reference documentation using a Google devsite Dokka" +
- " plugin. Places docs in $generatedDocsDir"
- group = JavaBasePlugin.DOCUMENTATION_GROUP
-
- dackkaClasspath.from(project.files(dackkaConfiguration))
- destinationDir = generatedDocsDir
- frameworkSamplesDir = File(project.rootDir, "samples")
- samplesDir = unzippedSamplesSources
- sourcesDir = unzippedDocsSources
- docsProjectDir = File(project.rootDir, "docs-public")
- dependenciesClasspath = androidJarFile(project) + dependencyClasspath
- excludedPackages = hiddenPackages.toSet()
- excludedPackagesForJava = hiddenPackagesJava
- excludedPackagesForKotlin = emptySet()
- }
- }
-
- val zipTask = project.tasks.register("zipDackkaDocs", Zip::class.java) { task ->
- task.apply {
- dependsOn(dackkaTask)
- from(generatedDocsDir)
-
- val baseName = "dackka-$docsType-docs"
- val buildId = getBuildId()
- archiveBaseName.set(baseName)
- archiveVersion.set(buildId)
- destinationDirectory.set(project.getDistributionDirectory())
- group = JavaBasePlugin.DOCUMENTATION_GROUP
-
- val filePath = "${project.getDistributionDirectory().canonicalPath}/"
- val fileName = "$baseName-$buildId.zip"
- val destinationFile = filePath + fileName
- description = "Zips Java and Kotlin documentation (generated via Dackka in the" +
- " style of d.android.com) into $destinationFile"
- }
- }
- buildOnServer.configure { it.dependsOn(zipTask) }
- }
-
- private fun configureDokka(
- unzippedDocsSources: File,
- unzipDocsTask: TaskProvider<Sync>,
- unzippedSamplesSources: File,
- unzipSamplesTask: TaskProvider<Sync>,
- dependencyClasspath: FileCollection,
- buildOnServer: TaskProvider<*>
- ) {
- val dokkaTask = Dokka.createDokkaTask(
- project,
- hiddenPackages,
- "Kotlin",
- "dac",
- "/reference/kotlin"
- )
- dokkaTask.configure { task ->
- task.sourceDirs += unzippedDocsSources
- task.sourceDirs += unzippedSamplesSources
- task.dependsOn(unzipDocsTask)
- task.dependsOn(unzipSamplesTask)
-
- val androidJar = androidJarFile(project)
- // DokkaTask tries to resolve DokkaTask#classpath right away for jars that might not
- // be there yet. Delay the setting of this property to before we run the task.
- task.inputs.files(androidJar, dependencyClasspath)
- task.doFirst { dokkaTask ->
- dokkaTask as DokkaAndroidTask
- val packages =
- unzippedSamplesSources.walkTopDown().filter { it.isFile }.mapNotNull { file ->
- val lines = file.readLines()
- lines.find { line ->
- line.startsWith("package ")
- }?.replace("package ", "")
- }.distinct()
-
- packages.forEach { packageName ->
- val opts = PackageOptions()
- opts.prefix = packageName
- opts.suppress = true
- dokkaTask.perPackageOptions.add(opts)
- }
-
- dokkaTask.classpath = project.files(dokkaTask.classpath)
- .plus(project.files(androidJar))
- .plus(dependencyClasspath)
- }
- }
- val zipTask = project.tasks.register("zipDokkaDocs", Zip::class.java) {
- it.apply {
- it.dependsOn(dokkaTask)
- from(dokkaTask.map { it.outputDirectory }) { copySpec ->
- copySpec.into("reference/kotlin")
- }
- val baseName = "dokka-$docsType-docs"
- val buildId = getBuildId()
- archiveBaseName.set(baseName)
- archiveVersion.set(buildId)
- destinationDirectory.set(project.getDistributionDirectory())
- group = JavaBasePlugin.DOCUMENTATION_GROUP
- val filePath = "${project.getDistributionDirectory().canonicalPath}/"
- val fileName = "$baseName-$buildId.zip"
- val destinationFile = filePath + fileName
- description = "Zips Kotlin documentation (generated via Dokka in the " +
- "style of d.android.com) into $destinationFile"
- }
- }
- buildOnServer.configure { it.dependsOn(zipTask) }
- }
-
- private fun configureDoclava(
- unzippedDocsSources: File,
- unzipDocsTask: TaskProvider<Sync>,
- dependencyClasspath: FileCollection,
- buildOnServer: TaskProvider<*>
- ) {
- // Hack to force tools.jar (required by com.sun.javadoc) to be available on the Doclava
- // run-time classpath. Note this breaks the ability to use JDK 9+ for compilation.
- val doclavaConfiguration = project.configurations.create("doclava")
- doclavaConfiguration.dependencies.add(project.dependencies.create(DOCLAVA_DEPENDENCY))
- doclavaConfiguration.dependencies.add(
- project.dependencies.create(
- project.files(System.getenv("JAVA_TOOLS_JAR"))
- )
- )
-
- val annotationConfiguration = project.configurations.create("annotation")
- annotationConfiguration.dependencies.add(
- project.dependencies.project(
- mapOf("path" to ":fakeannotations")
- )
- )
-
- val generatedSdk = File(project.buildDir, "generatedsdk")
- val generateSdkApiTask = createGenerateSdkApiTask(
- project, doclavaConfiguration, annotationConfiguration, generatedSdk
- )
-
- val destDir = File(project.buildDir, "javadoc")
- val offlineOverride = project.findProject("offlineDocs") as String?
- val offline = if (offlineOverride != null) { offlineOverride == "true" } else false
- val dacOptions = DacOptions("androidx", "ANDROIDX_DATA")
-
- val doclavaTask = project.tasks.register("doclavaDocs", DoclavaTask::class.java) {
- it.apply {
- dependsOn(unzipDocsTask)
- dependsOn(generateSdkApiTask)
- group = JavaBasePlugin.DOCUMENTATION_GROUP
- description = "Generates Java documentation in the style of d.android.com. To " +
- "generate offline docs use \'-PofflineDocs=true\' parameter. Places the " +
- "documentation in $destDir"
- dependsOn(doclavaConfiguration)
- setDocletpath(doclavaConfiguration)
- destinationDir = destDir
- classpath = androidJarFile(project) + dependencyClasspath
- checksConfig = GENERATE_DOCS_CONFIG
- extraArgumentsBuilder.apply {
- addStringOption(
- "templatedir",
- "${project.getCheckoutRoot()}/external/doclava/res/assets/templates-sdk"
- )
- // Note, this is pointing to the root checkout directory.
- addStringOption(
- "samplesdir",
- "${project.rootDir}/samples"
- )
- addStringOption(
- "federate",
- listOf("Android", "https://developer.android.com")
- )
- addStringOption(
- "federationapi",
- listOf(
- "Android",
- generateSdkApiTask.get().apiFile?.absolutePath.toString()
- )
- )
- addStringOption("hdf", listOf("android.whichdoc", "online"))
- addStringOption("hdf", listOf("android.hasSamples", "true"))
- addStringOption("hdf", listOf("dac", "true"))
-
- // Specific to reference docs.
- if (!offline) {
- addStringOption("toroot", "/")
- addOption("devsite")
- addOption("yamlV2")
- addStringOption("dac_libraryroot", dacOptions.libraryroot)
- addStringOption("dac_dataname", dacOptions.dataname)
- }
- }
- it.source(project.fileTree(unzippedDocsSources))
- }
- }
- val zipTask = project.tasks.register("zipDoclavaDocs", Zip::class.java) {
- it.apply {
- it.dependsOn(doclavaTask)
- from(doclavaTask.map { it.destinationDir!! })
- val baseName = "doclava-$docsType-docs"
- val buildId = getBuildId()
- archiveBaseName.set(baseName)
- archiveVersion.set(buildId)
- destinationDirectory.set(project.getDistributionDirectory())
- group = JavaBasePlugin.DOCUMENTATION_GROUP
- val filePath = "${project.getDistributionDirectory().canonicalPath}/"
- val fileName = "$baseName-$buildId.zip"
- val destinationFile = filePath + fileName
- description = "Zips Java documentation (generated via Doclava in the " +
- "style of d.android.com) into $destinationFile"
- }
- }
- buildOnServer.configure { it.dependsOn(zipTask) }
- }
-
- /**
- * Replace all tests etc with empty task, so we don't run anything
- * it is more effective then task.enabled = false, because we avoid executing deps as well
- */
- private fun disableUnneededTasks() {
- var reentrance = false
- project.tasks.whenTaskAdded { task ->
- if (task is Test || task.name.startsWith("assemble") ||
- task.name == "lint" ||
- task.name == "transformDexArchiveWithExternalLibsDexMergerForPublicDebug" ||
- task.name == "transformResourcesWithMergeJavaResForPublicDebug" ||
- task.name == "checkPublicDebugDuplicateClasses"
- ) {
- if (!reentrance) {
- reentrance = true
- project.tasks.named(task.name) {
- it.actions = emptyList()
- it.dependsOn(emptyList<Task>())
- }
- reentrance = false
- }
- }
- }
- }
-}
-
-open class DocsBuildOnServer : DefaultTask() {
- @Internal
- lateinit var docsType: String
- @Internal
- lateinit var buildId: String
- @Internal
- lateinit var distributionDirectory: File
-
- @InputFiles
- fun getRequiredFiles(): List<File> {
- return listOf(
- File(distributionDirectory, "dackka-$docsType-docs-$buildId.zip"),
- File(distributionDirectory, "doclava-$docsType-docs-$buildId.zip"),
- File(distributionDirectory, "dokka-$docsType-docs-$buildId.zip")
- )
- }
-
- @TaskAction
- fun checkAllBuildOutputs() {
- val missingFiles = mutableListOf<String>()
- getRequiredFiles().forEach { file ->
- if (!file.exists()) {
- missingFiles.add(file.path)
- }
- }
-
- if (missingFiles.isNotEmpty()) {
- val missingFileString = missingFiles.reduce { acc, s -> "$acc, $s" }
- throw FileNotFoundException("buildOnServer required output missing: $missingFileString")
- }
- }
-}
-
-/**
- * Adapter rule to handles prebuilt dependencies that do not use Gradle Metadata (only pom).
- * We create a new variant sources that we can later use in the same way we do for tip of tree
- * projects and prebuilts with Gradle Metadata.
- */
-abstract class SourcesVariantRule : ComponentMetadataRule {
- @get:Inject
- abstract val objects: ObjectFactory
- override fun execute(context: ComponentMetadataContext) {
- context.details.maybeAddVariant("sources", "runtime") {
- it.attributes {
- it.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
- it.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
- it.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
- }
- it.withFiles {
- it.removeAllFiles()
- it.addFile("${context.details.id.name}-${context.details.id.version}-sources.jar")
- }
- }
- }
-}
-
-private const val DACKKA_DEPENDENCY = "com.google.devsite:dackka:0.0.9"
-private const val DOCLAVA_DEPENDENCY = "com.android:doclava:1.0.6"
-
-// List of packages to exclude from both Java and Kotlin refdoc generation
-private val hiddenPackages = listOf(
- "androidx.camera.camera2.impl",
- "androidx.camera.camera2.internal",
- "androidx.camera.camera2.internal.compat",
- "androidx.camera.camera2.internal.compat.params",
- "androidx.camera.core.impl",
- "androidx.camera.core.impl.annotation",
- "androidx.camera.core.impl.utils",
- "androidx.camera.core.impl.utils.executor",
- "androidx.camera.core.impl.utils.futures",
- "androidx.camera.core.internal",
- "androidx.camera.core.internal.utils",
- "androidx.core.internal",
- "androidx.preference.internal",
- "androidx.wear.internal.widget.drawer",
- "androidx.webkit.internal",
- "androidx.work.impl",
- "androidx.work.impl.background",
- "androidx.work.impl.background.gcm",
- "androidx.work.impl.background.systemalarm",
- "androidx.work.impl.background.systemjob",
- "androidx.work.impl.constraints",
- "androidx.work.impl.constraints.controllers",
- "androidx.work.impl.constraints.trackers",
- "androidx.work.impl.model",
- "androidx.work.impl.utils",
- "androidx.work.impl.utils.futures",
- "androidx.work.impl.utils.taskexecutor"
-)
-
-// Set of packages to exclude from Java refdoc generation
-private val hiddenPackagesJava = setOf(
- "androidx.compose.animation",
- "androidx.compose.animation.core",
- "androidx.compose.foundation",
- "androidx.compose.foundation.gestures",
- "androidx.compose.foundation.interaction",
- "androidx.compose.foundation.layout",
- "androidx.compose.foundation.lazy",
- "androidx.compose.foundation.selection",
- "androidx.compose.foundation.shape",
- "androidx.compose.foundation.text",
- "androidx.compose.foundation.text.selection",
- "androidx.compose.material",
- "androidx.compose.material.icons",
- "androidx.compose.material.icons.filled",
- "androidx.compose.material.icons.outlined",
- "androidx.compose.material.icons.rounded",
- "androidx.compose.material.icons.sharp",
- "androidx.compose.material.icons.twotone",
- "androidx.compose.material.ripple",
- "androidx.compose.runtime",
- "androidx.compose.runtime.collection",
- "androidx.compose.runtime.internal",
- "androidx.compose.runtime.livedata",
- "androidx.compose.runtime.rxjava2",
- "androidx.compose.runtime.rxjava3",
- "androidx.compose.runtime.saveable",
- "androidx.compose.runtime.snapshots",
- "androidx.compose.runtime.tooling",
- "androidx.compose.ui",
- "androidx.compose.ui.autofill",
- "androidx.compose.ui.draw",
- "androidx.compose.ui.focus",
- "androidx.compose.ui.geometry",
- "androidx.compose.ui.graphics",
- "androidx.compose.ui.graphics.colorspace",
- "androidx.compose.ui.graphics.drawscope",
- "androidx.compose.ui.graphics.painter",
- "androidx.compose.ui.graphics.vector",
- "androidx.compose.ui.hapticfeedback",
- "androidx.compose.ui.input.key",
- "androidx.compose.ui.input.nestedscroll",
- "androidx.compose.ui.input.pointer",
- "androidx.compose.ui.input.pointer.util",
- "androidx.compose.ui.layout",
- "androidx.compose.ui.node",
- "androidx.compose.ui.platform",
- "androidx.compose.ui.res",
- "androidx.compose.ui.semantics",
- "androidx.compose.ui.state",
- "androidx.compose.ui.test",
- "androidx.compose.ui.test.junit4",
- "androidx.compose.ui.test.junit4.android",
- "androidx.compose.ui.text",
- "androidx.compose.ui.text.android",
- "androidx.compose.ui.text.font",
- "androidx.compose.ui.text.input",
- "androidx.compose.ui.text.intl",
- "androidx.compose.ui.text.platform.extensions",
- "androidx.compose.ui.text.style",
- "androidx.compose.ui.tooling",
- "androidx.compose.ui.tooling.data",
- "androidx.compose.ui.tooling.preview",
- "androidx.compose.ui.tooling.preview.datasource",
- "androidx.compose.ui.unit",
- "androidx.compose.ui.util",
- "androidx.compose.ui.viewinterop",
- "androidx.compose.ui.window",
-)
diff --git a/buildSrc/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt b/buildSrc/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt
deleted file mode 100644
index 9fa99e3..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build.metalava
-
-import androidx.build.checkapi.ApiBaselinesLocation
-import androidx.build.checkapi.ApiLocation
-import org.gradle.api.file.FileCollection
-import org.gradle.api.provider.Property
-import org.gradle.api.tasks.Input
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.OutputFile
-import org.gradle.api.tasks.OutputFiles
-import org.gradle.api.tasks.TaskAction
-import org.gradle.workers.WorkerExecutor
-import java.io.File
-import javax.inject.Inject
-
-abstract class UpdateApiLintBaselineTask @Inject constructor(
- workerExecutor: WorkerExecutor
-) : MetalavaTask(workerExecutor) {
- init {
- group = "API"
- description = "Updates an API lint baseline file (api/api_lint.ignore) to match the " +
- "current set of violations. Only use a baseline " +
- "if you are in a library without Android dependencies, or when enabling a new " +
- "lint check, and it is prohibitively expensive / not possible to fix the errors " +
- "generated by enabling this lint check. "
- }
-
- @get:Input
- abstract val baselines: Property<ApiBaselinesLocation>
-
- @get:Input
- abstract val targetsJavaConsumers: Property<Boolean>
-
- @OutputFile
- fun getApiLintBaseline(): File = baselines.get().apiLintFile
-
- @TaskAction
- fun updateBaseline() {
- check(bootClasspath.files.isNotEmpty()) { "Android boot classpath not set." }
- val baselineFile = baselines.get().apiLintFile
- val checkArgs = getGenerateApiArgs(
- bootClasspath, dependencyClasspath,
- sourcePaths.files.filter { it.exists() }, null, GenerateApiMode.PublicApi,
- ApiLintMode.CheckBaseline(baselineFile, targetsJavaConsumers.get()),
- manifestPath.orNull?.asFile?.absolutePath
- )
- val args = checkArgs + getCommonBaselineUpdateArgs(baselineFile)
-
- runWithArgs(args)
- }
-}
-
-abstract class IgnoreApiChangesTask @Inject constructor(
- workerExecutor: WorkerExecutor
-) : MetalavaTask(workerExecutor) {
- init {
- description = "Updates an API tracking baseline file (api/X.Y.Z.ignore) to match the " +
- "current set of violations"
- }
-
- // The API that the library is supposed to be compatible with
- @get:Input
- abstract val referenceApi: Property<ApiLocation>
-
- @get:Input
- abstract val api: Property<ApiLocation>
-
- // The baseline files (api/*.*.*.ignore) to update
- @get:Input
- abstract val baselines: Property<ApiBaselinesLocation>
-
- @InputFiles
- fun getTaskInputs(): List<File> {
- val referenceApiLocation = referenceApi.get()
- return listOf(
- referenceApiLocation.publicApiFile,
- referenceApiLocation.restrictedApiFile
- )
- }
-
- // Declaring outputs prevents Gradle from rerunning this task if the inputs haven't changed
- @OutputFiles
- fun getTaskOutputs(): List<File>? {
- val apiBaselinesLocation = baselines.get()
- return listOf(
- apiBaselinesLocation.publicApiFile,
- apiBaselinesLocation.restrictedApiFile
- )
- }
-
- @TaskAction
- fun exec() {
- check(bootClasspath.files.isNotEmpty()) { "Android boot classpath not set." }
-
- updateBaseline(
- api.get().publicApiFile,
- referenceApi.get().publicApiFile,
- baselines.get().publicApiFile,
- false
- )
- if (referenceApi.get().restrictedApiFile.exists()) {
- updateBaseline(
- api.get().restrictedApiFile,
- referenceApi.get().restrictedApiFile,
- baselines.get().restrictedApiFile,
- true
- )
- }
- }
-
- // Updates the contents of baselineFile to specify an exception for every API present in apiFile but not
- // present in the current source path
- private fun updateBaseline(
- api: File,
- prevApi: File,
- baselineFile: File,
- processRestrictedApis: Boolean
- ) {
- val args = getCommonBaselineUpdateArgs(
- bootClasspath,
- dependencyClasspath,
- baselineFile
- )
- args += listOf(
- "--baseline",
- baselineFile.toString(),
- "--check-compatibility:api:released",
- prevApi.toString(),
- "--source-files",
- api.toString()
- )
- if (processRestrictedApis) {
- args += listOf(
- "--show-annotation",
- "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope." +
- "LIBRARY_GROUP)",
- "--show-annotation",
- "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope." +
- "LIBRARY_GROUP_PREFIX)",
- "--show-unannotated"
- )
- }
- runWithArgs(args)
- }
-}
-
-private fun getCommonBaselineUpdateArgs(
- bootClasspath: FileCollection,
- dependencyClasspath: FileCollection,
- baselineFile: File
-): MutableList<String> {
- val args = mutableListOf(
- "--classpath",
- (bootClasspath.files + dependencyClasspath.files).joinToString(File.pathSeparator)
- )
- args += getCommonBaselineUpdateArgs(baselineFile)
- return args
-}
-
-private fun getCommonBaselineUpdateArgs(baselineFile: File): List<String> {
- // Create the baseline file if it does exist, as Metalava cannot handle non-existent files.
- baselineFile.createNewFile()
- return mutableListOf(
- "--update-baseline",
- baselineFile.toString(),
- "--pass-baseline-updates",
- "--delete-empty-baselines",
- "--format=v3",
- "--omit-common-packages=yes"
- )
-}
diff --git a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt b/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
deleted file mode 100644
index 2a1047c..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build.testConfiguration
-
-import androidx.build.dependencyTracker.ProjectSubset
-import androidx.build.isPresubmitBuild
-import androidx.build.renameApkForTesting
-import com.android.build.api.variant.BuiltArtifactsLoader
-import org.gradle.api.DefaultTask
-import org.gradle.api.file.DirectoryProperty
-import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.provider.Property
-import org.gradle.api.tasks.Input
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.Internal
-import org.gradle.api.tasks.Optional
-import org.gradle.api.tasks.OutputFile
-import org.gradle.api.tasks.TaskAction
-import java.io.File
-
-/**
- * Writes a configuration file in
- * <a href=https://source.android.com/devices/tech/test_infra/tradefed/testing/through-suite/android-test-structure>AndroidTest.xml</a>
- * format that gets zipped alongside the APKs to be tested.
- * This config gets ingested by Tradefed.
- */
-abstract class GenerateTestConfigurationTask : DefaultTask() {
-
- @get:InputFiles
- @get:Optional
- abstract val appFolder: DirectoryProperty
-
- @get:Internal
- abstract val appLoader: Property<BuiltArtifactsLoader>
-
- @get:Input
- @get:Optional
- abstract val appProjectPath: Property<String>
-
- @get:InputFiles
- abstract val testFolder: DirectoryProperty
-
- @get:Internal
- abstract val testLoader: Property<BuiltArtifactsLoader>
-
- @get:Input
- abstract val testProjectPath: Property<String>
-
- @get:Input
- abstract val minSdk: Property<Int>
-
- @get:Input
- abstract val hasBenchmarkPlugin: Property<Boolean>
-
- @get:Input
- @get:Optional
- abstract val benchmarkRunAlsoInterpreted: Property<Boolean>
-
- @get:Input
- abstract val testRunner: Property<String>
-
- @get:Input
- abstract val affectedModuleDetectorSubset: Property<ProjectSubset>
-
- @get:OutputFile
- abstract val outputXml: RegularFileProperty
-
- @get:OutputFile
- abstract val constrainedOutputXml: RegularFileProperty
-
- @TaskAction
- fun generateAndroidTestZip() {
- writeConfigFileContent(constrainedOutputXml, true)
- writeConfigFileContent(outputXml)
- }
-
- private fun writeConfigFileContent(
- outputFile: RegularFileProperty,
- isConstrained: Boolean = false
- ) {
- /*
- Testing an Android Application project involves 2 APKS: an application to be instrumented,
- and a test APK. Testing an Android Library project involves only 1 APK, since the library
- is bundled inside the test APK, meaning it is self instrumenting. We add extra data to
- configurations testing Android Application projects, so that both APKs get installed.
- */
- val configBuilder = ConfigBuilder()
- if (appLoader.isPresent) {
- val appApk = appLoader.get().load(appFolder.get())
- ?: throw RuntimeException("Cannot load required APK for task: $name")
- // We don't need to check hasBenchmarkPlugin because benchmarks shouldn't have test apps
- val appName = appApk.elements.single().outputFile.substringAfterLast("/")
- .renameApkForTesting(appProjectPath.get(), hasBenchmarkPlugin = false)
- // TODO(b/178776319): Clean up this hardcoded hack
- if (appProjectPath.get().contains("macrobenchmark-target")) {
- configBuilder.appApkName(appName.replace("debug-androidTest", "release"))
- } else {
- configBuilder.appApkName(appName)
- }
- }
- val isPresubmit = isPresubmitBuild()
- configBuilder.isPostsubmit(!isPresubmit)
- when (affectedModuleDetectorSubset.get()) {
- ProjectSubset.DEPENDENT_PROJECTS -> {
- // Don't ever run full tests of RV if it is dependent, since they take > 45 minutes
- if (isConstrained || testProjectPath.get().contains("recyclerview")) {
- configBuilder.runAllTests(false)
- } else {
- configBuilder.runAllTests(true)
- }
- }
- ProjectSubset.NONE -> {
- if (isPresubmit) {
- configBuilder.runAllTests(false)
- } else {
- configBuilder.runAllTests(true)
- }
- }
- // in all other cases, if we are building this config we want to run all the tests
- else -> {
- configBuilder.runAllTests(true)
- }
- }
- // This section adds metadata tags that will help filter runners to specific modules.
- if (hasBenchmarkPlugin.get()) {
- configBuilder.isBenchmark(true)
- if (configBuilder.isPostsubmit) {
- if (benchmarkRunAlsoInterpreted.get()) {
- configBuilder.tag("microbenchmarks_interpreted")
- }
- configBuilder.tag("microbenchmarks")
- } else {
- // in presubmit, we treat micro benchmarks as regular correctness tests as
- // they run with dryRunMode to check crashes don't happen, without measurement
- configBuilder.tag("androidx_unit_tests")
- }
- } else if (testProjectPath.get().endsWith("macrobenchmark")) {
- // macro benchmarks do not have a dryRunMode, so we don't run them in presubmit
- configBuilder.tag("macrobenchmarks")
- } else {
- configBuilder.tag("androidx_unit_tests")
- if (project.path.startsWith(":compose:")) {
- configBuilder.tag("compose")
- } else if (project.path.startsWith(":wear:")) {
- configBuilder.tag("wear")
- }
- }
- val testApk = testLoader.get().load(testFolder.get())
- ?: throw RuntimeException("Cannot load required APK for task: $name")
- val testName = testApk.elements.single().outputFile
- .substringAfterLast("/")
- .renameApkForTesting(testProjectPath.get(), hasBenchmarkPlugin.get())
- configBuilder.testApkName(testName)
- .applicationId(testApk.applicationId)
- .minSdk(minSdk.get().toString())
- .testRunner(testRunner.get())
-
- val resolvedOutputFile: File = outputFile.asFile.get()
- if (!resolvedOutputFile.exists()) {
- if (!resolvedOutputFile.createNewFile()) {
- throw RuntimeException(
- "Failed to create test configuration file: $resolvedOutputFile"
- )
- }
- }
- resolvedOutputFile.writeText(configBuilder.build())
- }
-}
diff --git a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
deleted file mode 100644
index 673eeae..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@file:Suppress("UnstableApiUsage") // Incubating AGP APIs
-
-package androidx.build.testConfiguration
-
-import androidx.build.AndroidXExtension
-import androidx.build.AndroidXPlugin
-import androidx.build.AndroidXPlugin.Companion.ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK
-import androidx.build.AndroidXPlugin.Companion.ZIP_TEST_CONFIGS_WITH_APKS_TASK
-import androidx.build.asFilenamePrefix
-import androidx.build.dependencyTracker.AffectedModuleDetector
-import androidx.build.getConstrainedTestConfigDirectory
-import androidx.build.getSupportRootFolder
-import androidx.build.getTestConfigDirectory
-import androidx.build.hasAndroidTestSourceCode
-import androidx.build.hasBenchmarkPlugin
-import androidx.build.renameApkForTesting
-import com.android.build.api.artifact.Artifacts
-import com.android.build.api.artifact.SingleArtifact
-import com.android.build.api.variant.AndroidComponentsExtension
-import com.android.build.api.variant.ApplicationAndroidComponentsExtension
-import com.android.build.api.variant.HasAndroidTest
-import com.android.build.gradle.BaseExtension
-import com.android.build.gradle.tasks.PackageAndroidArtifact
-import org.gradle.api.Project
-import org.gradle.api.file.DuplicatesStrategy
-import org.gradle.api.tasks.TaskProvider
-import org.gradle.api.tasks.bundling.Zip
-import org.gradle.kotlin.dsl.getByType
-import java.io.File
-
-/**
- * Creates and configures the test config generation task for a project. Configuration includes
- * populating the task with relevant data from the first 4 params, and setting whether the task
- * is enabled.
- *
- * @param overrideProject Allows the config task for one project to get registered to an
- * alternative project. Default is for the project to register the new config task to itself
- */
-fun Project.createTestConfigurationGenerationTask(
- variantName: String,
- artifacts: Artifacts,
- minSdk: Int,
- testRunner: String,
- overrideProject: Project = this
-) {
- val xmlName = "${path.asFilenamePrefix()}$variantName.xml"
- rootProject.tasks.named("createModuleInfo").configure {
- it as ModuleInfoGenerator
- it.testModules.add(
- TestModule(
- name = xmlName,
- path = listOf(projectDir.toRelativeString(getSupportRootFolder()))
- )
- )
- }
- val generateTestConfigurationTask = overrideProject.tasks.register(
- "${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}$variantName",
- GenerateTestConfigurationTask::class.java
- ) { task ->
- task.testFolder.set(artifacts.get(SingleArtifact.APK))
- task.testLoader.set(artifacts.getBuiltArtifactsLoader())
- task.outputXml.fileValue(File(getTestConfigDirectory(), xmlName))
- task.constrainedOutputXml.fileValue(File(getConstrainedTestConfigDirectory(), xmlName))
- // Disable work tests on < API 18: b/178127496
- if (path.startsWith(":work:")) {
- task.minSdk.set(maxOf(18, minSdk))
- } else {
- task.minSdk.set(minSdk)
- }
- val hasBenchmarkPlugin = hasBenchmarkPlugin()
- task.hasBenchmarkPlugin.set(hasBenchmarkPlugin)
- if (hasBenchmarkPlugin) {
- task.benchmarkRunAlsoInterpreted.set(
- extensions.getByType<AndroidXExtension>().benchmarkRunAlsoInterpreted
- )
- }
- task.testRunner.set(testRunner)
- task.testProjectPath.set(path)
- val detector = AffectedModuleDetector.getInstance(project)
- task.affectedModuleDetectorSubset.set(
- project.provider {
- detector.getSubset(task)
- }
- )
- AffectedModuleDetector.configureTaskGuard(task)
- }
- // Disable xml generation for projects that have no test sources
- this.afterEvaluate {
- generateTestConfigurationTask.configure {
- it.enabled = this.hasAndroidTestSourceCode()
- }
- }
- this.rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
- .dependsOn(generateTestConfigurationTask)
- this.rootProject.tasks.findByName(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK)!!
- .dependsOn(generateTestConfigurationTask)
-}
-
-/**
- * Further configures the test config generation task for a project. This only gets called when
- * there is a test app in addition to the instrumentation app, and the only thing it configures is
- * the location of the testapp.
- *
- * @param overrideProject Allows the config task for one project to get registered to an
- * alternative project. Default is for the project to register the new config task to itself
- */
-fun Project.addAppApkToTestConfigGeneration(overrideProject: Project = this) {
- if (project.isMacrobenchmarkTarget()) {
- return
- }
-
- extensions.getByType<ApplicationAndroidComponentsExtension>().apply {
- onVariants(selector().withBuildType("debug")) { appVariant ->
- overrideProject.tasks.named(
- "${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}${appVariant.name}AndroidTest"
- ) { configTask ->
- configTask as GenerateTestConfigurationTask
- configTask.appFolder.set(appVariant.artifacts.get(SingleArtifact.APK))
- configTask.appLoader.set(appVariant.artifacts.getBuiltArtifactsLoader())
- configTask.appProjectPath.set(overrideProject.path)
- }
- }
- }
-}
-
-/**
- * Configures the test zip task to include the project's apk
- */
-fun addToTestZips(project: Project, packageTask: PackageAndroidArtifact) {
- project.rootProject.tasks.named(ZIP_TEST_CONFIGS_WITH_APKS_TASK) { task ->
- task as Zip
- task.from(packageTask.outputDirectory) {
- it.include("*.apk")
- it.duplicatesStrategy = DuplicatesStrategy.FAIL
- it.rename { fileName ->
- fileName.renameApkForTesting(project.path, project.hasBenchmarkPlugin())
- }
- }
- task.dependsOn(packageTask)
- }
- project.rootProject.tasks.named(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK) { task ->
- task as Zip
- task.from(packageTask.outputDirectory) {
- it.include("*.apk")
- it.duplicatesStrategy = DuplicatesStrategy.FAIL
- it.rename { fileName ->
- fileName.renameApkForTesting(project.path, project.hasBenchmarkPlugin())
- }
- }
- task.dependsOn(packageTask)
- }
-}
-
-private fun getOrCreateMediaTestConfigTask(project: Project, isMedia2: Boolean):
- TaskProvider<GenerateMediaTestConfigurationTask> {
- val mediaPrefix = getMediaConfigTaskPrefix(isMedia2)
- val parentProject = project.parent!!
- if (!parentProject.tasks.withType(GenerateMediaTestConfigurationTask::class.java)
- .names.contains(
- "support-$mediaPrefix-test${
- AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK
- }"
- )
- ) {
- val task = parentProject.tasks.register(
- "support-$mediaPrefix-test${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}",
- GenerateMediaTestConfigurationTask::class.java
- ) { task ->
- AffectedModuleDetector.configureTaskGuard(task)
- val detector = AffectedModuleDetector.getInstance(project)
- task.affectedModuleDetectorSubset.set(
- project.provider {
- detector.getSubset(task)
- }
- )
- }
- project.rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
- .dependsOn(task)
- project.rootProject.tasks.findByName(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK)!!
-
- .dependsOn(task)
- return task
- } else {
- return parentProject.tasks.withType(GenerateMediaTestConfigurationTask::class.java)
- .named(
- "support-$mediaPrefix-test${
- AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK
- }"
- )
- }
- }
-
-private fun getMediaConfigTaskPrefix(isMedia2: Boolean): String {
- return if (isMedia2) "media2" else "media"
-}
-
-fun Project.createOrUpdateMediaTestConfigurationGenerationTask(
- variantName: String,
- artifacts: Artifacts,
- minSdk: Int,
- testRunner: String,
- isMedia2: Boolean
-) {
- val mediaPrefix = getMediaConfigTaskPrefix(isMedia2)
- val mediaTask = getOrCreateMediaTestConfigTask(this, isMedia2)
- mediaTask.configure {
- it as GenerateMediaTestConfigurationTask
- if (this.name.contains("client")) {
- if (this.name.contains("previous")) {
- it.clientPreviousFolder.set(artifacts.get(SingleArtifact.APK))
- it.clientPreviousLoader.set(artifacts.getBuiltArtifactsLoader())
- it.clientPreviousPath.set(this.path)
- } else {
- it.clientToTFolder.set(artifacts.get(SingleArtifact.APK))
- it.clientToTLoader.set(artifacts.getBuiltArtifactsLoader())
- it.clientToTPath.set(this.path)
- }
- } else {
- if (this.name.contains("previous")) {
- it.servicePreviousFolder.set(artifacts.get(SingleArtifact.APK))
- it.servicePreviousLoader.set(artifacts.getBuiltArtifactsLoader())
- it.servicePreviousPath.set(this.path)
- } else {
- it.serviceToTFolder.set(artifacts.get(SingleArtifact.APK))
- it.serviceToTLoader.set(artifacts.getBuiltArtifactsLoader())
- it.serviceToTPath.set(this.path)
- }
- }
- it.clientPreviousServiceToT.fileValue(
- File(
- this.getTestConfigDirectory(),
- "${mediaPrefix}ClientPreviousServiceToT$variantName.xml"
- )
- )
- it.clientToTServicePrevious.fileValue(
- File(
- this.getTestConfigDirectory(),
- "${mediaPrefix}ClientToTServicePrevious$variantName.xml"
- )
- )
- it.clientToTServiceToT.fileValue(
- File(
- this.getTestConfigDirectory(),
- "${mediaPrefix}ClientToTServiceToT$variantName.xml"
- )
- )
- it.constrainedClientPreviousServiceToT.fileValue(
- File(
- this.getConstrainedTestConfigDirectory(),
- "${mediaPrefix}ClientPreviousServiceToT$variantName.xml"
- )
- )
- it.constrainedClientToTServicePrevious.fileValue(
- File(
- this.getConstrainedTestConfigDirectory(),
- "${mediaPrefix}ClientToTServicePrevious$variantName.xml"
- )
- )
- it.constrainedClientToTServiceToT.fileValue(
- File(
- this.getConstrainedTestConfigDirectory(),
- "${mediaPrefix}ClientToTServiceToT$variantName.xml"
- )
- )
- it.minSdk.set(minSdk)
- it.testRunner.set(testRunner)
- AffectedModuleDetector.configureTaskGuard(it)
- }
-}
-
-private fun Project.getOrCreateMacrobenchmarkConfigTask(variantName: String):
- TaskProvider<GenerateTestConfigurationTask> {
- val parentProject = this.parent!!
- return if (
- parentProject.tasks.withType(GenerateTestConfigurationTask::class.java).isEmpty()
- ) {
- parentProject.tasks.register(
- "${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}$variantName",
- GenerateTestConfigurationTask::class.java
- )
- } else {
- parentProject.tasks.withType(GenerateTestConfigurationTask::class.java)
- .named("${AndroidXPlugin.GENERATE_TEST_CONFIGURATION_TASK}$variantName")
- }
- }
-
-private fun Project.configureMacrobenchmarkConfigTask(
- variantName: String,
- artifacts: Artifacts,
- minSdk: Int,
- testRunner: String
-) {
- val configTask = getOrCreateMacrobenchmarkConfigTask(variantName)
- if (path.endsWith("macrobenchmark")) {
- configTask.configure { task ->
- task.testFolder.set(artifacts.get(SingleArtifact.APK))
- task.testLoader.set(artifacts.getBuiltArtifactsLoader())
- task.outputXml.fileValue(
- File(
- this.getTestConfigDirectory(),
- "${this.path.asFilenamePrefix()}$variantName.xml"
- )
- )
- task.constrainedOutputXml.fileValue(
- File(
- this.getTestConfigDirectory(),
- "${this.path.asFilenamePrefix()}$variantName.xml"
- )
- )
- task.minSdk.set(minSdk)
- task.hasBenchmarkPlugin.set(this.hasBenchmarkPlugin())
- task.testRunner.set(testRunner)
- task.testProjectPath.set(this.path)
- val detector = AffectedModuleDetector.getInstance(project)
- task.affectedModuleDetectorSubset.set(
- project.provider {
- detector.getSubset(task)
- }
- )
-
- AffectedModuleDetector.configureTaskGuard(task)
- }
- // Disable xml generation for projects that have no test sources
- this.afterEvaluate {
- configTask.configure {
- it.enabled = this.hasAndroidTestSourceCode()
- }
- }
- this.rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
- .dependsOn(configTask)
- this.rootProject.tasks.findByName(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK)!!
- .dependsOn(configTask)
- } else if (isMacrobenchmarkTarget()) {
- configTask.configure { task ->
- task.appFolder.set(artifacts.get(SingleArtifact.APK))
- task.appLoader.set(artifacts.getBuiltArtifactsLoader())
- task.appProjectPath.set(path)
- }
- }
-}
-
-/**
- * Tells whether this project is the macrobenchmark-target project
- */
-fun Project.isMacrobenchmarkTarget(): Boolean {
- return path.endsWith("macrobenchmark-target")
-}
-
-fun Project.configureTestConfigGeneration(baseExtension: BaseExtension) {
- extensions.getByType(AndroidComponentsExtension::class.java).apply {
- onVariants { variant ->
- val androidTest = when (variant) {
- is HasAndroidTest -> variant.androidTest
- else -> return@onVariants
- } ?: return@onVariants
- when {
- path.contains("media2:media2-session:version-compat-tests:") -> {
- createOrUpdateMediaTestConfigurationGenerationTask(
- androidTest.name,
- androidTest.artifacts,
- baseExtension.defaultConfig.minSdk!!,
- baseExtension.defaultConfig.testInstrumentationRunner!!,
- isMedia2 = true
- )
- }
- path.contains("media:version-compat-tests:") -> {
- createOrUpdateMediaTestConfigurationGenerationTask(
- androidTest.name,
- androidTest.artifacts,
- baseExtension.defaultConfig.minSdk!!,
- baseExtension.defaultConfig.testInstrumentationRunner!!,
- isMedia2 = false
- )
- }
- path.endsWith("macrobenchmark") ||
- isMacrobenchmarkTarget() -> {
- configureMacrobenchmarkConfigTask(
- androidTest.name,
- androidTest.artifacts,
- baseExtension.defaultConfig.minSdk!!,
- baseExtension.defaultConfig.testInstrumentationRunner!!
- )
- }
- else -> {
- createTestConfigurationGenerationTask(
- androidTest.name,
- androidTest.artifacts,
- baseExtension.defaultConfig.minSdk!!,
- baseExtension.defaultConfig.testInstrumentationRunner!!
- )
- }
- }
- }
- }
-}
diff --git a/buildSrc/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt b/buildSrc/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
deleted file mode 100644
index 5bfa736..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build.uptodatedness
-
-import androidx.build.VERIFY_UP_TO_DATE
-import org.gradle.api.GradleException
-import org.gradle.api.Project
-import org.gradle.api.Task
-import org.gradle.api.provider.Provider
-import org.gradle.api.services.BuildService
-import org.gradle.api.services.BuildServiceParameters
-import org.gradle.build.event.BuildEventsListenerRegistry
-import org.gradle.tooling.events.FinishEvent
-import org.gradle.tooling.events.OperationCompletionListener
-import org.gradle.tooling.events.task.TaskExecutionResult
-
-/**
- * Validates that all tasks (except a temporary exception list) are considered up-to-date.
- * The expected usage of this is that the user will invoke a build with the
- * TaskUpToDateValidator disabled, and then reinvoke the same build with the TaskUpToDateValidator
- * enabled. If the second build actually runs any tasks, then some tasks don't have the correct
- * inputs/outputs declared and are running more often than necessary.
- */
-
-const val DISALLOW_TASK_EXECUTION_FLAG_NAME = "disallowExecution"
-
-private const val ENABLE_FLAG_NAME = VERIFY_UP_TO_DATE
-
-// Temporary set of exempt tasks that are known to still be out-of-date after running once
-// Entries in this set may be task names (like assembleRelease) or task paths
-// (like :core:core:assembleRelease)
-// Entries in this set do still get rerun because they might produce files that are needed by
-// subsequent tasks
-val ALLOW_RERUNNING_TASKS = setOf(
- "buildOnServer",
- "checkExternalLicenses",
- "createArchive",
- "createDiffArchiveForAll",
- "createProjectZip",
- "externalNativeBuildDebug",
- "externalNativeBuildRelease",
- "generateDebugUnitTestConfig",
- "generateJsonModelDebug",
- "generateJsonModelRelease",
- "generateMetadataFileForAndroidDebugPublication",
- "generateMetadataFileForAndroidReleasePublication",
- "generateMetadataFileForDesktopPublication",
- "generateMetadataFileForJvmPublication",
- "generateMetadataFileForJvmlinux-x64Publication",
- "generateMetadataFileForJvmlinux-arm64Publication",
- "generateMetadataFileForJvmmacos-x64Publication",
- "generateMetadataFileForJvmmacos-arm64Publication",
- "generateMetadataFileForJvmwindows-x64Publication",
- "generateMetadataFileForJvmallPublication",
- "generateMetadataFileForMavenPublication",
- "generateMetadataFileForMetadataPublication",
- "generateMetadataFileForKotlinMultiplatformPublication",
- "generateMetadataFileForPluginMavenPublication",
- "generatePomFileForBenchmarkPluginMarkerMavenPublication",
- "generatePomFileForAndroidDebugPublication",
- "generatePomFileForAndroidReleasePublication",
- "generatePomFileForDesktopPublication",
- "generatePomFileForJvmlinux-x64Publication",
- "generatePomFileForJvmlinux-arm64Publication",
- "generatePomFileForJvmmacos-x64Publication",
- "generatePomFileForJvmmacos-arm64Publication",
- "generatePomFileForJvmwindows-x64Publication",
- "generatePomFileForJvmallPublication",
- "generatePomFileForJvmPublication",
- "generatePomFileForKotlinMultiplatformPublication",
- "generatePomFileForMavenPublication",
- "generatePomFileForPluginMavenPublication",
- "generatePomFileForMetadataPublication",
- "generatePomFileForSafeargsJavaPluginMarkerMavenPublication",
- "generatePomFileForSafeargsKotlinPluginMarkerMavenPublication",
- "partiallyDejetifyArchive",
- "publishBenchmarkPluginMarkerMavenPublicationToMavenRepository",
- "publishAndroidDebugPublicationToMavenRepository",
- "publishAndroidReleasePublicationToMavenRepository",
- "publishDesktopPublicationToMavenRepository",
- "publishJvmPublicationToMavenRepository",
- "publishJvmlinux-x64PublicationToMavenRepository",
- "publishJvmlinux-arm64PublicationToMavenRepository",
- "publishJvmmacos-x64PublicationToMavenRepository",
- "publishJvmmacos-arm64PublicationToMavenRepository",
- "publishJvmwindows-x64PublicationToMavenRepository",
- "publishJvmallPublicationToMavenRepository",
- "publishKotlinMultiplatformPublicationToMavenRepository",
- "publishMavenPublicationToMavenRepository",
- "publishMetadataPublicationToMavenRepository",
- "publishPluginMavenPublicationToMavenRepository",
- "publishSafeargsJavaPluginMarkerMavenPublicationToMavenRepository",
- "publishSafeargsKotlinPluginMarkerMavenPublicationToMavenRepository",
- /**
- * relocateShadowJar is used to configure the ShadowJar hence it does not have any outputs.
- * https://github.com/johnrengelman/shadow/issues/561
- */
- "relocateShadowJar",
- "testDebugUnitTest",
- "stripArchiveForPartialDejetification",
- "verifyDependencyVersions",
- "zipConstrainedTestConfigsWithApks",
- "zipTestConfigsWithApks",
- "zipHtmlResultsOfTestDebugUnitTest",
- "zipXmlResultsOfTestDebugUnitTest",
-
- ":camera:integration-tests:camera-testapp-core:mergeLibDexDebug",
- ":camera:integration-tests:camera-testapp-core:packageDebug",
- ":camera:integration-tests:camera-testapp-extensions:mergeLibDexDebug",
- ":camera:integration-tests:camera-testapp-extensions:packageDebug",
- ":camera:integration-tests:camera-testapp-extensions:GenerateTestConfigurationdebugAndroidTest",
- ":camera:integration-tests:camera-testapp-uiwidgets:mergeLibDexDebug",
- ":camera:integration-tests:camera-testapp-uiwidgets:packageDebug",
- ":camera:integration-tests:camera-testapp-core:GenerateTestConfigurationdebug",
- ":camera:integration-tests:camera-testapp-core:GenerateTestConfigurationdebugAndroidTest",
- ":camera:integration-tests:camera-testapp-view:GenerateTestConfigurationdebug",
- ":camera:integration-tests:camera-testapp-view:GenerateTestConfigurationdebugAndroidTest",
- ":camera:integration-tests:camera-testapp-view:mergeLibDexDebug",
- ":camera:integration-tests:camera-testapp-view:packageDebug",
- "configureCMakeDebug",
- "buildCMakeDebug",
- "configureCMakeRelWithDebInfo",
- "buildCMakeRelWithDebInfo",
- ":appsearch:appsearch-local-storage:buildCMakeDebug[icing]",
- ":appsearch:appsearch-local-storage:buildCMakeRelWithDebInfo[icing]",
- ":external:libyuv:buildCMakeDebug[yuv]",
- ":external:libyuv:buildCMakeRelWithDebInfo[yuv]",
- ":hilt:hilt-navigation-compose:kaptGenerateStubsDebugKotlin",
- ":hilt:hilt-navigation-compose:kaptGenerateStubsReleaseKotlin",
- ":lint-checks:integration-tests:copyDebugAndroidLintReports",
-
- // https://github.com/gradle/gradle/issues/17262
- ":doclava:compileJava",
- ":doclava:processResources",
- ":doclava:jar"
-)
-
-// Additional tasks that are expected to be temporarily out-of-date after running once
-// Tasks in this set we don't even try to rerun, because they're known to be unnecessary
-val DONT_TRY_RERUNNING_TASKS = setOf(
- ":buildSrc-tests:project-subsets:test",
- "listTaskOutputs",
- "validateProperties",
- "tasks",
-
- ":benchmark:benchmark-macro:generateReleaseProtos",
- ":benchmark:benchmark-macro:generateDebugProtos",
- ":benchmark:benchmark-macro:compileReleaseKotlin",
- ":benchmark:benchmark-macro:compileDebugKotlin",
- ":benchmark:benchmark-macro:compileReleaseJavaWithJavac",
- ":benchmark:benchmark-macro:compileDebugJavaWithJavac",
- ":benchmark:benchmark-macro:extractReleaseAnnotations",
- ":benchmark:benchmark-macro:extractDebugAnnotations",
- ":benchmark:benchmark-macro:generateApi",
- ":benchmark:benchmark-macro:runErrorProne",
- ":benchmark:benchmark-macro:lintAnalyzeDebug",
- ":benchmark:benchmark-macro:lintDebug",
-
- // More information about the fact that these dokka tasks rerun can be found at b/167569304
- "dokkaKotlinDocs",
- "zipDokkaDocs",
- "dackkaDocs",
-
- // Flakily not up-to-date, b/176120659
- "doclavaDocs",
-
- // We should be able to remove these entries when b/160392650 is fixed
- "lint",
- "lintAnalyzeDebug",
- "lintDebug",
- "lintVitalRelease",
- "lintWithExpandProjectionDebug",
- "lintWithoutExpandProjectionDebug",
-)
-
-abstract class TaskUpToDateValidator :
- BuildService<TaskUpToDateValidator.Parameters>, OperationCompletionListener {
- interface Parameters : BuildServiceParameters {
- // We check <validate> during task execution rather than during project configuration
- // so that any configuration cache created during the first build can be reused during the
- // second build, saving build time
- var validate: Provider<Boolean>
- }
-
- override fun onFinish(event: FinishEvent) {
- if (!getParameters().validate.get()) {
- return
- }
- val result = event.result
- if (result is TaskExecutionResult) {
- val name = event.descriptor.name
- val executionReasons = result.executionReasons
- if (executionReasons.isNullOrEmpty()) {
- // empty list means task was actually up-to-date, see docs for
- // TaskExecutionResult.executionReasons
- // null list means the task already failed, so we'll skip emitting our error
- return
- }
- if (!isAllowedToRerunTask(name)) {
- throw GradleException(
- "Ran two consecutive builds of the same tasks, and in the " +
- "second build, observed:\n" +
- "task $name not UP-TO-DATE. It was out-of-date because:\n" +
- "${result.executionReasons}"
- )
- }
- }
- }
-
- companion object {
- // Tells whether to create a TaskUpToDateValidator listener
- private fun shouldEnable(project: Project): Boolean {
- return project.providers.gradleProperty(ENABLE_FLAG_NAME)
- .forUseAtConfigurationTime().isPresent()
- }
-
- private fun isAllowedToRerunTask(taskPath: String): Boolean {
- if (ALLOW_RERUNNING_TASKS.contains(taskPath)) {
- return true
- }
- val colonIndex = taskPath.lastIndexOf(":")
- if (colonIndex >= 0) {
- val taskName = taskPath.substring(colonIndex + 1)
- if (ALLOW_RERUNNING_TASKS.contains(taskName)) {
- return true
- }
- }
- return false
- }
-
- private fun shouldTryRerunningTask(task: Task): Boolean {
- return !(
- DONT_TRY_RERUNNING_TASKS.contains(task.name) ||
- DONT_TRY_RERUNNING_TASKS.contains(task.path)
- )
- }
-
- fun setup(rootProject: Project, registry: BuildEventsListenerRegistry) {
- if (!shouldEnable(rootProject)) {
- return
- }
- val validate = rootProject.providers.gradleProperty(DISALLOW_TASK_EXECUTION_FLAG_NAME)
- .map({ _ -> true }).orElse(false)
- // create listener for validating that any task that reran was expected to rerun
- val validatorProvider = rootProject.getGradle().getSharedServices()
- .registerIfAbsent(
- "TaskUpToDateValidator",
- TaskUpToDateValidator::class.java,
- { spec -> spec.getParameters().validate = validate }
- )
- registry.onTaskCompletion(validatorProvider)
-
- // skip rerunning tasks that are known to be unnecessary to rerun
- rootProject.allprojects { subproject ->
- subproject.tasks.configureEach { task ->
- task.onlyIf {
- shouldTryRerunningTask(task) || !validate.get()
- }
- }
- }
- }
- }
-}
diff --git a/busytown/androidx-studio-integration.sh b/busytown/androidx-studio-integration.sh
index 1e5c319..5ba70ad 100755
--- a/busytown/androidx-studio-integration.sh
+++ b/busytown/androidx-studio-integration.sh
@@ -1,5 +1,4 @@
set -e
SCRIPT_PATH="$(cd $(dirname $0) && pwd)"
-# runErrorProne is disabled due to I77d9800990e2a46648f7ed2713c54398cd798a0d in AGP
-$SCRIPT_PATH/impl/build-studio-and-androidx.sh -Pandroidx.summarizeStderr --no-daemon -Pandroidx.allWarningsAsErrors listTaskOutputs bOS -Pandroidx.verifyUpToDate -x verifyDependencyVersions -x runErrorProne --stacktrace
+$SCRIPT_PATH/impl/build-studio-and-androidx.sh -Pandroidx.summarizeStderr --no-daemon -Pandroidx.allWarningsAsErrors listTaskOutputs bOS -Pandroidx.verifyUpToDate -x verifyDependencyVersions --stacktrace
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
index c283e93..bf418b7 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
@@ -46,6 +46,7 @@
* This includes things like default template and session parameters, as well as maximum resolution
* and aspect ratios for the display.
*/
+@Suppress("DEPRECATION")
class CameraUseCaseAdapter(context: Context) : UseCaseConfigFactory {
private val display: Display by lazy {
@@ -242,4 +243,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
index 797d497..04d26e5 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
@@ -23,9 +23,9 @@
import androidx.camera.camera2.pipe.integration.adapter.CameraInfoAdapter
import androidx.camera.camera2.pipe.integration.adapter.CameraInternalAdapter
import androidx.camera.camera2.pipe.integration.compat.EvCompCompat
+import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
import androidx.camera.camera2.pipe.integration.impl.CameraPipeCameraProperties
import androidx.camera.camera2.pipe.integration.impl.CameraProperties
-import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
import androidx.camera.camera2.pipe.integration.impl.EvCompControl
import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
import androidx.camera.camera2.pipe.integration.impl.ZoomControl
@@ -39,7 +39,7 @@
import dagger.Subcomponent
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.asCoroutineDispatcher
import javax.inject.Scope
@@ -70,7 +70,7 @@
val dispatcher = cameraThreadConfig.cameraExecutor.asCoroutineDispatcher()
val cameraScope = CoroutineScope(
- Job() +
+ SupervisorJob() +
dispatcher +
CoroutineName("CXCP-UseCase-${cameraConfig.cameraId.value}")
)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ComboRequestListener.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ComboRequestListener.kt
new file mode 100644
index 0000000..cc0eeae
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ComboRequestListener.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.impl
+
+import android.hardware.camera2.CaptureFailure
+import androidx.camera.camera2.pipe.CameraTimestamp
+import androidx.camera.camera2.pipe.FrameInfo
+import androidx.camera.camera2.pipe.FrameMetadata
+import androidx.camera.camera2.pipe.FrameNumber
+import androidx.camera.camera2.pipe.Request
+import androidx.camera.camera2.pipe.RequestMetadata
+import androidx.camera.camera2.pipe.StreamId
+import androidx.camera.camera2.pipe.integration.config.CameraScope
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * A ComboRequestListener which contains a set of [Request.Listener]s.
+ * The primary purpose of this class is to receive the capture result from the currently
+ * configured [UseCaseCamera] and propagate to the registered [Request.Listener]s.
+ */
+@CameraScope
+class ComboRequestListener @Inject constructor() : Request.Listener {
+ private val requestListeners = mutableMapOf<Request.Listener, Executor>()
+
+ @Volatile
+ private var listeners: Map<Request.Listener, Executor> = mapOf()
+
+ fun addListener(listener: Request.Listener, executor: Executor) {
+ check(!listeners.contains(listener)) { "$listener was already registered!" }
+ synchronized(requestListeners) {
+ requestListeners[listener] = executor
+ listeners = requestListeners.toMap()
+ }
+ }
+
+ fun removeListener(listener: Request.Listener) {
+ synchronized(requestListeners) {
+ requestListeners.remove(listener)
+ listeners = requestListeners.toMap()
+ }
+ }
+
+ override fun onAborted(request: Request) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute { listener.onAborted(request) }
+ }
+ }
+
+ override fun onBufferLost(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ stream: StreamId
+ ) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute { listener.onBufferLost(requestMetadata, frameNumber, stream) }
+ }
+ }
+
+ override fun onComplete(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ result: FrameInfo
+ ) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute { listener.onComplete(requestMetadata, frameNumber, result) }
+ }
+ }
+
+ override fun onFailed(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ captureFailure: CaptureFailure
+ ) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute { listener.onFailed(requestMetadata, frameNumber, captureFailure) }
+ }
+ }
+
+ override fun onPartialCaptureResult(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ captureResult: FrameMetadata
+ ) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute {
+ listener.onPartialCaptureResult(
+ requestMetadata,
+ frameNumber,
+ captureResult
+ )
+ }
+ }
+ }
+
+ override fun onRequestSequenceAborted(requestMetadata: RequestMetadata) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute {
+ listener.onRequestSequenceAborted(requestMetadata)
+ }
+ }
+ }
+
+ override fun onRequestSequenceCompleted(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber
+ ) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute {
+ listener.onRequestSequenceCompleted(requestMetadata, frameNumber)
+ }
+ }
+ }
+
+ override fun onRequestSequenceCreated(requestMetadata: RequestMetadata) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute {
+ listener.onRequestSequenceCreated(requestMetadata)
+ }
+ }
+ }
+
+ override fun onRequestSequenceSubmitted(requestMetadata: RequestMetadata) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute {
+ listener.onRequestSequenceSubmitted(requestMetadata)
+ }
+ }
+ }
+
+ override fun onStarted(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ timestamp: CameraTimestamp
+ ) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute {
+ listener.onStarted(requestMetadata, frameNumber, timestamp)
+ }
+ }
+ }
+
+ override fun onTotalCaptureResult(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ totalCaptureResult: FrameInfo
+ ) {
+ listeners.forEach { (listener, executor) ->
+ executor.execute {
+ listener.onTotalCaptureResult(requestMetadata, frameNumber, totalCaptureResult)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
index e152929..83580ec 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
@@ -21,13 +21,10 @@
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.CameraStream
-import androidx.camera.camera2.pipe.Lock3ABehavior
import androidx.camera.camera2.pipe.Result3A
import androidx.camera.camera2.pipe.StreamFormat
import androidx.camera.camera2.pipe.StreamId
-import androidx.camera.camera2.pipe.TorchState
import androidx.camera.camera2.pipe.core.Log.debug
-import androidx.camera.camera2.pipe.integration.adapter.CaptureConfigAdapter
import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
import androidx.camera.camera2.pipe.integration.config.CameraConfig
import androidx.camera.camera2.pipe.integration.config.UseCaseCameraScope
@@ -47,24 +44,30 @@
// UseCases
var activeUseCases: Set<UseCase>
+ // RequestControl of the UseCaseCamera
+ val requestControl: UseCaseCameraRequestControl
+
// Parameters
fun <T> setParameter(
key: CaptureRequest.Key<T>,
value: T,
- priority: Config.OptionPriority = defaultOptionPriority
+ priority: Config.OptionPriority = defaultOptionPriority,
)
+
fun <T> setParameterAsync(
key: CaptureRequest.Key<T>,
value: T,
- priority: Config.OptionPriority = defaultOptionPriority
+ priority: Config.OptionPriority = defaultOptionPriority,
): Deferred<Unit>
+
fun setParameters(
values: Map<CaptureRequest.Key<*>, Any>,
- priority: Config.OptionPriority = defaultOptionPriority
+ priority: Config.OptionPriority = defaultOptionPriority,
)
+
fun setParametersAsync(
values: Map<CaptureRequest.Key<*>, Any>,
- priority: Config.OptionPriority = defaultOptionPriority
+ priority: Config.OptionPriority = defaultOptionPriority,
): Deferred<Unit>
// 3A
@@ -88,13 +91,10 @@
class UseCaseCameraImpl(
private val cameraGraph: CameraGraph,
private val useCases: List<UseCase>,
- private val surfaceToStreamMap: Map<DeferrableSurface, StreamId>,
- private val state: UseCaseCameraState,
- private val configAdapter: CaptureConfigAdapter,
private val threads: UseCaseThreads,
+ override val requestControl: UseCaseCameraRequestControl,
) : UseCaseCamera {
private val debugId = useCaseCameraIds.incrementAndGet()
- private val currentOptionBuilder = Camera2ImplConfig.Builder()
private var activeSessionConfigAdapter: SessionConfigAdapter? = null
private var _activeUseCases = setOf<UseCase>()
@@ -117,107 +117,56 @@
cameraGraph.close()
}
- override suspend fun setTorchAsync(enabled: Boolean): Deferred<Result3A> {
- return cameraGraph.acquireSession().use {
- it.setTorch(
- when (enabled) {
- true -> TorchState.ON
- false -> TorchState.OFF
- }
- )
- }
- }
+ override suspend fun setTorchAsync(enabled: Boolean): Deferred<Result3A> =
+ requestControl.setTorchAsync(enabled)
override suspend fun startFocusAndMeteringAsync(
aeRegions: List<MeteringRectangle>,
afRegions: List<MeteringRectangle>,
awbRegions: List<MeteringRectangle>
- ): Deferred<Result3A> {
- return cameraGraph.acquireSession().use {
- it.lock3A(
- aeRegions = aeRegions,
- afRegions = afRegions,
- awbRegions = awbRegions,
- afLockBehavior = Lock3ABehavior.AFTER_NEW_SCAN
- )
- }
- }
+ ): Deferred<Result3A> =
+ requestControl.startFocusAndMeteringAsync(aeRegions, afRegions, awbRegions)
override fun <T> setParameter(
key: CaptureRequest.Key<T>,
value: T,
- priority: Config.OptionPriority
+ priority: Config.OptionPriority,
) {
- currentOptionBuilder.setCaptureRequestOptionWithPriority(key, value, priority)
- state.update(parameters = currentOptionBuilder.build().toParameters())
+ setParameterAsync(key, value, priority)
}
override fun <T> setParameterAsync(
key: CaptureRequest.Key<T>,
value: T,
- priority: Config.OptionPriority
- ): Deferred<Unit> {
- currentOptionBuilder.setCaptureRequestOptionWithPriority(key, value, priority)
- return state.updateAsync(parameters = currentOptionBuilder.build().toParameters())
- }
+ priority: Config.OptionPriority,
+ ): Deferred<Unit> = requestControl.appendParametersAsync(
+ values = mapOf(key to (value as Any)),
+ optionPriority = priority
+ )
override fun setParameters(
values: Map<CaptureRequest.Key<*>, Any>,
- priority: Config.OptionPriority
+ priority: Config.OptionPriority,
) {
- currentOptionBuilder.addAllCaptureRequestOptionsWithPriority(values, priority)
- state.update(parameters = currentOptionBuilder.build().toParameters())
+ setParametersAsync(values, priority)
}
override fun setParametersAsync(
values: Map<CaptureRequest.Key<*>, Any>,
- priority: Config.OptionPriority
- ): Deferred<Unit> {
- currentOptionBuilder.addAllCaptureRequestOptionsWithPriority(values, priority)
- return state.updateAsync(parameters = currentOptionBuilder.build().toParameters())
- }
+ priority: Config.OptionPriority,
+ ): Deferred<Unit> = requestControl.appendParametersAsync(
+ values = values,
+ optionPriority = priority
+ )
- override fun capture(captureSequence: List<CaptureConfig>) {
- val requests = captureSequence.map { configAdapter.mapToRequest(it) }
- state.capture(requests)
- }
+ override fun capture(captureSequence: List<CaptureConfig>) =
+ requestControl.issueSingleCapture(captureSequence)
- private fun updateUseCases() {
- val repeatingStreamIds = mutableSetOf<StreamId>()
- val repeatingListeners = CameraCallbackMap()
-
- for (useCase in activeUseCases) {
- val repeatingCapture = useCase.sessionConfig.repeatingCaptureConfig
- for (deferrableSurface in repeatingCapture.surfaces) {
- val streamId = surfaceToStreamMap[deferrableSurface]
- if (streamId != null) {
- repeatingStreamIds.add(streamId)
- }
- }
- }
-
- activeSessionConfigAdapter?.getValidSessionConfigOrNull()?.let { sessionConfig ->
- sessionConfig.repeatingCameraCaptureCallbacks.forEach { callback ->
- repeatingListeners.addCaptureCallback(
- callback,
- threads.backgroundExecutor
- )
- }
-
- // Only update the state when the SessionConfig is valid
- state.update(
- parameters = Camera2ImplConfig.Builder().apply {
- insertAllOptions(currentOptionBuilder.mutableConfig)
- insertAllOptions(sessionConfig.implementationOptions)
- }.build().toParameters(),
- appendParameters = false,
- streams = repeatingStreamIds,
- listeners = setOf(repeatingListeners)
- )
- } ?: run {
- debug { "Unable to reset the session due to invalid config" }
- // TODO: Consider to reset the session if there is no valid config.
- }
+ private fun updateUseCases() = activeSessionConfigAdapter?.getValidSessionConfigOrNull()?.let {
+ requestControl.setSessionConfigAsync(it)
+ } ?: run {
+ debug { "Unable to reset the session due to invalid config" }
+ // TODO: Consider to reset the session if there is no valid config.
}
override fun toString(): String = "UseCaseCamera-$debugId"
@@ -232,6 +181,7 @@
useCases: java.util.ArrayList<UseCase>,
cameraConfig: CameraConfig,
callbackMap: CameraCallbackMap,
+ requestListener: ComboRequestListener,
threads: UseCaseThreads,
): UseCaseCamera {
val streamConfigMap = mutableMapOf<CameraStream.Config, DeferrableSurface>()
@@ -256,7 +206,7 @@
val config = CameraGraph.Config(
camera = cameraConfig.cameraId,
streams = streamConfigMap.keys.toList(),
- defaultListeners = listOf(callbackMap),
+ defaultListeners = listOf(callbackMap, requestListener),
)
val graph = cameraPipe.create(config)
@@ -273,18 +223,18 @@
debug { "Unable to create capture session due to conflicting configurations" }
}
- val state = UseCaseCameraState(graph, threads)
- val configAdapter =
- CaptureConfigAdapter(surfaceToStreamMap, threads.backgroundExecutor)
+ val requestControl = UseCaseCameraRequestControlImpl(
+ graph,
+ surfaceToStreamMap,
+ threads
+ )
graph.start()
return UseCaseCameraImpl(
graph,
useCases,
- surfaceToStreamMap,
- state,
- configAdapter,
- threads
+ threads,
+ requestControl,
)
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
new file mode 100644
index 0000000..8938aee
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.impl
+
+import android.hardware.camera2.CaptureRequest
+import android.hardware.camera2.params.MeteringRectangle
+import androidx.annotation.GuardedBy
+import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.Lock3ABehavior
+import androidx.camera.camera2.pipe.Request
+import androidx.camera.camera2.pipe.RequestTemplate
+import androidx.camera.camera2.pipe.Result3A
+import androidx.camera.camera2.pipe.StreamId
+import androidx.camera.camera2.pipe.TorchState
+import androidx.camera.camera2.pipe.integration.adapter.CaptureConfigAdapter
+import androidx.camera.camera2.pipe.integration.config.UseCaseCameraScope
+import androidx.camera.core.impl.CaptureConfig
+import androidx.camera.core.impl.Config
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.MutableTagBundle
+import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.TagBundle
+import kotlinx.coroutines.Deferred
+import javax.inject.Inject
+
+/**
+ * The RequestControl provides a couple of APIs to update the config of the camera, it also stores
+ * the (repeating) request parameters of the configured [UseCaseCamera].
+ * Once the parameters are updated, it will trigger the update to the [UseCaseCameraState].
+ *
+ * The parameters can be stored for the different types of config respectively. Each
+ * type of the config can be removed or overridden respectively without interfering with the
+ * other types.
+ */
+@UseCaseCameraScope
+interface UseCaseCameraRequestControl {
+
+ enum class Type {
+ DEFAULT,
+ CAMERA2_CAMERA_CONTROL,
+ SESSION_CONFIG,
+ }
+
+ // Repeating parameters
+ fun appendParametersAsync(
+ type: Type = Type.DEFAULT,
+ values: Map<CaptureRequest.Key<*>, Any> = emptyMap(),
+ optionPriority: Config.OptionPriority = defaultOptionPriority,
+ tags: Map<String, Any> = emptyMap(),
+ streams: Set<StreamId>? = null,
+ template: RequestTemplate? = null,
+ listeners: Set<Request.Listener> = emptySet()
+ ): Deferred<Unit>
+ fun setConfigAsync(
+ type: Type = Type.DEFAULT,
+ config: Config? = null,
+ tags: Map<String, Any> = emptyMap(),
+ streams: Set<StreamId>? = null,
+ template: RequestTemplate? = null,
+ listeners: Set<Request.Listener> = emptySet()
+ ): Deferred<Unit>
+ fun setSessionConfigAsync(
+ sessionConfig: SessionConfig,
+ ): Deferred<Unit>
+
+ // 3A
+ suspend fun setTorchAsync(enabled: Boolean): Deferred<Result3A>
+ suspend fun startFocusAndMeteringAsync(
+ aeRegions: List<MeteringRectangle>,
+ afRegions: List<MeteringRectangle>,
+ awbRegions: List<MeteringRectangle>,
+ ): Deferred<Result3A>
+
+ // Capture
+ fun issueSingleCapture(captureSequence: List<CaptureConfig>)
+}
+
+class UseCaseCameraRequestControlImpl @Inject constructor(
+ private val graph: CameraGraph,
+ private val surfaceToStreamMap: Map<DeferrableSurface, StreamId>,
+ private val threads: UseCaseThreads,
+) : UseCaseCameraRequestControl {
+
+ private data class InfoBundle(
+ val options: Camera2ImplConfig.Builder = Camera2ImplConfig.Builder(),
+ val tags: MutableMap<String, Any> = mutableMapOf(),
+ val listeners: MutableSet<Request.Listener> = mutableSetOf()
+ )
+
+ @GuardedBy("lock")
+ private val infoBundleMap = mutableMapOf<UseCaseCameraRequestControl.Type, InfoBundle>()
+ private val lock = Any()
+
+ private val state = UseCaseCameraState(graph, threads)
+ private val configAdapter = CaptureConfigAdapter(surfaceToStreamMap, threads.backgroundExecutor)
+
+ override fun appendParametersAsync(
+ type: UseCaseCameraRequestControl.Type,
+ values: Map<CaptureRequest.Key<*>, Any>,
+ optionPriority: Config.OptionPriority,
+ tags: Map<String, Any>,
+ streams: Set<StreamId>?,
+ template: RequestTemplate?,
+ listeners: Set<Request.Listener>
+ ): Deferred<Unit> = synchronized(lock) {
+ if (infoBundleMap[type] == null) {
+ infoBundleMap[type] = InfoBundle()
+ }
+
+ infoBundleMap[type]?.let {
+ it.options.addAllCaptureRequestOptionsWithPriority(values, optionPriority)
+ it.tags.putAll(tags)
+ it.listeners.addAll(listeners)
+ }
+ infoBundleMap.toMap()
+ }.updateCameraStateAsync(
+ streams = streams,
+ template = template,
+ )
+
+ override fun setConfigAsync(
+ type: UseCaseCameraRequestControl.Type,
+ config: Config?,
+ tags: Map<String, Any>,
+ streams: Set<StreamId>?,
+ template: RequestTemplate?,
+ listeners: Set<Request.Listener>
+ ): Deferred<Unit> = synchronized(lock) {
+ infoBundleMap[type] = InfoBundle(
+ Camera2ImplConfig.Builder().apply {
+ config?.let {
+ insertAllOptions(it)
+ }
+ },
+ tags.toMutableMap(),
+ listeners.toMutableSet()
+ )
+ infoBundleMap.toMap()
+ }.updateCameraStateAsync(
+ streams = streams,
+ template = template,
+ )
+
+ override fun setSessionConfigAsync(sessionConfig: SessionConfig): Deferred<Unit> {
+ val repeatingStreamIds = mutableSetOf<StreamId>()
+ val repeatingListeners = CameraCallbackMap()
+
+ sessionConfig.repeatingCaptureConfig.surfaces.forEach {
+ surfaceToStreamMap[it]?.let { streamId ->
+ repeatingStreamIds.add(streamId)
+ }
+ }
+
+ sessionConfig.repeatingCameraCaptureCallbacks.forEach { callback ->
+ repeatingListeners.addCaptureCallback(
+ callback,
+ threads.backgroundExecutor
+ )
+ }
+
+ return setConfigAsync(
+ type = UseCaseCameraRequestControl.Type.SESSION_CONFIG,
+ config = sessionConfig.implementationOptions,
+ listeners = setOf(repeatingListeners),
+ streams = repeatingStreamIds,
+ )
+ }
+
+ override suspend fun setTorchAsync(enabled: Boolean): Deferred<Result3A> =
+ graph.acquireSession().use {
+ it.setTorch(
+ when (enabled) {
+ true -> TorchState.ON
+ false -> TorchState.OFF
+ }
+ )
+ }
+
+ override suspend fun startFocusAndMeteringAsync(
+ aeRegions: List<MeteringRectangle>,
+ afRegions: List<MeteringRectangle>,
+ awbRegions: List<MeteringRectangle>
+ ): Deferred<Result3A> = graph.acquireSession().use {
+ it.lock3A(
+ aeRegions = aeRegions,
+ afRegions = afRegions,
+ awbRegions = awbRegions,
+ afLockBehavior = Lock3ABehavior.AFTER_NEW_SCAN
+ )
+ }
+
+ override fun issueSingleCapture(captureSequence: List<CaptureConfig>) {
+ val requests = captureSequence.map { configAdapter.mapToRequest(it) }
+ // TODO(b/194243796): Need to append repeating parameters to the capture request.
+ state.capture(requests)
+ }
+
+ private fun Map<UseCaseCameraRequestControl.Type, InfoBundle>.updateCameraStateAsync(
+ streams: Set<StreamId>? = null,
+ template: RequestTemplate? = null,
+ ) = state.updateAsync(
+ parameters = toParameter(),
+ appendParameters = false,
+ internalParameters = mapOf(CAMERAX_TAG_BUNDLE to toTagBundle()),
+ appendInternalParameters = false,
+ streams = streams,
+ template = template,
+ listeners = getListeners(),
+ )
+
+ /**
+ * Merge and return all the request parameters from different types. it throws an exception
+ * If there are any parameter conflicts.
+ */
+ private fun Map<UseCaseCameraRequestControl.Type, InfoBundle>.toParameter() =
+ Camera2ImplConfig.Builder().also {
+ this.values.forEach { infoBundle ->
+ it.insertAllOptions(infoBundle.options.mutableConfig)
+ }
+ }.build().toParameters()
+
+ /**
+ * Merge all the tags together and store them in the TagBundle. It doesn't check the conflict
+ * of the tag key. i.e. doesn't check two different values but using the same key.
+ */
+ private fun Map<UseCaseCameraRequestControl.Type, InfoBundle>.toTagBundle(): TagBundle =
+ MutableTagBundle.create().also { tagBundle ->
+ this.values.map { it.tags }.forEach { requestTag ->
+ requestTag.forEach { (tagKey, tagValue) -> tagBundle.putTag(tagKey, tagValue) }
+ }
+ }
+
+ /**
+ * Merge and return the Request.listeners from different types.
+ */
+ private fun Map<UseCaseCameraRequestControl.Type, InfoBundle>.getListeners():
+ Set<Request.Listener> = mutableSetOf<Request.Listener>().also {
+ this.values.map { it.listeners }.forEach { listenerSet ->
+ it.addAll(listenerSet)
+ }
+ }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseThreads.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseThreads.kt
index c96c461..47c5bd2 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseThreads.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseThreads.kt
@@ -16,8 +16,11 @@
package androidx.camera.camera2.pipe.integration.impl
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executor
/**
@@ -28,4 +31,10 @@
val backgroundExecutor: Executor,
val backgroundDispatcher: CoroutineDispatcher,
-)
+) {
+ val sequentialExecutor = CameraXExecutors.newSequentialExecutor(backgroundExecutor)
+ val sequentialDispatcher = sequentialExecutor.asCoroutineDispatcher()
+ val sequentialScope = CoroutineScope(
+ scope.coroutineContext + SupervisorJob() + sequentialDispatcher
+ )
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
index 02ae06e..afa8a1a 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
@@ -18,13 +18,18 @@
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.params.MeteringRectangle
+import androidx.camera.camera2.pipe.Request
+import androidx.camera.camera2.pipe.RequestTemplate
import androidx.camera.camera2.pipe.Result3A
+import androidx.camera.camera2.pipe.StreamId
import androidx.camera.camera2.pipe.integration.config.UseCaseCameraComponent
import androidx.camera.camera2.pipe.integration.config.UseCaseCameraConfig
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
import androidx.camera.core.UseCase
import androidx.camera.core.impl.CaptureConfig
import androidx.camera.core.impl.Config
+import androidx.camera.core.impl.SessionConfig
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
@@ -50,7 +55,55 @@
}
// TODO: Further implement the methods in this class as needed
-class FakeUseCaseCamera(override var activeUseCases: Set<UseCase> = emptySet()) : UseCaseCamera {
+class FakeUseCaseCameraRequestControl : UseCaseCameraRequestControl {
+ override fun appendParametersAsync(
+ type: UseCaseCameraRequestControl.Type,
+ values: Map<CaptureRequest.Key<*>, Any>,
+ optionPriority: Config.OptionPriority,
+ tags: Map<String, Any>,
+ streams: Set<StreamId>?,
+ template: RequestTemplate?,
+ listeners: Set<Request.Listener>
+ ): Deferred<Unit> {
+ return CompletableDeferred(Unit)
+ }
+
+ override fun setConfigAsync(
+ type: UseCaseCameraRequestControl.Type,
+ config: Config?,
+ tags: Map<String, Any>,
+ streams: Set<StreamId>?,
+ template: RequestTemplate?,
+ listeners: Set<Request.Listener>
+ ): Deferred<Unit> {
+ return CompletableDeferred(Unit)
+ }
+
+ override fun setSessionConfigAsync(sessionConfig: SessionConfig): Deferred<Unit> {
+ return CompletableDeferred(Unit)
+ }
+
+ override suspend fun setTorchAsync(enabled: Boolean): Deferred<Result3A> {
+ return CompletableDeferred(Result3A(status = Result3A.Status.OK))
+ }
+
+ override suspend fun startFocusAndMeteringAsync(
+ aeRegions: List<MeteringRectangle>,
+ afRegions: List<MeteringRectangle>,
+ awbRegions: List<MeteringRectangle>
+ ): Deferred<Result3A> {
+ return CompletableDeferred(Result3A(status = Result3A.Status.OK))
+ }
+
+ override fun issueSingleCapture(captureSequence: List<CaptureConfig>) {
+ }
+}
+
+// TODO: Further implement the methods in this class as needed
+class FakeUseCaseCamera(
+ override var activeUseCases: Set<UseCase> = emptySet(),
+ override var requestControl: UseCaseCameraRequestControl = FakeUseCaseCameraRequestControl(),
+) : UseCaseCamera {
override fun <T> setParameter(
key: CaptureRequest.Key<T>,
@@ -64,7 +117,7 @@
value: T,
priority: Config.OptionPriority
): Deferred<Unit> {
- return CompletableDeferred<Unit>().apply { complete(Unit) }
+ return CompletableDeferred(Unit)
}
override fun setParameters(
@@ -77,13 +130,11 @@
values: Map<CaptureRequest.Key<*>, Any>,
priority: Config.OptionPriority
): Deferred<Unit> {
- return CompletableDeferred<Unit>().apply { complete(Unit) }
+ return CompletableDeferred(Unit)
}
override suspend fun setTorchAsync(enabled: Boolean): Deferred<Result3A> {
- return CompletableDeferred<Result3A>().apply {
- complete(Result3A(status = Result3A.Status.OK))
- }
+ return CompletableDeferred(Result3A(status = Result3A.Status.OK))
}
override suspend fun startFocusAndMeteringAsync(
@@ -91,9 +142,7 @@
afRegions: List<MeteringRectangle>,
awbRegions: List<MeteringRectangle>
): Deferred<Result3A> {
- return CompletableDeferred<Result3A>().apply {
- complete(Result3A(status = Result3A.Status.OK))
- }
+ return CompletableDeferred(Result3A(status = Result3A.Status.OK))
}
override fun capture(captureSequence: List<CaptureConfig>) {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
index f2d49f8..39859f2 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
@@ -188,6 +188,7 @@
}
@RequiresApi(Build.VERSION_CODES.P)
+@Suppress("DEPRECATION")
internal object Api28Compat {
@JvmStatic
@Throws(CameraAccessException::class)
diff --git a/camera/camera-camera2/lint-baseline.xml b/camera/camera-camera2/lint-baseline.xml
index 3c8a8b9..9212724 100644
--- a/camera/camera-camera2/lint-baseline.xml
+++ b/camera/camera-camera2/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
<issue
id="NewApi"
@@ -52,7 +52,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="104"
+ line="105"
column="41"/>
</issue>
@@ -63,7 +63,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="123"
+ line="124"
column="41"/>
</issue>
@@ -74,7 +74,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="124"
+ line="125"
column="21"/>
</issue>
@@ -85,7 +85,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="167"
+ line="168"
column="52"/>
</issue>
@@ -96,7 +96,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="172"
+ line="173"
column="41"/>
</issue>
@@ -107,7 +107,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="173"
+ line="174"
column="21"/>
</issue>
@@ -118,7 +118,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="192"
+ line="193"
column="52"/>
</issue>
@@ -129,7 +129,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="197"
+ line="198"
column="41"/>
</issue>
@@ -140,7 +140,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="198"
+ line="199"
column="21"/>
</issue>
@@ -151,7 +151,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatTest.java"
- line="217"
+ line="218"
column="41"/>
</issue>
@@ -426,7 +426,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/SynchronizedCaptureSessionBaseTest.java"
- line="118"
+ line="119"
column="55"/>
</issue>
@@ -437,7 +437,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/SynchronizedCaptureSessionBaseTest.java"
- line="120"
+ line="121"
column="36"/>
</issue>
@@ -448,7 +448,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/SynchronizedCaptureSessionBaseTest.java"
- line="132"
+ line="133"
column="55"/>
</issue>
@@ -459,7 +459,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/camera/camera2/internal/SynchronizedCaptureSessionBaseTest.java"
- line="135"
+ line="136"
column="36"/>
</issue>
@@ -541,39 +541,6 @@
</issue>
<issue
- id="SoonBlockedPrivateApi"
- message="Reflective access to MAX_SURFACES_COUNT will throw an exception when targeting API 30 and above"
- errorLine1=" Field maxSurfacesCountField = OutputConfiguration.class.getDeclaredField("
- errorLine2=" ^">
- <location
- file="src/main/java/androidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi26Impl.java"
- line="62"
- column="39"/>
- </issue>
-
- <issue
- id="SoonBlockedPrivateApi"
- message="Reflective access to mSurfaces will throw an exception when targeting API 30 and above"
- errorLine1=" Field surfacesField = OutputConfiguration.class.getDeclaredField(SURFACES_FIELD);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi26Impl.java"
- line="71"
- column="31"/>
- </issue>
-
- <issue
- id="WrongConstant"
- message="Must be one of: SessionConfigurationCompat.SESSION_REGULAR, SessionConfigurationCompat.SESSION_HIGH_SPEED"
- errorLine1=" return mObject.getSessionType();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/internal/compat/params/SessionConfigurationCompat.java"
- line="427"
- column="20"/>
- </issue>
-
- <issue
id="BanUncheckedReflection"
message="Calling `Method.invoke` without an SDK check"
errorLine1=" return (Size) getSurfaceSize.invoke(null, surface);"
@@ -607,6 +574,281 @@
</issue>
<issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/compat/workaround/AeFpsRange.java"
+ line="54"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.setCaptureRequestOption(CaptureRequest.CONTROL_ZOOM_RATIO, mCurrentZoomRatio);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/AndroidRZoomImpl.java"
+ line="60"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.setCaptureRequestOption(CaptureRequest.SCALER_CROP_REGION,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java"
+ line="65"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/ExposureControl.java"
+ line="127"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="181"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="185"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="189"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="193"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" Camera2ImplConfig.Builder configBuilder = new Camera2ImplConfig.Builder();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="366"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption(CaptureRequest.CONTROL_AF_TRIGGER,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="367"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.addImplementationOptions(configBuilder.build());"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="369"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" Camera2ImplConfig.Builder configBuilder = new Camera2ImplConfig.Builder();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="417"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="418"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.addImplementationOptions(configBuilder.build());"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="420"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" Camera2ImplConfig.Builder configBuilder = new Camera2ImplConfig.Builder();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="459"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption(CaptureRequest.CONTROL_AF_TRIGGER,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="461"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" configBuilder.setCaptureRequestOption(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="465"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.addImplementationOptions(configBuilder.build());"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java"
+ line="468"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" Camera2ImplConfig.Builder camera2ConfigBuilder = new Camera2ImplConfig.Builder();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/ImageCaptureOptionUnpacker.java"
+ line="52"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.addImplementationOptions(camera2ConfigBuilder.build());"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/ImageCaptureOptionUnpacker.java"
+ line="59"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.setCaptureRequestOption(CaptureRequest.CONTROL_ENABLE_ZSL, true);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/compat/workaround/ImageCapturePixelHDRPlus.java"
+ line="53"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" builder.setCaptureRequestOption(CaptureRequest.CONTROL_ENABLE_ZSL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/compat/workaround/ImageCapturePixelHDRPlus.java"
+ line="57"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" Camera2ImplConfig.Builder camera2ConfigBuilder = new Camera2ImplConfig.Builder();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/compat/workaround/PreviewPixelHDRnet.java"
+ line="46"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" camera2ConfigBuilder.setCaptureRequestOption(CaptureRequest.TONEMAP_MODE,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/compat/workaround/PreviewPixelHDRnet.java"
+ line="47"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" sessionBuilder.addImplementationOptions(camera2ConfigBuilder.build());"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/androidx/camera/camera2/internal/compat/workaround/PreviewPixelHDRnet.java"
+ line="49"
+ column="70"/>
+ </issue>
+
+ <issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
errorLine1=" public static List<OutputConfiguration> transformFromCompat("
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
index 4581562..89eee13 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
@@ -35,6 +35,7 @@
@RunWith(Parameterized::class)
@SmallTest
+@Suppress("DEPRECATION")
public class Camera2CamcorderProfileProviderTest(private val quality: Int) {
public companion object {
@JvmStatic
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProvider.java
index a1040d8..f88e1dc 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProvider.java
@@ -93,6 +93,7 @@
}
@Nullable
+ @SuppressWarnings("deprecation")
private CamcorderProfileProxy getProfileInternal(int quality) {
CamcorderProfile profile = null;
try {
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java
index e9ab04f..7f3dd92f 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java
@@ -69,6 +69,7 @@
}
@Override
+ @SuppressWarnings("deprecation")
public CamcorderProfile get(int cameraId, int quality) {
return CamcorderProfile.get(cameraId, quality);
}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi26Impl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi26Impl.java
index 8ef8352..e05d996 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi26Impl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi26Impl.java
@@ -16,6 +16,7 @@
package androidx.camera.camera2.internal.compat.params;
+import android.annotation.SuppressLint;
import android.hardware.camera2.params.OutputConfiguration;
import android.view.Surface;
@@ -59,6 +60,7 @@
private static int getMaxSharedSurfaceCountApi26()
throws NoSuchFieldException, IllegalAccessException {
+ @SuppressLint("SoonBlockedPrivateApi") // Only used between API 26 and 28
Field maxSurfacesCountField = OutputConfiguration.class.getDeclaredField(
MAX_SHARED_SURFACES_COUNT_FIELD);
maxSurfacesCountField.setAccessible(true);
@@ -68,6 +70,7 @@
@SuppressWarnings("unchecked")
private static List<Surface> getMutableSurfaceListApi26(OutputConfiguration outputConfiguration)
throws NoSuchFieldException, IllegalAccessException {
+ @SuppressLint("SoonBlockedPrivateApi") // Only used between API 26 and 28
Field surfacesField = OutputConfiguration.class.getDeclaredField(SURFACES_FIELD);
surfacesField.setAccessible(true);
return (List<Surface>) surfacesField.get(outputConfiguration);
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java
index 5e4cf17..23c7482 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java
@@ -65,6 +65,9 @@
if (CameraNoResponseWhenEnablingFlashQuirk.load(cameraCharacteristicsCompat)) {
quirks.add(new CameraNoResponseWhenEnablingFlashQuirk());
}
+ if (YuvImageOnePixelShiftQuirk.load(cameraCharacteristicsCompat)) {
+ quirks.add(new YuvImageOnePixelShiftQuirk());
+ }
return new Quirks(quirks);
}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/YuvImageOnePixelShiftQuirk.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/YuvImageOnePixelShiftQuirk.java
new file mode 100644
index 0000000..0d4fa6a
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/YuvImageOnePixelShiftQuirk.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.internal.compat.quirk;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.core.internal.compat.quirk.OnePixelShiftQuirk;
+
+/**
+ * For these devices, workaround will be patched to shift one pixel right to left and
+ * duplicate the last pixel for YUV_420_888 data when converting to RGBA.
+ */
+public final class YuvImageOnePixelShiftQuirk implements OnePixelShiftQuirk {
+
+ static boolean load(@NonNull CameraCharacteristicsCompat characteristicsCompat) {
+ return isMotorolaMotoG3() || isSamsungSMG532F() || isSamsungSMGJ700F();
+ }
+
+ private static boolean isMotorolaMotoG3() {
+ return "motorola".equalsIgnoreCase(Build.BRAND) && "MotoG3".equalsIgnoreCase(Build.MODEL);
+ }
+
+ private static boolean isSamsungSMG532F() {
+ return "samsung".equalsIgnoreCase(Build.BRAND) && "SM-G532F".equalsIgnoreCase(Build.MODEL);
+ }
+
+ private static boolean isSamsungSMGJ700F() {
+ return "samsung".equalsIgnoreCase(Build.BRAND) && "SM-J700F".equalsIgnoreCase(Build.MODEL);
+ }
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/YuvImageOnePixelShiftQuirkTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/YuvImageOnePixelShiftQuirkTest.java
new file mode 100644
index 0000000..c793843
--- /dev/null
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/YuvImageOnePixelShiftQuirkTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.internal.compat.quirk;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.core.impl.Quirks;
+import androidx.camera.core.internal.compat.quirk.OnePixelShiftQuirk;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.ParameterizedRobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.internal.DoNotInstrument;
+import org.robolectric.shadows.ShadowCameraCharacteristics;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Unit test for {@link YuvImageOnePixelShiftQuirk}.
+ */
+@RunWith(ParameterizedRobolectricTestRunner.class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+public class YuvImageOnePixelShiftQuirkTest {
+
+ private static final String CAMERA_ID = "0";
+
+ @ParameterizedRobolectricTestRunner.Parameters
+ public static Collection<Object[]> data() {
+ final List<Object[]> data = new ArrayList<>();
+ data.add(new Object[]{new Config(
+ "motorola", "MotoG3", true)});
+ data.add(new Object[]{new Config(
+ "samsung", "SM-G532F", true)});
+ data.add(new Object[]{new Config(
+ "samsung", "SM-J700F", true)});
+ data.add(new Object[]{new Config(
+ "motorola", "MotoG100", false)});
+ return data;
+ }
+
+ @NonNull private final Config mConfig;
+
+ public YuvImageOnePixelShiftQuirkTest(@NonNull Config config) {
+ mConfig = config;
+ }
+
+ @Test
+ public void shouldApplyOnePixelShift() {
+ // Arrange.
+ if (mConfig.mBrand != null) {
+ ReflectionHelpers.setStaticField(Build.class, "BRAND", mConfig.mBrand);
+ ReflectionHelpers.setStaticField(Build.class, "MODEL", mConfig.mModel);
+ }
+
+ // Act.
+ CameraCharacteristics characteristics =
+ ShadowCameraCharacteristics.newCameraCharacteristics();
+ CameraCharacteristicsCompat characteristicsCompat =
+ CameraCharacteristicsCompat.toCameraCharacteristicsCompat(characteristics);
+ final Quirks quirks = CameraQuirks.get(CAMERA_ID, characteristicsCompat);
+
+ // Assert.
+ boolean isSupported = quirks != null && quirks.contains(OnePixelShiftQuirk.class);
+ assertThat(isSupported).isEqualTo(mConfig.mIsSupported);
+ }
+
+ static class Config {
+ @NonNull final String mBrand;
+ @NonNull final String mModel;
+ final boolean mIsSupported;
+
+ Config(@NonNull String brand, @NonNull String model, boolean isSupported) {
+ mBrand = brand;
+ mModel = model;
+ mIsSupported = isSupported;
+ }
+ }
+}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
index b4a3131..59247ca 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
@@ -21,9 +21,11 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
+import androidx.camera.testing.fakes.FakeCameraInfoInternal;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -41,6 +43,7 @@
@Test
@UiThreadTest
public void becomesActive_whenHasAnalyzer() {
+ when(mMockCameraInternal.getCameraInfoInternal()).thenReturn(new FakeCameraInfoInternal());
ImageAnalysis useCase = new ImageAnalysis.Builder().setBackpressureStrategy(
STRATEGY_KEEP_ONLY_LATEST).build();
@@ -54,6 +57,7 @@
@Test
@UiThreadTest
public void becomesInactive_whenNoAnalyzer() {
+ when(mMockCameraInternal.getCameraInfoInternal()).thenReturn(new FakeCameraInfoInternal());
ImageAnalysis useCase = new ImageAnalysis.Builder().setBackpressureStrategy(
STRATEGY_KEEP_ONLY_LATEST).build();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageYuvToRgbConverterTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageYuvToRgbConverterTest.java
index e3aca6f..98d03e3 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageYuvToRgbConverterTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageYuvToRgbConverterTest.java
@@ -77,7 +77,7 @@
// Act.
ImageProxy rgbImageProxy = ImageYuvToRgbConverter.convertYUVToRGB(mYUVImageProxy,
- mRGBImageReaderProxy);
+ mRGBImageReaderProxy, /*onePixelShiftRequested=*/false);
// Assert.
assertThat(rgbImageProxy.getFormat()).isEqualTo(PixelFormat.RGBA_8888);
@@ -86,13 +86,13 @@
@Test
public void convertYUVToRGBWhenFlipUV() {
- // Act.
+ // Arrange.
mYUVImageProxy.setPlanes(createYUV420ImagePlanes(WIDTH, HEIGHT, PIXEL_STRIDE_Y,
PIXEL_STRIDE_UV, true));
// Act.
ImageProxy rgbImageProxy = ImageYuvToRgbConverter.convertYUVToRGB(mYUVImageProxy,
- mRGBImageReaderProxy);
+ mRGBImageReaderProxy, /*onePixelShiftRequested=*/false);
// Assert.
assertThat(rgbImageProxy.getFormat()).isEqualTo(PixelFormat.RGBA_8888);
@@ -101,13 +101,16 @@
@Test
public void convertYUVToRGBWhenUnsupportedYUVFormat() {
- // Act.
- mYUVImageProxy.setPlanes(createYUV420ImagePlanes(WIDTH, HEIGHT, PIXEL_STRIDE_Y_UNSUPPORTED,
+ // Arrange.
+ mYUVImageProxy.setPlanes(createYUV420ImagePlanes(
+ WIDTH,
+ HEIGHT,
+ PIXEL_STRIDE_Y_UNSUPPORTED,
PIXEL_STRIDE_UV_UNSUPPORTED, true));
// Act.
ImageProxy rgbImageProxy = ImageYuvToRgbConverter.convertYUVToRGB(mYUVImageProxy,
- mRGBImageReaderProxy);
+ mRGBImageReaderProxy, /*onePixelShiftRequested=*/false);
// Assert.
assertThat(rgbImageProxy.getFormat()).isEqualTo(PixelFormat.RGBA_8888);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/CamcorderProfileProxyTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/CamcorderProfileProxyTest.kt
index 1f560eb..45b1947 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/CamcorderProfileProxyTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/CamcorderProfileProxyTest.kt
@@ -26,6 +26,7 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
+@Suppress("DEPRECATION")
public class CamcorderProfileProxyTest {
@Test
diff --git a/camera/camera-core/src/main/cpp/yuv_to_rgb_jni.cc b/camera/camera-core/src/main/cpp/yuv_to_rgb_jni.cc
index d9091b0..7bb92d5 100644
--- a/camera/camera-core/src/main/cpp/yuv_to_rgb_jni.cc
+++ b/camera/camera-core/src/main/cpp/yuv_to_rgb_jni.cc
@@ -22,11 +22,14 @@
jint src_stride_u,
jobject src_v,
jint src_stride_v,
+ jint src_pixel_stride_y,
jint src_pixel_stride_uv,
jobject surface,
jint width,
jint height,
- jint start_offset) {
+ jint start_offset_y,
+ jint start_offset_u,
+ jint start_offset_v) {
uint8_t* src_y_ptr =
static_cast<uint8_t*>(env->GetDirectBufferAddress(src_y));
@@ -34,9 +37,6 @@
static_cast<uint8_t*>(env->GetDirectBufferAddress(src_u));
uint8_t* src_v_ptr =
static_cast<uint8_t*>(env->GetDirectBufferAddress(src_v));
- src_y_ptr += start_offset;
- src_u_ptr += start_offset;
- src_v_ptr += start_offset;
ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
if (window == nullptr) {
@@ -50,17 +50,79 @@
}
uint8_t* dst_abgr_ptr = reinterpret_cast<uint8_t*>(buffer.bits);
- int result = libyuv::Android420ToABGR(src_y_ptr,
- src_stride_y,
- src_u_ptr,
- src_stride_u,
- src_v_ptr,
- src_stride_v,
- src_pixel_stride_uv,
- dst_abgr_ptr,
- buffer.stride * 4,
- width,
- height);
+ int result = 0;
+ // Apply workaround for one pixel shift issue by checking offset.
+ if (start_offset_y > 0 || start_offset_u > 0 || start_offset_v > 0) {
+
+ // TODO(b/195990691): extend the pixel shift to handle multiple corrupted pixels.
+ // We don't support multiple pixel shift now.
+ if (start_offset_y != src_pixel_stride_y
+ || start_offset_u != src_pixel_stride_uv
+ || start_offset_v != src_pixel_stride_uv) {
+ ANativeWindow_unlockAndPost(window);
+ ANativeWindow_release(window);
+ return -1;
+ }
+
+ // Convert yuv to rgb except the last line.
+ result = libyuv::Android420ToABGR(src_y_ptr + start_offset_y,
+ src_stride_y,
+ src_u_ptr + start_offset_u,
+ src_stride_u,
+ src_v_ptr + start_offset_v,
+ src_stride_v,
+ src_pixel_stride_uv,
+ dst_abgr_ptr,
+ buffer.stride * 4,
+ width,
+ height - 1);
+ if (result == 0) {
+ // Convert the last row with (width - 1) pixels
+ // since the last pixel's yuv data is missing.
+ result = libyuv::Android420ToABGR(
+ src_y_ptr + start_offset_y + src_stride_y * (height - 1),
+ src_stride_y - 1,
+ src_u_ptr + start_offset_u + src_stride_u * (height - 2) / 2,
+ src_stride_u - 1,
+ src_v_ptr + start_offset_v + src_stride_v * (height - 2) / 2,
+ src_stride_v - 1,
+ src_pixel_stride_uv,
+ dst_abgr_ptr + buffer.stride * 4 * (height - 1),
+ buffer.stride * 4,
+ width - 1,
+ 1);
+ }
+
+ if (result == 0) {
+ // Set the 2x2 pixels on the right bottom by duplicating the 3rd pixel
+ // from the right to left in each row.
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ int r_ind = buffer.stride * 4 * (height - 1 - i) + width * 4 - (j * 4 + 1);
+ int g_ind = buffer.stride * 4 * (height - 1 - i) + width * 4 - (j * 4 + 2);
+ int b_ind = buffer.stride * 4 * (height - 1 - i) + width * 4 - (j * 4 + 3);
+ int a_ind = buffer.stride * 4 * (height - 1 - i) + width * 4 - (j * 4 + 4);
+ dst_abgr_ptr[r_ind] = dst_abgr_ptr[r_ind - 8];
+ dst_abgr_ptr[g_ind] = dst_abgr_ptr[g_ind - 8];
+ dst_abgr_ptr[b_ind] = dst_abgr_ptr[b_ind - 8];
+ dst_abgr_ptr[a_ind] = dst_abgr_ptr[a_ind - 8];
+ }
+ }
+ }
+ } else {
+ result = libyuv::Android420ToABGR(src_y_ptr + start_offset_y,
+ src_stride_y,
+ src_u_ptr + start_offset_u,
+ src_stride_u,
+ src_v_ptr + start_offset_v,
+ src_stride_v,
+ src_pixel_stride_uv,
+ dst_abgr_ptr,
+ buffer.stride * 4,
+ width,
+ height);
+ }
+
ANativeWindow_unlockAndPost(window);
ANativeWindow_release(window);
return result;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index 883c6c5..c690dbef 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -19,6 +19,7 @@
import static androidx.camera.core.impl.ImageAnalysisConfig.OPTION_BACKPRESSURE_STRATEGY;
import static androidx.camera.core.impl.ImageAnalysisConfig.OPTION_IMAGE_QUEUE_DEPTH;
import static androidx.camera.core.impl.ImageAnalysisConfig.OPTION_IMAGE_READER_PROXY_PROVIDER;
+import static androidx.camera.core.impl.ImageAnalysisConfig.OPTION_ONE_PIXEL_SHIFT_ENABLED;
import static androidx.camera.core.impl.ImageAnalysisConfig.OPTION_OUTPUT_IMAGE_FORMAT;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_MAX_RESOLUTION;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_SUPPORTED_RESOLUTIONS;
@@ -52,6 +53,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.camera.core.impl.CameraInfoInternal;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.CaptureConfig;
import androidx.camera.core.impl.Config;
@@ -71,6 +73,7 @@
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.TargetConfig;
import androidx.camera.core.internal.ThreadConfig;
+import androidx.camera.core.internal.compat.quirk.OnePixelShiftQuirk;
import androidx.core.util.Consumer;
import androidx.core.util.Preconditions;
import androidx.lifecycle.LifecycleOwner;
@@ -176,6 +179,8 @@
private static final int DEFAULT_IMAGE_QUEUE_DEPTH = 6;
// Default to YUV_420_888 format for output.
private static final int DEFAULT_OUTPUT_IMAGE_FORMAT = OUTPUT_IMAGE_FORMAT_YUV_420_888;
+ // One pixel shift for YUV.
+ private static final Boolean DEFAULT_ONE_PIXEL_SHIFT_ENABLED = null;
@SuppressWarnings("WeakerAccess") /* synthetic access */
final ImageAnalysisAbstractAnalyzer mImageAnalysisAbstractAnalyzer;
@@ -218,6 +223,30 @@
mImageAnalysisAbstractAnalyzer.setOutputImageFormat(getOutputImageFormat());
}
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ protected UseCaseConfig<?> onMergeConfig(@NonNull CameraInfoInternal cameraInfo,
+ @NonNull UseCaseConfig.Builder<?, ?, ?> builder) {
+
+ // Flag to enable or disable one pixel shift. It will override the flag set by device info.
+ // If enabled, the workaround will be applied for all devices.
+ // If disabled, the workaround will be disabled for all devices.
+ // If not configured, the workaround will be applied to the problem devices only.
+ Boolean isOnePixelShiftEnabled = getOnePixelShiftEnabled();
+ boolean isOnePixelShiftIssueDevice = cameraInfo.getCameraQuirks().contains(
+ OnePixelShiftQuirk.class) ? true : false;
+ mImageAnalysisAbstractAnalyzer.setOnePixelShiftEnabled(
+ isOnePixelShiftEnabled == null ? isOnePixelShiftIssueDevice
+ : isOnePixelShiftEnabled);
+ return super.onMergeConfig(cameraInfo, builder);
+ }
+
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
SessionConfig.Builder createPipeline(@NonNull String cameraId,
@NonNull ImageAnalysisConfig config, @NonNull Size resolution) {
@@ -481,6 +510,16 @@
}
/**
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Boolean getOnePixelShiftEnabled() {
+ return ((ImageAnalysisConfig) getCurrentConfig()).getOnePixelShiftEnabled(
+ DEFAULT_ONE_PIXEL_SHIFT_ENABLED);
+ }
+
+ /**
* Gets resolution related information of the {@link ImageAnalysis}.
*
* <p>The returned {@link ResolutionInfo} will be expressed in the coordinates of the camera
@@ -834,6 +873,15 @@
return this;
}
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public Builder setOnePixelShiftEnabled(boolean onePixelShiftEnabled) {
+ getMutableConfig().insertOption(OPTION_ONE_PIXEL_SHIFT_ENABLED,
+ Boolean.valueOf(onePixelShiftEnabled));
+ return this;
+ }
+
/**
* {@inheritDoc}
*
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisAbstractAnalyzer.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisAbstractAnalyzer.java
index 39421c7..92d6266 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisAbstractAnalyzer.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisAbstractAnalyzer.java
@@ -48,6 +48,7 @@
private volatile int mRelativeRotation;
@ImageAnalysis.OutputImageFormat
private volatile int mOutputImageFormat = ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888;
+ private volatile boolean mOnePixelShiftEnabled;
@GuardedBy("mAnalyzerLock")
private Executor mUserExecutor;
@@ -122,7 +123,9 @@
final ImageProxy rgbImageProxy =
(mOutputImageFormat == OUTPUT_IMAGE_FORMAT_RGBA_8888
&& rgbImageReaderProxy != null)
- ? convertYUVToRGB(imageProxy, rgbImageReaderProxy) : null;
+ ? convertYUVToRGB(
+ imageProxy, rgbImageReaderProxy, mOnePixelShiftEnabled)
+ : null;
// When the analyzer exists and ImageAnalysis is active.
future = CallbackToFutureAdapter.getFuture(
@@ -160,6 +163,10 @@
mOutputImageFormat = outputImageFormat;
}
+ void setOnePixelShiftEnabled(boolean onePixelShiftEnabled) {
+ mOnePixelShiftEnabled = onePixelShiftEnabled;
+ }
+
void setRGBImageReaderProxy(@NonNull ImageReaderProxy rgbImageReaderProxy) {
synchronized (mAnalyzerLock) {
mRGBImageReaderProxy = rgbImageReaderProxy;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageYuvToRgbConverter.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageYuvToRgbConverter.java
index 5270af1..a762f02 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageYuvToRgbConverter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageYuvToRgbConverter.java
@@ -54,12 +54,14 @@
*
* @param imageProxy input image proxy in YUV.
* @param rgbImageReaderProxy output image reader proxy in RGB.
+ * @param onePixelShiftEnabled true if one pixel shift should be applied, otherwise false.
* @return output image proxy in RGB.
*/
@Nullable
public static ImageProxy convertYUVToRGB(
- ImageProxy imageProxy,
- ImageReaderProxy rgbImageReaderProxy) {
+ @NonNull ImageProxy imageProxy,
+ @NonNull ImageReaderProxy rgbImageReaderProxy,
+ boolean onePixelShiftEnabled) {
if (!ImageYuvToRgbConverter.isSupportedYUVFormat(imageProxy)) {
Logger.e(TAG, "Unsupported format for YUV to RGB");
return null;
@@ -67,7 +69,7 @@
// Convert YUV To RGB and write data to surface
ImageYuvToRgbConverter.Result result = convertYUVToRGBInternal(
- imageProxy, rgbImageReaderProxy.getSurface());
+ imageProxy, rgbImageReaderProxy.getSurface(), onePixelShiftEnabled);
if (result == Result.ERROR_CONVERSION) {
Logger.e(TAG, "YUV to RGB conversion failure");
@@ -105,24 +107,30 @@
*
* @param imageProxy input image proxy in YUV.
* @param surface output surface for RGB data.
+ * @param onePixelShiftEnabled true if one pixel shift should be applied, otherwise false.
* @return {@link Result}.
*/
@NonNull
private static Result convertYUVToRGBInternal(
@NonNull ImageProxy imageProxy,
- @NonNull Surface surface) {
+ @NonNull Surface surface,
+ boolean onePixelShiftEnabled) {
if (!isSupportedYUVFormat(imageProxy)) {
return Result.ERROR_FORMAT;
}
int imageWidth = imageProxy.getWidth();
int imageHeight = imageProxy.getHeight();
- int startOffset = 0;
int srcStrideY = imageProxy.getPlanes()[0].getRowStride();
int srcStrideU = imageProxy.getPlanes()[1].getRowStride();
int srcStrideV = imageProxy.getPlanes()[2].getRowStride();
+ int srcPixelStrideY = imageProxy.getPlanes()[0].getPixelStride();
int srcPixelStrideUV = imageProxy.getPlanes()[1].getPixelStride();
+ int startOffsetY = onePixelShiftEnabled ? srcPixelStrideY : 0;
+ int startOffsetU = onePixelShiftEnabled ? srcPixelStrideUV : 0;
+ int startOffsetV = onePixelShiftEnabled ? srcPixelStrideUV : 0;
+
int result = convertAndroid420ToABGR(
imageProxy.getPlanes()[0].getBuffer(),
srcStrideY,
@@ -130,11 +138,14 @@
srcStrideU,
imageProxy.getPlanes()[2].getBuffer(),
srcStrideV,
+ srcPixelStrideY,
srcPixelStrideUV,
surface,
imageWidth,
imageHeight,
- startOffset);
+ startOffsetY,
+ startOffsetU,
+ startOffsetV);
if (result != 0) {
return Result.ERROR_CONVERSION;
}
@@ -150,11 +161,14 @@
* @param srcStrideU Source U row stride.
* @param srcByteBufferV Source V data.
* @param srcStrideV Source V row stride.
+ * @param srcPixelStrideY Pixel stride for Y.
* @param srcPixelStrideUV Pixel stride for UV.
* @param surface Destination surface for ABGR data.
* @param width Destination image width.
* @param height Destination image height.
- * @param startOffset Position in source data to begin reading from.
+ * @param startOffsetY Position in Y source data to begin reading from.
+ * @param startOffsetU Position in U source data to begin reading from.
+ * @param startOffsetV Position in V source data to begin reading from.
* @return zero if succeeded, otherwise non-zero.
*/
private static native int convertAndroid420ToABGR(
@@ -164,10 +178,13 @@
int srcStrideU,
@NonNull ByteBuffer srcByteBufferV,
int srcStrideV,
+ int srcPixelStrideY,
int srcPixelStrideUV,
@NonNull Surface surface,
int width,
int height,
- int startOffset);
+ int startOffsetY,
+ int startOffsetU,
+ int startOffsetV);
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
index 70a24af..1b891d9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
@@ -1143,6 +1143,7 @@
}
/** Set audio record parameters by CamcorderProfile */
+ @SuppressWarnings("deprecation")
private void setAudioParametersByCamcorderProfile(Size currentResolution, String cameraId) {
CamcorderProfile profile;
boolean isCamcorderProfileFound = false;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java
index a6f1523d..7a9196b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java
@@ -18,6 +18,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.Preview;
@@ -42,6 +43,9 @@
Option<Integer> OPTION_USE_CASE_COMBINATION_REQUIRED_RULE =
Option.create("camerax.core.camera.useCaseCombinationRequiredRule", Integer.class);
+ Option<SessionProcessor> OPTION_SESSION_PROCESSOR =
+ Option.create("camerax.core.camera.SessionProcessor", SessionProcessor.class);
+
/**
* No rule is required when the camera is opened by the camera config.
*/
@@ -65,7 +69,9 @@
* Retrieves the use case config factory instance.
*/
@NonNull
- UseCaseConfigFactory getUseCaseConfigFactory();
+ default UseCaseConfigFactory getUseCaseConfigFactory() {
+ return retrieveOption(OPTION_USECASE_CONFIG_FACTORY, UseCaseConfigFactory.EMPTY_INSTANCE);
+ }
/**
* Retrieves the compatibility {@link Identifier}.
@@ -82,11 +88,37 @@
*/
@RequiredRule
default int getUseCaseCombinationRequiredRule() {
- return REQUIRED_RULE_NONE;
+ return retrieveOption(OPTION_USE_CASE_COMBINATION_REQUIRED_RULE, REQUIRED_RULE_NONE);
+ }
+
+ /**
+ * Returns the session processor which will transform the stream configurations and
+ * will perform the repeating request and still capture request when being requested by CameraX.
+ *
+ * @param valueIfMissing The value to return if this configuration option has not been set.
+ * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
+ * configuration.
+ */
+ @Nullable
+ default SessionProcessor getSessionProcessor(@Nullable SessionProcessor valueIfMissing) {
+ return retrieveOption(OPTION_SESSION_PROCESSOR, valueIfMissing);
+ }
+
+ /**
+ * Returns the session processor which will transform the stream configurations and will
+ * perform the repeating request and still capture request when being requested by CameraX.
+ *
+ * @return The stored value, if it exists in this configuration.
+ * @throws IllegalArgumentException if the option does not exist in this configuration.
+ */
+ @NonNull
+ default SessionProcessor getSessionProcessor() {
+ return retrieveOption(OPTION_SESSION_PROCESSOR);
}
/**
* Builder for creating a {@link CameraConfig}.
+ *
* @param <B> the top level builder type for which this builder is composed with.
*/
interface Builder<B> {
@@ -107,5 +139,12 @@
*/
@NonNull
B setUseCaseCombinationRequiredRule(@RequiredRule int useCaseCombinationRequiredRule);
+
+ /**
+ * Sets the session processor which will transform the stream configurations and will
+ * perform the repeating request and still capture request when being requested by CameraX.
+ */
+ @NonNull
+ B setSessionProcessor(@NonNull SessionProcessor sessionProcessor);
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfigs.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfigs.java
index d0f7fae..fd99c72c9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfigs.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfigs.java
@@ -17,7 +17,6 @@
package androidx.camera.core.impl;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
/**
* Utility methods for operating on {@link CameraConfig} instances.
@@ -34,32 +33,13 @@
}
static final class EmptyCameraConfig implements CameraConfig {
- private final UseCaseConfigFactory mUseCaseConfigFactory = new UseCaseConfigFactory() {
- /**
- * Returns the configuration for the given capture type, or <code>null</code> if the
- * configuration cannot be produced.
- */
- @Nullable
- @Override
- public Config getConfig(@NonNull CaptureType captureType) {
- return null;
- }
- };
-
private final Identifier mIdentifier = Identifier.create(new Object());
@NonNull
@Override
- public UseCaseConfigFactory getUseCaseConfigFactory() {
- return mUseCaseConfigFactory;
- }
-
- @NonNull
- @Override
public Identifier getCompatibilityId() {
return mIdentifier;
}
-
@NonNull
@Override
public Config getConfig() {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageAnalysisConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageAnalysisConfig.java
index d558a7d..a53a1f6 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageAnalysisConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageAnalysisConfig.java
@@ -50,6 +50,9 @@
public static final Option<Integer> OPTION_OUTPUT_IMAGE_FORMAT =
Option.create("camerax.core.imageAnalysis.outputImageFormat",
ImageAnalysis.OutputImageFormat.class);
+ public static final Option<Boolean> OPTION_ONE_PIXEL_SHIFT_ENABLED =
+ Option.create("camerax.core.imageAnalysis.onePixelShiftEnabled",
+ Boolean.class);
// *********************************************************************************************
@@ -142,6 +145,17 @@
}
/**
+ * Gets if one pixel shift is requested or not.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Boolean getOnePixelShiftEnabled(@Nullable Boolean valueIfMissing) {
+ return retrieveOption(OPTION_ONE_PIXEL_SHIFT_ENABLED, valueIfMissing);
+ }
+
+ /**
* Gets the caller provided {@link ImageReaderProxy}.
*
* @hide
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/OutputSurface.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/OutputSurface.java
new file mode 100644
index 0000000..4d633f9
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/OutputSurface.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.core.impl;
+
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * A class wrapping output surface information for initializing {@link SessionProcessor}.
+ */
+@AutoValue
+public abstract class OutputSurface {
+ /**
+ * Creates an OutputSurface instance.
+ */
+ @NonNull
+ public static OutputSurface create(
+ @NonNull Surface surface, @NonNull Size size, int imageFormat) {
+ return new AutoValue_OutputSurface(surface, size, imageFormat);
+ }
+
+ /**
+ * Gets the {@link Surface}.
+ */
+ @NonNull
+ public abstract Surface getSurface();
+
+ /**
+ * Gets the size of the {@link Surface}.
+ */
+ @NonNull
+ public abstract Size getSize();
+
+ /**
+ * Gets the image format of the {@link Surface}.
+ */
+ public abstract int getImageFormat();
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/RequestProcessor.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/RequestProcessor.java
new file mode 100644
index 0000000..03f8543
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/RequestProcessor.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.core.impl;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * A wrapper provided to {@link SessionProcessor} to execute camera requests.
+ *
+ * <p>When the {@link SessionProcessor#startRepeating(SessionProcessor.CaptureCallback)} or
+ * {@link SessionProcessor#startCapture(SessionProcessor.CaptureCallback)} is called, it can
+ * invoke the APIs in this class to submit camera requests to achieve the required functionality.
+ *
+ * <p>The images to be fetched is managed inside {@link SessionProcessor}.
+ */
+public interface RequestProcessor {
+ /**
+ * Submit a request. Returning true if request is submitted or false otherwise.
+ */
+ boolean submit(@NonNull Request request,
+ @NonNull Callback callback);
+
+ /**
+ * Submit a list of requests. Returning true if request is submitted or false otherwise.
+ */
+ boolean submit(@NonNull List<Request> requests,
+ @NonNull Callback callback);
+
+ /**
+ * Set a repeating request. Returning true if request is submitted or false otherwise.
+ */
+ boolean setRepeating(@NonNull Request request,
+ @NonNull Callback callback);
+
+ /**
+ * Abort captures
+ */
+ void abortCaptures();
+
+ /**
+ * Stop repeating requests.
+ */
+ void stopRepeating();
+
+ /**
+ * A interface representing a capture request configuration used for submitting requests in
+ * {@link RequestProcessor}.
+ */
+ interface Request {
+ /**
+ * Gets the target ids of the outputConfig which identifies corresponding
+ * Surface to be the targeted for the request.
+ */
+ @NonNull
+ List<Integer> getTargetOutputConfigIds();
+
+ /**
+ * Gets all the parameters.
+ */
+ @NonNull
+ Config getParameters();
+
+ /**
+ * Gets the template id.
+ */
+ int getTemplateId();
+ }
+
+ /**
+ * Callback to be invoked during the capture.
+ */
+ interface Callback {
+ void onCaptureStarted(
+ @NonNull Request request,
+ long frameNumber,
+ long timestamp);
+
+ void onCaptureProgressed(
+ @NonNull Request request,
+ @NonNull CameraCaptureResult captureResult);
+
+ void onCaptureCompleted(
+ @NonNull Request request,
+ @Nullable CameraCaptureResult captureResult);
+
+ void onCaptureFailed(
+ @NonNull Request request,
+ @Nullable CameraCaptureFailure captureFailure);
+
+ void onCaptureBufferLost(
+ @NonNull Request request,
+ long frameNumber,
+ int outputStreamId);
+
+ void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
+
+ void onCaptureSequenceAborted(int sequenceId);
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/SessionProcessor.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/SessionProcessor.java
new file mode 100644
index 0000000..6bbf57c
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/SessionProcessor.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.core.impl;
+
+import android.media.ImageReader;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.core.CameraInfo;
+
+/**
+ * A processor for (1) transforming the surfaces used in Preview/ImageCapture/ImageAnalysis
+ * into final session configuration where intermediate {@link ImageReader}s could be created for
+ * processing the image and writing the result to output surfaces (2) performing repeating request
+ * and still image capture by using {@link RequestProcessor}.
+ *
+ * <p>A {@link RequestProcessor} will be passed to the {@link SessionProcessor} when
+ * {@link SessionProcessor#onCaptureSessionStart(RequestProcessor)} is called to execute camera
+ * requests. When being requested to execute repeating request or still capture, the
+ * SessionProcessor can set any target surfaces and parameters it needs. It can also send
+ * multiple requests if necessary.
+ *
+ * <p>The SessionProcessor is expected to release all intermediate {@link ImageReader}s when
+ * {@link #deInitSession()} is called.
+ */
+public interface SessionProcessor {
+ /**
+ * Initializes the session and returns a transformed {@link SessionConfig} which should be
+ * used to configure the camera instead of original one.
+ *
+ * <p>Output surfaces of preview, image capture and imageAnalysis should be passed in. The
+ * SessionProcessor is responsible to write the output to this given output surfaces.
+ *
+ * @param cameraInfo cameraInfo for querying the camera info
+ * @param previewSurfaceConfig output surface for preview. This is mandatory.
+ * @param imageCaptureSurfaceConfig output surface for image capture. This is mandatory.
+ * @param imageAnalysisSurfaceConfig output surface for image analysis. This is optional.
+ * Passing null if image analysis output is not needed.
+ * @return a {@link SessionConfig} that contains the surfaces and the session parameters and
+ * should be used to configure the camera session.
+ */
+ @NonNull
+ SessionConfig initSession(
+ @NonNull CameraInfo cameraInfo,
+ @NonNull OutputSurface previewSurfaceConfig,
+ @NonNull OutputSurface imageCaptureSurfaceConfig,
+ @Nullable OutputSurface imageAnalysisSurfaceConfig);
+
+ /**
+ * De-initializes the session. This is called after the camera session is closed.
+ */
+ void deInitSession();
+
+ /**
+ * Sets the camera parameters to be enabled in every single and repeating request.
+ */
+ void setParameters(@NonNull Config config);
+
+ /**
+ * Notifies the SessionProcessor that the camera session is just started. A
+ * {@link RequestProcessor} is provided to execute camera requests.
+ */
+ void onCaptureSessionStart(
+ @NonNull RequestProcessor requestProcessor);
+
+ /**
+ * Notifies the SessionProcessor that the camera session is going to be closed.
+ * {@link RequestProcessor} will no longer accept any requests
+ * after onCaptureSessionEnd() returns.
+ */
+ void onCaptureSessionEnd();
+
+ /**
+ * Requests the SessionProcessor to start the repeating request that enables
+ * preview and image analysis.
+ *
+ * @param callback callback to notify the status.
+ * @return the id of the capture sequence.
+ */
+ int startRepeating(@NonNull CaptureCallback callback);
+
+
+ /**
+ * Stop the repeating request.
+ */
+ void stopRepeating();
+
+ /**
+ * Requests the SessionProcessor to start the still image capture. The capture task can only
+ * perform one at a time.
+ *
+ * @param callback callback to notify the status.
+ * @return the id of the capture sequence.
+ */
+ int startCapture(
+ @NonNull CaptureCallback callback);
+
+ /**
+ * Aborts the pending capture.
+ */
+ void abortCapture(int captureSequenceId);
+
+ /**
+ * Callback for {@link #startRepeating} and {@link #startCapture}.
+ */
+ interface CaptureCallback {
+ /**
+ * This method is called when the camera has started capturing the initial input
+ * image.
+ *
+ * For a multi-frame capture, the method is called when the onCaptureStarted of first
+ * frame is called and its timestamp is directly forwarded to timestamp parameter of
+ * this method.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ * @param timestamp the timestamp at start of capture for repeating
+ * request or the timestamp at start of capture of the
+ * first frame in a multi-frame capture, in nanoseconds.
+ */
+ void onCaptureStarted(int captureSequenceId, long timestamp);
+
+ /**
+ * This method is called when an image (or images in case of multi-frame
+ * capture) is captured and device-specific extension processing is triggered.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureProcessStarted(int captureSequenceId);
+
+ /**
+ * This method is called instead of {@link #onCaptureProcessStarted} when the camera
+ * device failed to produce the required input image. The cause could be a failed camera
+ * capture request, a failed capture result or dropped camera frame.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureFailed(int captureSequenceId);
+
+ /**
+ * This method is called independently of the others in the CaptureCallback, when a capture
+ * sequence finishes.
+ *
+ * <p>In total, there will be at least one {@link #onCaptureProcessStarted}/
+ * {@link #onCaptureFailed} invocation before this callback is triggered. If the capture
+ * sequence is aborted before any requests have begun processing,
+ * {@link #onCaptureSequenceAborted} is invoked instead.</p>
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceCompleted(int captureSequenceId);
+
+ /**
+ * This method is called when a capture sequence aborts.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceAborted(int captureSequenceId);
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java
index 3362559..ea5df64 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java
@@ -71,4 +71,12 @@
*/
@Nullable
Config getConfig(@NonNull CaptureType captureType);
+
+ UseCaseConfigFactory EMPTY_INSTANCE = new UseCaseConfigFactory() {
+ @Nullable
+ @Override
+ public Config getConfig(@NonNull CaptureType captureType) {
+ return null;
+ }
+ };
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index c4c8c5b..09b6da7 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -559,6 +559,9 @@
}
mCameraConfig = cameraConfig;
+
+ //Configure the CameraInternal as well so that it can get SessionProcessor.
+ mCameraInternal.setExtendedConfig(mCameraConfig);
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/OnePixelShiftQuirk.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/OnePixelShiftQuirk.java
new file mode 100644
index 0000000..70adcc1
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/OnePixelShiftQuirk.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.core.internal.compat.quirk;
+
+import androidx.camera.core.impl.Quirk;
+
+/**
+ * A Quirk interface which enables one pixel shift for YUV data when converting to RGB.
+ * More details in b/184229033.
+ *
+ * <p>Subclasses of this quirk may contain device specific information.
+ */
+public interface OnePixelShiftQuirk extends Quirk {
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
index e5404ef..b917b5f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
@@ -146,6 +146,7 @@
/** Crops byte array with given {@link android.graphics.Rect}. */
@NonNull
+ @SuppressWarnings("deprecation")
public static byte[] cropByteArray(@NonNull byte[] data, @Nullable Rect cropRect)
throws CodecFailedException {
if (cropRect == null) {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java b/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java
index 90f3979..1db4883 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java
@@ -70,6 +70,14 @@
}
@Test
+ public void canSetNullValue() {
+ MutableOptionsBundle bundle = MutableOptionsBundle.create();
+ bundle.insertOption(OPTION_1, null);
+
+ assertThat(bundle.retrieveOption(OPTION_1)).isNull();
+ }
+
+ @Test
public void canCreateFromConfiguration_andAddMore() {
MutableOptionsBundle mutOpts = MutableOptionsBundle.create();
mutOpts.insertOption(OPTION_1, REQUIRED, VALUE_2);
diff --git a/camera/camera-core/src/test/resources/robolectric.properties b/camera/camera-core/src/test/resources/robolectric.properties
index 3f2e0d0..5fad9a0 100644
--- a/camera/camera-core/src/test/resources/robolectric.properties
+++ b/camera/camera-core/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
\ No newline at end of file
+sdk=30
\ No newline at end of file
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
index a0f6085..c6eba34 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
@@ -37,18 +37,25 @@
/**
* Submits a request.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives and invalid argument.
*/
- boolean submit(Request request, Callback callback);
+ int submit(Request request, Callback callback);
/**
* Submits a list of requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives and invalid argument.
*/
- boolean submit(List<Request> requests, Callback callback);
+ int submit(List<Request> requests, Callback callback);
/**
* Set repeating requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives and invalid argument.
*/
- boolean setRepeating(Request request, Callback callback);
+ int setRepeating(Request request, Callback callback);
+
/**
* Abort captures.
diff --git a/camera/camera-extensions/lint-baseline.xml b/camera/camera-extensions/lint-baseline.xml
new file mode 100644
index 0000000..c2a1cfa
--- /dev/null
+++ b/camera/camera-extensions/lint-baseline.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" Camera2ImplConfig.Builder camera2ConfigurationBuilder = new Camera2ImplConfig.Builder();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/extensions/internal/AdaptingCaptureStage.java"
+ line="38"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" camera2ConfigurationBuilder.setCaptureRequestOption(captureParameter.first,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/extensions/internal/AdaptingCaptureStage.java"
+ line="41"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" captureConfigBuilder.addImplementationOptions(camera2ConfigurationBuilder.build());"
+ errorLine2=" ~~~~~">
+ <location
+ file="src/main/java/androidx/camera/extensions/internal/AdaptingCaptureStage.java"
+ line="46"
+ column="83"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java"
+ line="110"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java"
+ line="110"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java"
+ line="110"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
+ errorLine1=" new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java"
+ line="110"
+ column="55"/>
+ </issue>
+
+</issues>
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java
index c1375e0..e44e5cc 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java
@@ -21,16 +21,15 @@
import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.Identifier;
import androidx.camera.core.impl.MutableOptionsBundle;
-import androidx.camera.core.impl.ReadableConfig;
+import androidx.camera.core.impl.SessionProcessor;
import androidx.camera.core.impl.UseCaseConfigFactory;
/**
* Implementation of CameraConfig which provides the extensions capability.
*/
-class ExtensionsConfig implements ReadableConfig, CameraConfig {
+class ExtensionsConfig implements CameraConfig {
// Option Declarations:
// *********************************************************************************************
-
public static final Option<Integer> OPTION_EXTENSION_MODE =
Option.create(
"camerax.extensions.extensionMode", int.class);
@@ -52,23 +51,12 @@
return retrieveOption(OPTION_EXTENSION_MODE);
}
- @Override
- @NonNull
- public UseCaseConfigFactory getUseCaseConfigFactory() {
- return retrieveOption(OPTION_USECASE_CONFIG_FACTORY);
- }
-
@NonNull
@Override
public Identifier getCompatibilityId() {
return retrieveOption(OPTION_COMPATIBILITY_ID);
}
- @Override
- public int getUseCaseCombinationRequiredRule() {
- return retrieveOption(OPTION_USE_CASE_COMBINATION_REQUIRED_RULE);
- }
-
static final class Builder implements CameraConfig.Builder<Builder> {
private final MutableOptionsBundle mConfig = MutableOptionsBundle.create();
@@ -102,5 +90,12 @@
useCaseCombinationRequiredRule);
return this;
}
+
+ @NonNull
+ @Override
+ public Builder setSessionProcessor(@NonNull SessionProcessor sessionProcessor) {
+ mConfig.insertOption(OPTION_SESSION_PROCESSOR, sessionProcessor);
+ return this;
+ }
}
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
index 5438a2b..3312813 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
@@ -33,6 +33,7 @@
import androidx.camera.core.impl.CameraConfigProvider;
import androidx.camera.core.impl.ExtendedCameraConfigProviderStore;
import androidx.camera.core.impl.Identifier;
+import androidx.camera.core.impl.SessionProcessor;
import androidx.camera.extensions.internal.AdvancedVendorExtender;
import androidx.camera.extensions.internal.BasicVendorExtender;
import androidx.camera.extensions.internal.ExtensionVersion;
@@ -217,13 +218,19 @@
ExtensionsUseCaseConfigFactory factory = new
ExtensionsUseCaseConfigFactory(mode, vendorExtender, context);
- return new ExtensionsConfig.Builder()
+ ExtensionsConfig.Builder builder = new ExtensionsConfig.Builder()
.setExtensionMode(mode)
.setUseCaseConfigFactory(factory)
.setCompatibilityId(id)
.setUseCaseCombinationRequiredRule(
- CameraConfig.REQUIRED_RULE_COEXISTING_PREVIEW_AND_IMAGE_CAPTURE)
- .build();
+ CameraConfig.REQUIRED_RULE_COEXISTING_PREVIEW_AND_IMAGE_CAPTURE);
+
+ SessionProcessor sessionProcessor = vendorExtender.createSessionProcessor(context);
+ if (sessionProcessor != null) {
+ builder.setSessionProcessor(sessionProcessor);
+ }
+
+ return builder.build();
});
}
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
index b231ccb..3e74c77 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
@@ -178,6 +178,15 @@
+ "are missed in the vendor library. " + e);
completer.set(getOrCreateExtensionsManager(
ExtensionsAvailability.LIBRARY_UNAVAILABLE_MISSING_IMPLEMENTATION));
+ } catch (RuntimeException e) {
+ // Catches all unexpected runtime exceptions and still returns an
+ // ExtensionsManager instance which performs default behavior.
+ Logger.e(TAG,
+ "Failed to initialize extensions. Something wents wrong when "
+ + "initializing the vendor library. "
+ + e);
+ completer.set(getOrCreateExtensionsManager(
+ ExtensionsAvailability.LIBRARY_UNAVAILABLE_ERROR_LOADING));
}
return "Initialize extensions";
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/AdvancedVendorExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/AdvancedVendorExtender.java
index 09fe8e9..9dc6d62 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/AdvancedVendorExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/AdvancedVendorExtender.java
@@ -16,6 +16,7 @@
package androidx.camera.extensions.internal;
+import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.util.Pair;
@@ -28,6 +29,7 @@
import androidx.camera.camera2.interop.Camera2CameraInfo;
import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
import androidx.camera.core.CameraInfo;
+import androidx.camera.core.impl.SessionProcessor;
import androidx.camera.extensions.ExtensionMode;
import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.AutoAdvancedExtenderImpl;
@@ -137,4 +139,12 @@
List<Size> yuvList = mAdvancedExtenderImpl.getSupportedYuvAnalysisResolutions(mCameraId);
return yuvList == null ? new Size[0] : yuvList.toArray(new Size[0]);
}
+
+ @Nullable
+ @Override
+ public SessionProcessor createSessionProcessor(@NonNull Context context) {
+ Preconditions.checkNotNull(mCameraId, "VendorExtender#init() must be called first");
+ //TODO: To be implemented in later CLs.
+ return null;
+ }
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
index 8fa3e27..227295f 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
@@ -16,6 +16,7 @@
package androidx.camera.extensions.internal;
+import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -30,6 +31,7 @@
import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.Logger;
+import androidx.camera.core.impl.SessionProcessor;
import androidx.camera.extensions.ExtensionMode;
import androidx.camera.extensions.impl.AutoImageCaptureExtenderImpl;
import androidx.camera.extensions.impl.AutoPreviewExtenderImpl;
@@ -85,7 +87,7 @@
break;
case ExtensionMode.NONE:
default:
- throw new IllegalArgumentException("Should not active ExtensionMode.NONE");
+ throw new IllegalArgumentException("Should not activate ExtensionMode.NONE");
}
} catch (NoClassDefFoundError e) {
throw new IllegalArgumentException("Extension mode does not exist: " + mode);
@@ -163,6 +165,7 @@
return ImageFormat.PRIVATE;
}
}
+
private int getCaptureInputImageFormat() {
if (mImageCaptureExtenderImpl.getCaptureProcessor() != null) {
return ImageFormat.YUV_420_888;
@@ -223,4 +226,14 @@
Preconditions.checkNotNull(mCameraInfo, "VendorExtender#init() must be called first");
return getOutputSizes(ImageFormat.YUV_420_888);
}
+
+ @Nullable
+ @Override
+ public SessionProcessor createSessionProcessor(@NonNull Context context) {
+ Preconditions.checkNotNull(mCameraInfo, "VendorExtender#init() must be called first");
+ /* Return null to keep using existing flow for basic extender to ensure compatibility for
+ * now. We will switch to SessionProcessor implementation once compatibility is ensured.
+ */
+ return null;
+ }
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionsUseCaseConfigFactory.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionsUseCaseConfigFactory.java
index 7ffe9ef..d3180d1 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionsUseCaseConfigFactory.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionsUseCaseConfigFactory.java
@@ -38,15 +38,8 @@
@ExtensionMode.Mode int mode,
@NonNull VendorExtender vendorExtender,
@NonNull Context context) {
- if (vendorExtender instanceof BasicVendorExtender) {
- BasicVendorExtender basicVendorExtender = (BasicVendorExtender) vendorExtender;
- mImageCaptureConfigProvider = new ImageCaptureConfigProvider(
- mode, basicVendorExtender, context);
- mPreviewConfigProvider = new PreviewConfigProvider(
- mode, basicVendorExtender, context);
- } else {
- throw new UnsupportedOperationException("Advanced extender implementation not ready");
- }
+ mImageCaptureConfigProvider = new ImageCaptureConfigProvider(mode, vendorExtender, context);
+ mPreviewConfigProvider = new PreviewConfigProvider(mode, vendorExtender, context);
}
/**
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
index ba3c9ff..c51e759 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
@@ -41,7 +41,6 @@
import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ConfigProvider;
import androidx.camera.core.impl.ImageCaptureConfig;
-import androidx.camera.core.impl.OptionsBundle;
import androidx.camera.extensions.ExtensionMode;
import androidx.camera.extensions.impl.CaptureProcessorImpl;
import androidx.camera.extensions.impl.CaptureStageImpl;
@@ -60,15 +59,15 @@
Config.Option.create("camerax.extensions.imageCaptureConfigProvider.mode",
Integer.class);
- private final BasicVendorExtender mVendorExtender;
+ private final VendorExtender mVendorExtender;
private final Context mContext;
@ExtensionMode.Mode
- private int mEffectMode;
+ private final int mEffectMode;
@OptIn(markerClass = ExperimentalCamera2Interop.class)
public ImageCaptureConfigProvider(
@ExtensionMode.Mode int mode,
- @NonNull BasicVendorExtender vendorExtender,
+ @NonNull VendorExtender vendorExtender,
@NonNull Context context) {
mEffectMode = mode;
mVendorExtender = vendorExtender;
@@ -78,12 +77,7 @@
@NonNull
@Override
public ImageCaptureConfig getConfig() {
- if (mVendorExtender == null) {
- return new ImageCaptureConfig(OptionsBundle.emptyBundle());
- }
-
ImageCapture.Builder builder = new ImageCapture.Builder();
-
updateBuilderConfig(builder, mEffectMode, mVendorExtender, mContext);
return builder.getUseCaseConfig();
@@ -93,29 +87,35 @@
* Update extension related configs to the builder.
*/
void updateBuilderConfig(@NonNull ImageCapture.Builder builder,
- @ExtensionMode.Mode int effectMode, @NonNull BasicVendorExtender vendorExtender,
+ @ExtensionMode.Mode int effectMode, @NonNull VendorExtender vendorExtender,
@NonNull Context context) {
- CaptureProcessorImpl captureProcessor =
- vendorExtender.getImageCaptureExtenderImpl().getCaptureProcessor();
- if (captureProcessor != null) {
- builder.setCaptureProcessor(new AdaptingCaptureProcessor(captureProcessor));
+ if (vendorExtender instanceof BasicVendorExtender) {
+ ImageCaptureExtenderImpl imageCaptureExtenderImpl =
+ ((BasicVendorExtender) vendorExtender).getImageCaptureExtenderImpl();
+
+ CaptureProcessorImpl captureProcessor =
+ imageCaptureExtenderImpl.getCaptureProcessor();
+ if (captureProcessor != null) {
+ builder.setCaptureProcessor(new AdaptingCaptureProcessor(captureProcessor));
+ }
+
+ if (imageCaptureExtenderImpl.getMaxCaptureStage() > 0) {
+ builder.setMaxCaptureStages(
+ imageCaptureExtenderImpl.getMaxCaptureStage());
+ }
+
+ ImageCaptureEventAdapter imageCaptureEventAdapter =
+ new ImageCaptureEventAdapter(imageCaptureExtenderImpl,
+ context);
+ new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
+ new CameraEventCallbacks(imageCaptureEventAdapter));
+ builder.setUseCaseEventCallback(imageCaptureEventAdapter);
+
+ builder.setCaptureBundle(imageCaptureEventAdapter);
}
- if (vendorExtender.getImageCaptureExtenderImpl().getMaxCaptureStage() > 0) {
- builder.setMaxCaptureStages(
- vendorExtender.getImageCaptureExtenderImpl().getMaxCaptureStage());
- }
-
- ImageCaptureEventAdapter imageCaptureEventAdapter =
- new ImageCaptureEventAdapter(vendorExtender.getImageCaptureExtenderImpl(), context);
- new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
- new CameraEventCallbacks(imageCaptureEventAdapter));
- builder.setUseCaseEventCallback(imageCaptureEventAdapter);
-
- builder.setCaptureBundle(imageCaptureEventAdapter);
builder.getMutableConfig().insertOption(OPTION_IMAGE_CAPTURE_CONFIG_PROVIDER_MODE,
effectMode);
-
List<Pair<Integer, Size[]>> supportedResolutions =
vendorExtender.getSupportedCaptureOutputResolutions();
builder.setSupportedResolutions(supportedResolutions);
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
index 0aaa41a..0d21105 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
@@ -38,7 +38,6 @@
import androidx.camera.core.impl.CaptureConfig;
import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ConfigProvider;
-import androidx.camera.core.impl.OptionsBundle;
import androidx.camera.core.impl.PreviewConfig;
import androidx.camera.extensions.ExtensionMode;
import androidx.camera.extensions.impl.CaptureStageImpl;
@@ -54,15 +53,15 @@
private static final String TAG = "PreviewConfigProvider";
static final Config.Option<Integer> OPTION_PREVIEW_CONFIG_PROVIDER_MODE = Config.Option.create(
"camerax.extensions.previewConfigProvider.mode", Integer.class);
- private final BasicVendorExtender mVendorExtender;
- private Context mContext;
+ private final VendorExtender mVendorExtender;
+ private final Context mContext;
@ExtensionMode.Mode
- private int mEffectMode;
+ private final int mEffectMode;
@OptIn(markerClass = ExperimentalCamera2Interop.class)
public PreviewConfigProvider(
@ExtensionMode.Mode int mode,
- @NonNull BasicVendorExtender vendorExtender,
+ @NonNull VendorExtender vendorExtender,
@NonNull Context context) {
mEffectMode = mode;
mVendorExtender = vendorExtender;
@@ -72,11 +71,7 @@
@NonNull
@Override
public PreviewConfig getConfig() {
- if (mVendorExtender == null) {
- return new PreviewConfig(OptionsBundle.emptyBundle());
- }
Preview.Builder builder = new Preview.Builder();
-
updateBuilderConfig(builder, mEffectMode, mVendorExtender, mContext);
return builder.getUseCaseConfig();
@@ -86,34 +81,37 @@
* Update extension related configs to the builder.
*/
void updateBuilderConfig(@NonNull Preview.Builder builder,
- @ExtensionMode.Mode int effectMode, @NonNull BasicVendorExtender vendorExtender,
+ @ExtensionMode.Mode int effectMode, @NonNull VendorExtender vendorExtender,
@NonNull Context context) {
- PreviewEventAdapter previewEventAdapter;
-
- PreviewExtenderImpl previewExtenderImpl = vendorExtender.getPreviewExtenderImpl();
- switch (vendorExtender.getPreviewExtenderImpl().getProcessorType()) {
- case PROCESSOR_TYPE_REQUEST_UPDATE_ONLY:
- AdaptingRequestUpdateProcessor adaptingRequestUpdateProcessor =
- new AdaptingRequestUpdateProcessor(previewExtenderImpl);
- builder.setImageInfoProcessor(adaptingRequestUpdateProcessor);
- previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
- adaptingRequestUpdateProcessor);
- break;
- case PROCESSOR_TYPE_IMAGE_PROCESSOR:
- AdaptingPreviewProcessor adaptingPreviewProcessor = new
- AdaptingPreviewProcessor(
- (PreviewImageProcessorImpl) previewExtenderImpl.getProcessor());
- builder.setCaptureProcessor(adaptingPreviewProcessor);
- previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
- adaptingPreviewProcessor);
- break;
- default:
- previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context, null);
+ if (vendorExtender instanceof BasicVendorExtender) {
+ PreviewEventAdapter previewEventAdapter;
+ PreviewExtenderImpl previewExtenderImpl =
+ ((BasicVendorExtender) vendorExtender).getPreviewExtenderImpl();
+ switch (previewExtenderImpl.getProcessorType()) {
+ case PROCESSOR_TYPE_REQUEST_UPDATE_ONLY:
+ AdaptingRequestUpdateProcessor adaptingRequestUpdateProcessor =
+ new AdaptingRequestUpdateProcessor(previewExtenderImpl);
+ builder.setImageInfoProcessor(adaptingRequestUpdateProcessor);
+ previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
+ adaptingRequestUpdateProcessor);
+ break;
+ case PROCESSOR_TYPE_IMAGE_PROCESSOR:
+ AdaptingPreviewProcessor adaptingPreviewProcessor = new
+ AdaptingPreviewProcessor(
+ (PreviewImageProcessorImpl) previewExtenderImpl.getProcessor());
+ builder.setCaptureProcessor(adaptingPreviewProcessor);
+ previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
+ adaptingPreviewProcessor);
+ break;
+ default:
+ previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
+ null);
+ }
+ new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
+ new CameraEventCallbacks(previewEventAdapter));
+ builder.setUseCaseEventCallback(previewEventAdapter);
}
- new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
- new CameraEventCallbacks(previewEventAdapter));
- builder.setUseCaseEventCallback(previewEventAdapter);
builder.getMutableConfig().insertOption(OPTION_PREVIEW_CONFIG_PROVIDER_MODE, effectMode);
List<Pair<Integer, Size[]>> supportedResolutions =
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/VendorExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/VendorExtender.java
index 6f9bf99..81b5807 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/VendorExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/VendorExtender.java
@@ -16,6 +16,7 @@
package androidx.camera.extensions.internal;
+import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.util.Pair;
@@ -25,6 +26,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.CameraInfo;
+import androidx.camera.core.impl.SessionProcessor;
import java.util.List;
import java.util.Map;
@@ -106,4 +108,12 @@
*/
@NonNull
Size[] getSupportedYuvAnalysisResolutions();
+
+ /**
+ * Creates a {@link SessionProcessor} that is responsible for (1) determining the stream
+ * configuration based on given output surfaces (2) Requesting OEM implementation to start
+ * repeating request and performing a still image capture.
+ */
+ @Nullable
+ SessionProcessor createSessionProcessor(@NonNull Context context);
}
diff --git a/camera/camera-testing/lint-baseline.xml b/camera/camera-testing/lint-baseline.xml
index d112ce8..b2a3ecc 100644
--- a/camera/camera-testing/lint-baseline.xml
+++ b/camera/camera-testing/lint-baseline.xml
@@ -1,16 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" public static CameraManager getCameraManager() {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/testing/CameraUtil.java"
- line="258"
- column="19"/>
- </issue>
+<issues format="6" by="lint 7.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-alpha07)" variant="all" version="7.1.0-alpha07">
<issue
id="UnknownNullness"
diff --git a/camera/camera-testing/src/main/AndroidManifest.xml b/camera/camera-testing/src/main/AndroidManifest.xml
index 958dea7..6fb4156 100644
--- a/camera/camera-testing/src/main/AndroidManifest.xml
+++ b/camera/camera-testing/src/main/AndroidManifest.xml
@@ -16,11 +16,11 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.camera.testing">
- <uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
<uses-permission android:name="android.permission.CAMERA" />
<application>
<activity
android:name="androidx.camera.testing.activity.ForegroundTestActivity"
+ android:exported="true"
android:label="ForegroundTestActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -29,6 +29,7 @@
</activity>
<activity
android:name="androidx.camera.testing.activity.CameraXTestActivity"
+ android:exported="true"
android:label="CameraX TestActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -37,6 +38,7 @@
</activity>
<activity
android:name="androidx.camera.testing.activity.Camera2TestActivity"
+ android:exported="true"
android:label="Camera2 TestActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/CoreAppTestUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/CoreAppTestUtil.java
index 876b212..451b33b 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/CoreAppTestUtil.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/CoreAppTestUtil.java
@@ -16,6 +16,7 @@
package androidx.camera.testing;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Instrumentation;
import android.app.KeyguardManager;
@@ -81,6 +82,7 @@
* Clean up the device UI and back to the home screen for test.
* @param instrumentation the instrumentation used to run the test
*/
+ @SuppressLint("MissingPermission") // Permission needed for action_close_system_dialogs in S
@SuppressWarnings("deprecation")
public static void clearDeviceUI(@NonNull Instrumentation instrumentation) {
UiDevice device = UiDevice.getInstance(instrumentation);
@@ -110,8 +112,10 @@
device.waitForIdle(MAX_TIMEOUT_MS);
// Close system dialogs first to avoid interrupt.
- instrumentation.getTargetContext().sendBroadcast(
- new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
+ instrumentation.getTargetContext().sendBroadcast(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ }
}
/**
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
index 8704eb4..d0c7010 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
@@ -468,6 +468,7 @@
val outputOptions = FileOutputOptions.builder().setFile(file).build()
val pendingRecording = recorder.prepareRecording(outputOptions)
+ .withEventListener(CameraXExecutors.directExecutor(), videoRecordEventListener)
@Suppress("UNCHECKED_CAST")
val streamStateObserver =
@@ -475,11 +476,18 @@
recorder.streamState.addObserver(CameraXExecutors.directExecutor(), streamStateObserver)
val activeRecording = pendingRecording.start()
- verify(streamStateObserver, timeout(1000L)).onNewData(eq(VideoOutput.StreamState.ACTIVE))
+
+ val inOrder = inOrder(streamStateObserver)
+ inOrder.verify(streamStateObserver, timeout(1000L))
+ .onNewData(eq(VideoOutput.StreamState.ACTIVE))
+
+ verify(videoRecordEventListener, timeout(15000L).atLeast(5))
+ .accept(any(VideoRecordEvent.Status::class.java))
activeRecording.stop()
- verify(streamStateObserver, timeout(1000L)).onNewData(eq(VideoOutput.StreamState.INACTIVE))
+ inOrder.verify(streamStateObserver, timeout(FINALIZE_TIMEOUT))
+ .onNewData(eq(VideoOutput.StreamState.INACTIVE))
file.delete()
}
@@ -594,6 +602,135 @@
}
@Test
+ fun pause_noOpWhenAlreadyPaused() {
+ clearInvocations(videoRecordEventListener)
+ invokeSurfaceRequest()
+ val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+ val outputOptions = FileOutputOptions.builder().setFile(file).build()
+
+ val pendingRecording = recorder.prepareRecording(outputOptions)
+ pendingRecording.withEventListener(
+ CameraXExecutors.directExecutor(),
+ videoRecordEventListener
+ ).withAudioEnabled()
+
+ val activeRecording = pendingRecording.start()
+
+ val inOrder = inOrder(videoRecordEventListener)
+ inOrder.verify(videoRecordEventListener, timeout(1000L))
+ .accept(any(VideoRecordEvent.Start::class.java))
+ inOrder.verify(videoRecordEventListener, timeout(15000L).atLeast(5))
+ .accept(any(VideoRecordEvent.Status::class.java))
+
+ activeRecording.pause()
+ inOrder.verify(videoRecordEventListener, timeout(1000L))
+ .accept(any(VideoRecordEvent.Pause::class.java))
+
+ activeRecording.pause()
+
+ // Shouldn't receive an additional Pause event.
+ inOrder.verifyNoMoreInteractions()
+
+ activeRecording.stop()
+
+ inOrder.verify(videoRecordEventListener, timeout(FINALIZE_TIMEOUT))
+ .accept(any(VideoRecordEvent.Finalize::class.java))
+
+ file.delete()
+ }
+
+ @Test
+ fun pause_throwsExceptionWhenStopping() {
+ clearInvocations(videoRecordEventListener)
+ invokeSurfaceRequest()
+ val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+ val outputOptions = FileOutputOptions.builder().setFile(file).build()
+
+ val pendingRecording = recorder.prepareRecording(outputOptions)
+ pendingRecording.withEventListener(
+ CameraXExecutors.directExecutor(),
+ videoRecordEventListener
+ ).withAudioEnabled()
+
+ val activeRecording = pendingRecording.start()
+
+ val inOrder = inOrder(videoRecordEventListener)
+ inOrder.verify(videoRecordEventListener, timeout(1000L))
+ .accept(any(VideoRecordEvent.Start::class.java))
+ inOrder.verify(videoRecordEventListener, timeout(15000L).atLeast(5))
+ .accept(any(VideoRecordEvent.Status::class.java))
+
+ activeRecording.stop()
+ assertThrows(IllegalStateException::class.java) {
+ activeRecording.pause()
+ }
+
+ file.delete()
+ }
+
+ @Test
+ fun resume_noOpWhenNotPaused() {
+ clearInvocations(videoRecordEventListener)
+ invokeSurfaceRequest()
+ val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+ val outputOptions = FileOutputOptions.builder().setFile(file).build()
+
+ val pendingRecording = recorder.prepareRecording(outputOptions)
+ pendingRecording.withEventListener(
+ CameraXExecutors.directExecutor(),
+ videoRecordEventListener
+ ).withAudioEnabled()
+
+ val activeRecording = pendingRecording.start()
+
+ val inOrder = inOrder(videoRecordEventListener)
+ inOrder.verify(videoRecordEventListener, timeout(1000L))
+ .accept(any(VideoRecordEvent.Start::class.java))
+ inOrder.verify(videoRecordEventListener, timeout(15000L).atLeast(5))
+ .accept(any(VideoRecordEvent.Status::class.java))
+
+ activeRecording.resume()
+
+ // Shouldn't receive an Resume event.
+ inOrder.verifyNoMoreInteractions()
+
+ activeRecording.stop()
+
+ inOrder.verify(videoRecordEventListener, timeout(FINALIZE_TIMEOUT))
+ .accept(any(VideoRecordEvent.Finalize::class.java))
+
+ file.delete()
+ }
+
+ fun resume_throwsExceptionWhenStopping() {
+ clearInvocations(videoRecordEventListener)
+ invokeSurfaceRequest()
+ val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+ val outputOptions = FileOutputOptions.builder().setFile(file).build()
+
+ val pendingRecording = recorder.prepareRecording(outputOptions)
+ pendingRecording.withEventListener(
+ CameraXExecutors.directExecutor(),
+ videoRecordEventListener
+ ).withAudioEnabled()
+
+ val activeRecording = pendingRecording.start()
+
+ val inOrder = inOrder(videoRecordEventListener)
+ inOrder.verify(videoRecordEventListener, timeout(1000L))
+ .accept(any(VideoRecordEvent.Start::class.java))
+ inOrder.verify(videoRecordEventListener, timeout(15000L).atLeast(5))
+ .accept(any(VideoRecordEvent.Status::class.java))
+
+ activeRecording.stop()
+ assertThrows(IllegalStateException::class.java) {
+ activeRecording.resume()
+ }
+
+ file.delete()
+ }
+
+ @Test
fun stop_beforeSurfaceRequested() {
clearInvocations(videoRecordEventListener)
val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
@@ -677,6 +814,37 @@
}
@Test
+ fun stop_noOpWhenStopping() {
+ clearInvocations(videoRecordEventListener)
+ invokeSurfaceRequest()
+ val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+ val outputOptions = FileOutputOptions.builder().setFile(file).build()
+
+ val pendingRecording = recorder.prepareRecording(outputOptions)
+ pendingRecording.withEventListener(
+ CameraXExecutors.directExecutor(),
+ videoRecordEventListener
+ ).withAudioEnabled()
+
+ val activeRecording = pendingRecording.start()
+
+ val inOrder = inOrder(videoRecordEventListener)
+ inOrder.verify(videoRecordEventListener, timeout(1000L))
+ .accept(any(VideoRecordEvent.Start::class.java))
+ inOrder.verify(videoRecordEventListener, timeout(15000L).atLeast(5))
+ .accept(any(VideoRecordEvent.Status::class.java))
+
+ activeRecording.stop()
+ activeRecording.stop()
+
+ inOrder.verify(videoRecordEventListener, timeout(FINALIZE_TIMEOUT))
+ .accept(any(VideoRecordEvent.Finalize::class.java))
+ inOrder.verifyNoMoreInteractions()
+
+ file.delete()
+ }
+
+ @Test
fun optionsOverridesDefaults() {
val qualitySelector = QualitySelector.of(QualitySelector.QUALITY_HIGHEST)
val recorder = Recorder.Builder()
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt
index cd23158..e06a490 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt
@@ -41,6 +41,7 @@
import androidx.camera.testing.CameraUtil
import androidx.camera.testing.SurfaceTextureProvider
import androidx.camera.testing.SurfaceTextureProvider.SurfaceTextureCallback
+import androidx.concurrent.futures.ResolvableFuture
import androidx.core.content.ContextCompat
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -73,6 +74,7 @@
@LargeTest
@RunWith(AndroidJUnit4::class)
+@Suppress("DEPRECATION")
class VideoEncoderTest {
@get: Rule
@@ -91,6 +93,7 @@
private lateinit var preview: Preview
private lateinit var mainExecutor: Executor
private lateinit var encoderExecutor: Executor
+ private lateinit var latestSurfaceReadyToRelease: ResolvableFuture<Void>
@Before
fun setUp() {
@@ -140,6 +143,13 @@
}
}
+ if (::latestSurfaceReadyToRelease.isInitialized) {
+ latestSurfaceReadyToRelease.addListener(
+ { videoEncoder.release() },
+ CameraXExecutors.directExecutor()
+ )
+ }
+
// Ensure all cameras are released for the next test
CameraX.shutdown()[10, TimeUnit.SECONDS]
}
@@ -151,7 +161,7 @@
var inOrder = inOrder(videoEncoderCallback)
inOrder.verify(videoEncoderCallback, timeout(5000L)).onEncodeStart()
inOrder.verify(videoEncoderCallback, timeout(15000L).atLeast(5)).onEncodedData(any())
- videoEncoder.stop()
+ videoEncoder.stopSafely()
inOrder.verify(videoEncoderCallback, timeout(5000L)).onEncodeStop()
clearInvocations(videoEncoderCallback)
@@ -164,7 +174,7 @@
inOrder.verify(videoEncoderCallback, timeout(15000L).atLeast(5)).onEncodedData(any())
// Act.
- videoEncoder.stop()
+ videoEncoder.stopSafely()
// Assert.
inOrder.verify(videoEncoderCallback, timeout(5000L)).onEncodeStop()
@@ -201,7 +211,7 @@
// callback.
verify(videoEncoderCallback, noInvocation(3000L, 10000L)).onEncodedData(any())
- videoEncoder.stop()
+ videoEncoder.stopSafely()
verify(videoEncoderCallback, timeout(5000L)).onEncodeStop()
@@ -241,22 +251,20 @@
@Test
fun startVideoEncoder_firstEncodedDataIsKeyFrame() {
- for (i in 0..2) {
- clearInvocations(videoEncoderCallback)
+ clearInvocations(videoEncoderCallback)
- videoEncoder.start()
- val captor = ArgumentCaptor.forClass(EncodedData::class.java)
- verify(
- videoEncoderCallback,
- timeout(5000L).atLeastOnce()
- ).onEncodedData(captor.capture())
+ videoEncoder.start()
+ val captor = ArgumentCaptor.forClass(EncodedData::class.java)
+ verify(
+ videoEncoderCallback,
+ timeout(5000L).atLeastOnce()
+ ).onEncodedData(captor.capture())
- assertThat(isKeyFrame(captor.allValues.first().bufferInfo)).isTrue()
+ assertThat(isKeyFrame(captor.allValues.first().bufferInfo)).isTrue()
- videoEncoder.stop()
+ videoEncoder.stopSafely()
- verify(videoEncoderCallback, timeout(5000L)).onEncodeStop()
- }
+ verify(videoEncoderCallback, timeout(5000L)).onEncodeStop()
}
@Test
@@ -317,20 +325,27 @@
videoEncoder.setEncoderCallback(videoEncoderCallback, CameraXExecutors.directExecutor())
+ latestSurfaceReadyToRelease = ResolvableFuture.create<Void>().apply { set(null) }
+
(videoEncoder.input as Encoder.SurfaceInput).setOnSurfaceUpdateListener(
mainExecutor
) { surface: Surface ->
+ latestSurfaceReadyToRelease = ResolvableFuture.create()
currentSurface = surface
- previewForVideoEncoder.setSurfaceProvider { request: SurfaceRequest ->
- request.provideSurface(
- surface,
- mainExecutor
- ) {
- if (it.surface != currentSurface) {
- it.surface.release()
- } else {
- videoEncoder.release()
- }
+ setVideoPreviewSurfaceProvider(surface)
+ }
+ }
+
+ private fun setVideoPreviewSurfaceProvider(surface: Surface) {
+ previewForVideoEncoder.setSurfaceProvider { request: SurfaceRequest ->
+ request.provideSurface(
+ surface,
+ mainExecutor
+ ) {
+ if (it.surface != currentSurface) {
+ it.surface.release()
+ } else {
+ latestSurfaceReadyToRelease.set(null)
}
}
}
@@ -371,4 +386,29 @@
private fun isKeyFrame(bufferInfo: MediaCodec.BufferInfo): Boolean {
return bufferInfo.flags and MediaCodec.BUFFER_FLAG_KEY_FRAME != 0
}
+
+ /**
+ * Stops safely by first removing the Encoder surface from camera repeating request.
+ *
+ * <p>When encoder is started and repeating request is running, stop the encoder will get EGL
+ * error on some devices such as Samsung J2, J3 and J7 (Exynos chipset). The encoder surface
+ * needs to be removed from repeating request before stop the encoder to avoid this failure.
+ *
+ * See b/196039619.
+ */
+ private fun EncoderImpl.stopSafely() {
+ instrumentation.runOnMainSync { previewForVideoEncoder.setSurfaceProvider(null) }
+ verify(videoEncoderCallback, noInvocation(2000L, 6000L)).onEncodedData(any())
+
+ stop()
+ verify(videoEncoderCallback, timeout(5000L)).onEncodeStop()
+
+ // The SurfaceProvider needs to be added back to recover repeating. However, for API < 23,
+ // EncoderImpl will trigger a surface update event to OnSurfaceUpdateListener and this will
+ // be handled by initVideoEncoder() to set the SurfaceProvider with new surface. So no
+ // need to add the SurfaceProvider back here.
+ if (Build.VERSION.SDK_INT >= 23) {
+ instrumentation.runOnMainSync { setVideoPreviewSurfaceProvider(currentSurface!!) }
+ }
+ }
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java b/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
index c43e36c..b9d8906 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
@@ -63,6 +63,8 @@
import androidx.camera.video.internal.AudioSourceAccessException;
import androidx.camera.video.internal.BufferProvider;
import androidx.camera.video.internal.compat.Api26Impl;
+import androidx.camera.video.internal.compat.quirk.DeviceQuirks;
+import androidx.camera.video.internal.compat.quirk.RecorderSetInactiveWhenStoppingQuirk;
import androidx.camera.video.internal.encoder.AudioEncoderConfig;
import androidx.camera.video.internal.encoder.EncodeException;
import androidx.camera.video.internal.encoder.EncodedData;
@@ -155,6 +157,10 @@
*/
PAUSED,
/**
+ * There's a recording being stopped.
+ */
+ STOPPING,
+ /**
* There's a running recording and the Recorder is being reset.
*/
RESETTING,
@@ -238,8 +244,7 @@
private final Object mLock = new Object();
@GuardedBy("mLock")
- private final MutableStateObservable<State> mState =
- MutableStateObservable.withInitialState(State.INITIALIZING);
+ private State mState = State.INITIALIZING;
private final MutableStateObservable<StreamState> mStreamState =
MutableStateObservable.withInitialState(StreamState.INACTIVE);
// Used only by getExecutor()
@@ -308,8 +313,7 @@
@Override
public void onSurfaceRequested(@NonNull SurfaceRequest request) {
synchronized (mLock) {
- State state = getObservableData(mState);
- switch (state) {
+ switch (mState) {
case RESETTING:
// Fall-through
case PENDING_RECORDING:
@@ -326,9 +330,11 @@
// Fall-through
case RECORDING:
// Fall-through
+ case STOPPING:
+ // Fall-through
case PAUSED:
throw new IllegalStateException("Surface was requested when the Recorder had "
- + "been initialized with state " + state);
+ + "been initialized with state " + mState);
case ERROR:
throw new IllegalStateException("Surface was requested when the Recorder had "
+ "encountered error " + mErrorCause);
@@ -359,7 +365,7 @@
mSourceState.set(sourceState);
if (sourceState == SourceState.INACTIVE) {
synchronized (mLock) {
- switch (getObservableData(mState)) {
+ switch (mState) {
case PENDING_RECORDING:
// Fall-through
case PENDING_PAUSED:
@@ -379,6 +385,8 @@
// Fall-through
case RESETTING:
// Fall-through
+ case STOPPING:
+ // Fall-through
case ERROR:
// No-op
break;
@@ -540,8 +548,9 @@
new IllegalStateException("The video frame producer is inactive.")));
} else {
synchronized (mLock) {
- State state = getObservableData(mState);
- switch (state) {
+ switch (mState) {
+ case STOPPING:
+ // Fall-through
case PENDING_PAUSED:
// Fall-through
case PAUSED:
@@ -584,7 +593,7 @@
void pause() {
synchronized (mLock) {
- switch (getObservableData(mState)) {
+ switch (mState) {
case PENDING_RECORDING:
// Fall-through
case RESETTING:
@@ -593,8 +602,11 @@
// The recording will automatically pause once the initialization completes.
setState(State.PENDING_PAUSED);
break;
+ case STOPPING:
+ // Fall-through
case IDLING:
- throw new IllegalStateException("Calling pause() while idling is invalid.");
+ throw new IllegalStateException(
+ "Incorrectly invoke pause() in state " + mState);
case RECORDING:
mSequentialExecutor.execute(this::pauseInternal);
setState(State.PAUSED);
@@ -616,7 +628,7 @@
void resume() {
synchronized (mLock) {
- switch (getObservableData(mState)) {
+ switch (mState) {
case PENDING_PAUSED:
// Fall-through
case RESETTING:
@@ -625,8 +637,11 @@
// The recording will automatically start once the initialization completes.
setState(State.PENDING_RECORDING);
break;
+ case STOPPING:
+ // Fall-through
case IDLING:
- throw new IllegalStateException("Calling resume() while idling is invalid.");
+ throw new IllegalStateException(
+ "Incorrectly invoke resume() in state " + mState);
case PENDING_RECORDING:
// Fall-through
case RECORDING:
@@ -648,7 +663,7 @@
void stop() {
synchronized (mLock) {
- switch (getObservableData(mState)) {
+ switch (mState) {
case PENDING_RECORDING:
// Fall-through
case PENDING_PAUSED:
@@ -663,6 +678,7 @@
case PAUSED:
// Fall-through
case RECORDING:
+ setState(State.STOPPING);
mSequentialExecutor.execute(() -> stopInternal(ERROR_NONE));
break;
case ERROR:
@@ -671,8 +687,10 @@
mSequentialExecutor.execute(
() -> finalizeRecording(ERROR_RECORDER_ERROR, mErrorCause));
break;
+ case STOPPING:
+ // Fall-through
case RESETTING:
- // No-Op, the Recorder is being resetting.
+ // No-Op
break;
}
}
@@ -688,7 +706,7 @@
@ExecutedBy("mSequentialExecutor")
void reset() {
synchronized (mLock) {
- switch (getObservableData(mState)) {
+ switch (mState) {
case PENDING_RECORDING:
// Fall-through
case PENDING_PAUSED:
@@ -708,6 +726,9 @@
// at finalizeRecording().
mSequentialExecutor.execute(() -> stopInternal(ERROR_NONE));
break;
+ case STOPPING:
+ setState(State.RESETTING);
+ break;
case RESETTING:
// No-Op, the Recorder is being reset.
break;
@@ -740,30 +761,34 @@
@ExecutedBy("mSequentialExecutor")
private void onInitialized() {
synchronized (mLock) {
- State state = getObservableData(mState);
- switch (state) {
+ switch (mState) {
case IDLING:
// Fall-through
case RECORDING:
// Fall-through
case PAUSED:
// Fall-through
+ case STOPPING:
+ // Fall-through
case RESETTING:
throw new IllegalStateException(
- "Incorrectly invoke onInitialized() in state " + state);
+ "Incorrectly invoke onInitialized() in state " + mState);
case INITIALIZING:
setState(State.IDLING);
break;
case PENDING_PAUSED:
- // Fall-through
+ // Start and pause recording if start() has been called before video encoder is
+ // setup.
+ mSequentialExecutor.execute(() -> {
+ startInternal();
+ pauseInternal();
+ });
+ setState(State.PAUSED);
+ break;
case PENDING_RECORDING:
// Start recording if start() has been called before video encoder is setup.
mSequentialExecutor.execute(this::startInternal);
setState(State.RECORDING);
- if (state == State.PENDING_PAUSED) {
- mSequentialExecutor.execute(this::pauseInternal);
- setState(State.PAUSED);
- }
break;
case ERROR:
Logger.e(TAG,
@@ -1318,7 +1343,7 @@
setState(State.INITIALIZING);
}
- private int internalAudioStateToEventAudioState(AudioState audioState) {
+ private int internalAudioStateToEventAudioState(@NonNull AudioState audioState) {
switch (audioState) {
case DISABLED:
return RecordingStats.AUDIO_DISABLED;
@@ -1335,6 +1360,15 @@
throw new IllegalStateException("Invalid internal audio state: " + audioState);
}
+ @NonNull
+ private StreamState internalStateToStreamState(@NonNull State state) {
+ // Stopping state should be treated as inactive on certain chipsets. See b/196039619.
+ RecorderSetInactiveWhenStoppingQuirk quirk =
+ DeviceQuirks.get(RecorderSetInactiveWhenStoppingQuirk.class);
+ return state == State.RECORDING || (state == State.STOPPING && quirk == null)
+ ? StreamState.ACTIVE : StreamState.INACTIVE;
+ }
+
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
boolean isAudioEnabled() {
return mAudioState != AudioState.DISABLED && mAudioState != AudioState.ENCODER_ERROR;
@@ -1386,20 +1420,22 @@
mFileSizeLimitInBytes = OutputOptions.FILE_SIZE_UNLIMITED;
synchronized (mLock) {
- switch (getObservableData(mState)) {
+ switch (mState) {
case INITIALIZING:
// Fall-through
case IDLING:
- // No-op
- break;
+ // Fall-through
+ case RECORDING:
+ // Fall-through
+ case PAUSED:
+ throw new IllegalStateException(
+ "Incorrectly invoke finalizeRecording in state " + mState);
case PENDING_RECORDING:
// Fall-through
case PENDING_PAUSED:
setState(State.INITIALIZING);
break;
- case RECORDING:
- // Fall-through
- case PAUSED:
+ case STOPPING:
// Fall-through
case ERROR:
// Reset the internal state, except when the error is an recorder error,
@@ -1462,14 +1498,12 @@
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
void setState(@NonNull State state) {
synchronized (mLock) {
- Logger.d(TAG,
- "Transitioning Recorder internal state: " + getObservableData(mState) + " -->"
- + " " + state);
- mState.setState(state);
- if (state == State.RECORDING) {
- mStreamState.setState(StreamState.ACTIVE);
+ if (mState != state) {
+ Logger.d(TAG, "Transitioning Recorder internal state: " + mState + " --> " + state);
+ mState = state;
+ mStreamState.setState(internalStateToStreamState(state));
} else {
- mStreamState.setState(StreamState.INACTIVE);
+ Logger.w(TAG, "Attempting to transition to the same state " + mState);
}
}
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java
index 7db9551..8360571 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java
@@ -990,6 +990,7 @@
}
/** Set audio record parameters by CamcorderProfile */
+ @SuppressWarnings("deprecation")
private void setAudioParametersByCamcorderProfile(Size currentResolution, String cameraId) {
CamcorderProfile profile;
boolean isCamcorderProfileFound = false;
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java
index d28f26c..cc01ae0 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java
@@ -45,6 +45,9 @@
if (MediaCodecInfoReportIncorrectInfoQuirk.load()) {
quirks.add(new MediaCodecInfoReportIncorrectInfoQuirk());
}
+ if (RecorderSetInactiveWhenStoppingQuirk.load()) {
+ quirks.add(new RecorderSetInactiveWhenStoppingQuirk());
+ }
return quirks;
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/RecorderSetInactiveWhenStoppingQuirk.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/RecorderSetInactiveWhenStoppingQuirk.java
new file mode 100644
index 0000000..808c126
--- /dev/null
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/RecorderSetInactiveWhenStoppingQuirk.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.video.internal.compat.quirk;
+
+import android.media.MediaCodec;
+import android.os.Build;
+
+import androidx.camera.core.impl.Quirk;
+import androidx.camera.video.Recorder;
+import androidx.camera.video.VideoCapture;
+import androidx.camera.video.VideoOutput;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * Quick denotes that {@link Recorder#getStreamState()} has to returns
+ * {@link VideoOutput.StreamState#INACTIVE} when the active recording is being stopped.
+ *
+ * <p>As described in b/196039619, on devices with certain chipsets, the camera fails if
+ * {@link MediaCodec} is stopped while frames are still being provided.
+ * {@link VideoCapture} monitors {@link VideoOutput#getStreamState()} and
+ * detach the surface from camera if it becomes {@link VideoOutput.StreamState#INACTIVE inactive}.
+ * So making the {@link Recorder} inactive in stopping state will stop the camera from producing
+ * frames to the {@link MediaCodec} before actually stopping it.
+ */
+public class RecorderSetInactiveWhenStoppingQuirk implements Quirk {
+
+ private static final List<String> BUILD_HARDWARE_SET = Arrays.asList("sc8830",
+ "samsungexynos7580");
+
+ static boolean load() {
+ return "SAMSUNG".equalsIgnoreCase(Build.BRAND) && BUILD_HARDWARE_SET.contains(
+ Build.HARDWARE.toLowerCase());
+ }
+}
diff --git a/camera/camera-view/api/current.txt b/camera/camera-view/api/current.txt
index eedab6e..2d8e12b 100644
--- a/camera/camera-view/api/current.txt
+++ b/camera/camera-view/api/current.txt
@@ -106,9 +106,9 @@
public final class RotationProvider {
ctor public RotationProvider(android.content.Context);
- method public void clearListener();
- method public boolean setListener(androidx.camera.view.RotationProvider.Listener);
- method public boolean setListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method @CheckResult public boolean addListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method public void removeAllListeners();
+ method public void removeListener(androidx.camera.view.RotationProvider.Listener);
}
public static interface RotationProvider.Listener {
diff --git a/camera/camera-view/api/public_plus_experimental_current.txt b/camera/camera-view/api/public_plus_experimental_current.txt
index 1d3b8bb..970410d 100644
--- a/camera/camera-view/api/public_plus_experimental_current.txt
+++ b/camera/camera-view/api/public_plus_experimental_current.txt
@@ -114,9 +114,9 @@
public final class RotationProvider {
ctor public RotationProvider(android.content.Context);
- method public void clearListener();
- method public boolean setListener(androidx.camera.view.RotationProvider.Listener);
- method public boolean setListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method @CheckResult public boolean addListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method public void removeAllListeners();
+ method public void removeListener(androidx.camera.view.RotationProvider.Listener);
}
public static interface RotationProvider.Listener {
diff --git a/camera/camera-view/api/restricted_current.txt b/camera/camera-view/api/restricted_current.txt
index 3cb762a..84dfbad 100644
--- a/camera/camera-view/api/restricted_current.txt
+++ b/camera/camera-view/api/restricted_current.txt
@@ -106,13 +106,13 @@
public final class RotationProvider {
ctor public RotationProvider(android.content.Context);
- method public void clearListener();
- method public boolean setListener(androidx.camera.view.RotationProvider.Listener);
- method public boolean setListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method @CheckResult public boolean addListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method public void removeAllListeners();
+ method public void removeListener(androidx.camera.view.RotationProvider.Listener);
}
public static interface RotationProvider.Listener {
- method public void onRotationChanged(int);
+ method public void onRotationChanged(@androidx.camera.core.impl.ImageOutputConfig.RotationValue int);
}
}
diff --git a/camera/camera-view/lint-baseline.xml b/camera/camera-view/lint-baseline.xml
index 327075e..90df4da 100644
--- a/camera/camera-view/lint-baseline.xml
+++ b/camera/camera-view/lint-baseline.xml
@@ -1,15 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
<issue
- id="WrongConstant"
- message="Must be one of: AspectRatio.RATIO_4_3, AspectRatio.RATIO_16_9"
- errorLine1=" builder.setTargetAspectRatio(outputSize.getAspectRatio());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.core.ExperimentalUseCaseGroup' or '@OptIn(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)'"
+ errorLine1=" return ViewPort.FILL_END;"
+ errorLine2=" ~~~~~~~~">
<location
- file="src/main/java/androidx/camera/view/CameraController.java"
- line="465"
- column="42"/>
+ file="src/main/java/androidx/camera/view/PreviewView.java"
+ line="566"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.core.ExperimentalUseCaseGroup' or '@OptIn(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)'"
+ errorLine1=" return ViewPort.FILL_CENTER;"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/view/PreviewView.java"
+ line="568"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.core.ExperimentalUseCaseGroup' or '@OptIn(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)'"
+ errorLine1=" return ViewPort.FILL_START;"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/camera/view/PreviewView.java"
+ line="570"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="UnsafeOptInUsageError"
+ message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.core.ExperimentalUseCaseGroup' or '@OptIn(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)'"
+ errorLine1=" return ViewPort.FIT;"
+ errorLine2=" ~~~">
+ <location
+ file="src/main/java/androidx/camera/view/PreviewView.java"
+ line="576"
+ column="33"/>
</issue>
</issues>
diff --git a/camera/camera-view/src/androidTest/AndroidManifest.xml b/camera/camera-view/src/androidTest/AndroidManifest.xml
index fd947bb..2dd2c7c 100644
--- a/camera/camera-view/src/androidTest/AndroidManifest.xml
+++ b/camera/camera-view/src/androidTest/AndroidManifest.xml
@@ -15,12 +15,10 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.camera.camera2.view">
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-permission android:name="android.permission.RECORD_AUDIO" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
- <activity
+ <activity
android:name="androidx.camera.testing.fakes.FakeActivity"
+ android:exported="true"
android:label="Fake Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -28,4 +26,8 @@
</intent-filter>
</activity>
</application>
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-permission android:name="android.permission.CAMERA" />
</manifest>
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index ff9a174..38946e9f 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -523,12 +523,13 @@
private void startListeningToRotationEvents() {
getDisplayManager().registerDisplayListener(mDisplayRotationListener,
new Handler(Looper.getMainLooper()));
- mRotationProvider.setListener(mDeviceRotationListener);
+ mRotationProvider.addListener(CameraXExecutors.mainThreadExecutor(),
+ mDeviceRotationListener);
}
private void stopListeningToRotationEvents() {
getDisplayManager().unregisterDisplayListener(mDisplayRotationListener);
- mRotationProvider.clearListener();
+ mRotationProvider.removeAllListeners();
}
private DisplayManager getDisplayManager() {
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/RotationProvider.java b/camera/camera-view/src/main/java/androidx/camera/view/RotationProvider.java
index 6c3279f..f97c051 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/RotationProvider.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/RotationProvider.java
@@ -22,14 +22,19 @@
import android.view.OrientationEventListener;
import android.view.Surface;
+import androidx.annotation.CheckResult;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.UseCase;
-import androidx.camera.core.impl.utils.executor.CameraXExecutors;
+import androidx.camera.core.impl.ImageOutputConfig;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Provider for receiving rotation updates from the {@link SensorManager} when the rotation of
@@ -65,14 +70,8 @@
// Synthetic access
@SuppressWarnings("WeakerAccess")
@GuardedBy("mLock")
- @Nullable
- Executor mExecutor;
-
- // Synthetic access
- @SuppressWarnings("WeakerAccess")
- @GuardedBy("mLock")
- @Nullable
- Listener mListener;
+ @NonNull
+ final Map<Listener, ListenerWrapper> mListeners = new HashMap<>();
// Set this value to true to test adding listener in unit tests.
@VisibleForTesting
@@ -98,14 +97,15 @@
int newRotation = orientationToSurfaceRotation(orientation);
if (mRotation != newRotation) {
mRotation = newRotation;
- Executor executor;
- Listener listener;
+ List<ListenerWrapper> listeners;
+ // Take a snapshot for thread safety.
synchronized (mLock) {
- executor = mExecutor;
- listener = mListener;
+ listeners = new ArrayList<>(mListeners.values());
}
- if (executor != null && listener != null) {
- executor.execute(() -> listener.onRotationChanged(newRotation));
+ if (!listeners.isEmpty()) {
+ for (ListenerWrapper listenerWrapper : listeners) {
+ listenerWrapper.onRotationChanged(newRotation);
+ }
}
}
}
@@ -115,42 +115,48 @@
/**
* Sets a {@link Listener} that listens for rotation changes.
*
- * <p> The {@link Listener#onRotationChanged(int)} method will be invoked on the main thread.
- *
- * @return false if the device cannot detection rotation changes.
- */
- public boolean setListener(@NonNull Listener listener) {
- return setListener(CameraXExecutors.mainThreadExecutor(), listener);
- }
-
- /**
- * Sets a {@link Listener} that listens for rotation changes.
- *
* @param executor The executor in which the {@link {@link Listener#onRotationChanged(int)}
* will be run.
* @return false if the device cannot detection rotation changes. In that case, the listener
* will not be set.
*/
- public boolean setListener(@NonNull Executor executor, @NonNull Listener listener) {
+ @CheckResult
+ public boolean addListener(@NonNull Executor executor, @NonNull Listener listener) {
synchronized (mLock) {
if (!mOrientationListener.canDetectOrientation() && !mIgnoreCanDetectForTest) {
return false;
}
- mExecutor = executor;
- mListener = listener;
+ mListeners.put(listener, new ListenerWrapper(listener, executor));
mOrientationListener.enable();
}
return true;
}
/**
- * Clears the previously set {@link Listener}.
+ * Removes the given {@link Listener} from this object.
+ *
+ * <p> The removed listener will no longer receive rotation updates.
*/
- public void clearListener() {
+ public void removeListener(@NonNull Listener listener) {
+ synchronized (mLock) {
+ ListenerWrapper listenerWrapper = mListeners.get(listener);
+ if (listenerWrapper != null) {
+ listenerWrapper.disable();
+ mListeners.remove(listener);
+ }
+ if (mListeners.isEmpty()) {
+ mOrientationListener.disable();
+ }
+ }
+ }
+
+ /**
+ * Removes all {@link Listener} from this object.
+ */
+ public void removeAllListeners() {
synchronized (mLock) {
mOrientationListener.disable();
- mExecutor = null;
- mListener = null;
+ mListeners.clear();
}
}
@@ -158,7 +164,7 @@
* Converts orientation degrees to {@link Surface} rotation.
*/
@VisibleForTesting
- static int orientationToSurfaceRotation(int orientation) {
+ static int orientationToSurfaceRotation(@ImageOutputConfig.RotationValue int orientation) {
if (orientation >= 315 || orientation < 45) {
return Surface.ROTATION_0;
} else if (orientation >= 225) {
@@ -171,6 +177,37 @@
}
/**
+ * Wrapper of {@link Listener} with the executor and a tombstone flag.
+ */
+ private static class ListenerWrapper {
+ private final Listener mListener;
+ private final Executor mExecutor;
+ private final AtomicBoolean mEnabled;
+
+ ListenerWrapper(Listener listener, Executor executor) {
+ mListener = listener;
+ mExecutor = executor;
+ mEnabled = new AtomicBoolean(true);
+ }
+
+ void onRotationChanged(@ImageOutputConfig.RotationValue int rotation) {
+ mExecutor.execute(() -> {
+ if (mEnabled.get()) {
+ mListener.onRotationChanged(rotation);
+ }
+ });
+ }
+
+ /**
+ * Once disabled, the app will not receive callback even if it has already been posted on
+ * the callback thread.
+ */
+ void disable() {
+ mEnabled.set(false);
+ }
+ }
+
+ /**
* Callback interface to receive rotation updates.
*/
public interface Listener {
@@ -189,6 +226,6 @@
* <tr><td>[225°, 315°)</td><td>{@link Surface#ROTATION_90}</td></tr>
* </table>
*/
- void onRotationChanged(int rotation);
+ void onRotationChanged(@ImageOutputConfig.RotationValue int rotation);
}
}
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/RotationProviderTest.kt b/camera/camera-view/src/test/java/androidx/camera/view/RotationProviderTest.kt
index 5c315e6..ccd823d 100644
--- a/camera/camera-view/src/test/java/androidx/camera/view/RotationProviderTest.kt
+++ b/camera/camera-view/src/test/java/androidx/camera/view/RotationProviderTest.kt
@@ -19,6 +19,7 @@
import android.os.Build
import android.os.Looper.getMainLooper
import android.view.Surface
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.google.common.truth.Truth.assertThat
import org.junit.After
@@ -30,6 +31,8 @@
import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
+private const val INVALID_ROTATION = -1
+
/**
* Unit tests for [RotationProvider].
*/
@@ -51,10 +54,50 @@
}
@Test
+ fun addAndRemoveAllListener_noCallback() {
+ // Arrange.
+ var rotation = INVALID_ROTATION
+ rotationProvider.addListener(CameraXExecutors.mainThreadExecutor()) {
+ rotation = it
+ }
+
+ // Act.
+ rotationProvider.removeAllListeners()
+ rotationProvider.mOrientationListener.onOrientationChanged(0)
+ shadowOf(getMainLooper()).idle()
+
+ // Assert.
+ assertThat(rotation).isEqualTo(INVALID_ROTATION)
+ }
+
+ @Test
+ fun addAndRemoveListener_noCallback() {
+ var rotationNoChange = INVALID_ROTATION
+ var rotationChanged = INVALID_ROTATION
+ val listenerKept = RotationProvider.Listener {
+ rotationChanged = it
+ }
+ val listenerRemoved = RotationProvider.Listener {
+ rotationNoChange = it
+ }
+ rotationProvider.addListener(CameraXExecutors.mainThreadExecutor(), listenerKept)
+ rotationProvider.addListener(CameraXExecutors.mainThreadExecutor(), listenerRemoved)
+
+ // Act.
+ rotationProvider.removeListener(listenerRemoved)
+ rotationProvider.mOrientationListener.onOrientationChanged(0)
+ shadowOf(getMainLooper()).idle()
+
+ // Assert.
+ assertThat(rotationNoChange).isEqualTo(INVALID_ROTATION)
+ assertThat(rotationChanged).isEqualTo(Surface.ROTATION_0)
+ }
+
+ @Test
fun addListener_receivesCallback() {
// Arrange.
var rotation = -1
- rotationProvider.setListener {
+ rotationProvider.addListener(CameraXExecutors.mainThreadExecutor()) {
rotation = it
}
// Act.
@@ -67,7 +110,7 @@
@Test
fun cannotDetectOrientation_addingReturnsFalse() {
rotationProvider.mIgnoreCanDetectForTest = false
- assertThat(rotationProvider.setListener {}).isFalse()
+ assertThat(rotationProvider.addListener(CameraXExecutors.mainThreadExecutor()) {}).isFalse()
}
@Test
diff --git a/camera/camera-view/src/test/resources/robolectric.properties b/camera/camera-view/src/test/resources/robolectric.properties
index 3f2e0d0..5fad9a0 100644
--- a/camera/camera-view/src/test/resources/robolectric.properties
+++ b/camera/camera-view/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
\ No newline at end of file
+sdk=30
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/Viewfinder.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/Viewfinder.kt
index cd16141..186059f 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/Viewfinder.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/Viewfinder.kt
@@ -41,6 +41,7 @@
*
* To use the viewfinder, call configure with the desired surface size, mode, and format.
*/
+@Suppress("DEPRECATION")
class Viewfinder(
context: Context?,
attrs: AttributeSet?,
@@ -553,4 +554,4 @@
internal fun Size.area(): Long {
return this.width * this.height.toLong()
-}
\ No newline at end of file
+}
diff --git a/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml b/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
index c8d6045..8f480fb 100644
--- a/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
@@ -27,7 +27,8 @@
android:theme="@style/AppTheme">
<activity
android:name=".CameraXActivity"
- android:label="Camera Core Test App">
+ android:label="Camera Core Test App"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -37,7 +38,8 @@
<activity
android:name=".OpenGLActivity"
android:label="Camera Core Test App (OpenGL Activity)"
- android:theme="@style/NoTitleTheme">
+ android:theme="@style/NoTitleTheme"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/camera/integration-tests/extensionstestapp/src/main/AndroidManifest.xml b/camera/integration-tests/extensionstestapp/src/main/AndroidManifest.xml
index 4df4d8d..35a369e 100644
--- a/camera/integration-tests/extensionstestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/extensionstestapp/src/main/AndroidManifest.xml
@@ -28,6 +28,7 @@
android:theme="@style/AppTheme">
<activity
android:name="androidx.camera.integration.extensions.CameraExtensionsActivity"
+ android:exported="true"
android:label="Camera Extensions">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/camera/integration-tests/timingtestapp/src/main/AndroidManifest.xml b/camera/integration-tests/timingtestapp/src/main/AndroidManifest.xml
index 8833509..6c7e3b5 100644
--- a/camera/integration-tests/timingtestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/timingtestapp/src/main/AndroidManifest.xml
@@ -45,7 +45,7 @@
android:supportsRtl="true"
android:name=".TimingApplication"
android:theme="@style/AppTheme">
- <activity android:name="androidx.camera.integration.antelope.MainActivity">
+ <activity android:name="androidx.camera.integration.antelope.MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/camera/integration-tests/uiwidgetstestapp/src/main/AndroidManifest.xml b/camera/integration-tests/uiwidgetstestapp/src/main/AndroidManifest.xml
index 85c76e0..d0ccb19 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/uiwidgetstestapp/src/main/AndroidManifest.xml
@@ -21,7 +21,7 @@
android:label="@string/app_name"
android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
+ <activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -30,23 +30,28 @@
</activity>
<activity
+ android:exported="false"
android:name=".viewpager.ViewPager2Activity"
android:label="ViewPager2 CameraX Test" />
<activity
+ android:exported="false"
android:name=".viewpager.ViewPagerActivity"
android:label="ViewPager CameraX Test" />
<activity
+ android:exported="false"
android:name=".rotations.UnlockedOrientationActivity"
android:label="Rotation - Unlocked orientation" />
<activity
+ android:exported="false"
android:name=".rotations.LockedOrientationActivity"
android:label="Rotation - Locked orientation"
android:screenOrientation="portrait" />
<activity
+ android:exported="false"
android:name=".rotations.OrientationConfigChangesOverriddenActivity"
android:configChanges="orientation|screenSize"
android:label="Rotation - ConfigChanges overridden" />
diff --git a/camera/integration-tests/viewtestapp/src/main/AndroidManifest.xml b/camera/integration-tests/viewtestapp/src/main/AndroidManifest.xml
index bff5a11..3960500 100644
--- a/camera/integration-tests/viewtestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/viewtestapp/src/main/AndroidManifest.xml
@@ -30,6 +30,7 @@
<activity
android:name=".MainActivity"
android:label="@string/app_name"
+ android:exported="true"
android:screenOrientation="fullUser">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
index 4cae28c..35f3a85 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
@@ -43,6 +43,7 @@
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
+import androidx.camera.core.Logger;
import androidx.camera.core.ZoomState;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.FutureCallback;
@@ -131,7 +132,12 @@
@Nullable Bundle savedInstanceState) {
mExecutorService = Executors.newSingleThreadExecutor();
mRotationProvider = new RotationProvider(requireContext());
- mRotationProvider.setListener(rotation -> mRotation = rotation);
+ boolean canDetectRotation =
+ mRotationProvider.addListener(CameraXExecutors.mainThreadExecutor(),
+ rotation -> mRotation = rotation);
+ if (!canDetectRotation) {
+ Logger.e(TAG, "The device cannot detect rotation with motion sensor.");
+ }
mCameraController = new LifecycleCameraController(requireContext());
checkFailedFuture(mCameraController.getInitializationFuture());
runSafely(() -> mCameraController.bindToLifecycle(getViewLifecycleOwner()));
@@ -334,7 +340,7 @@
if (mExecutorService != null) {
mExecutorService.shutdown();
}
- mRotationProvider.clearListener();
+ mRotationProvider.removeAllListeners();
}
void checkFailedFuture(ListenableFuture<Void> voidFuture) {
diff --git a/car/app/app-automotive/api/public_plus_experimental_current.txt b/car/app/app-automotive/api/public_plus_experimental_current.txt
index e44b1f5..10d773e 100644
--- a/car/app/app-automotive/api/public_plus_experimental_current.txt
+++ b/car/app/app-automotive/api/public_plus_experimental_current.txt
@@ -33,3 +33,11 @@
}
+package androidx.car.app.hardware {
+
+ @androidx.car.app.annotations.ExperimentalCarApi public final class AutomotiveCarHardwareManager implements androidx.car.app.hardware.CarHardwareManager {
+ ctor public AutomotiveCarHardwareManager(android.content.Context);
+ }
+
+}
+
diff --git a/car/app/app-automotive/src/main/java/androidx/car/app/activity/renderer/surface/SurfaceWrapperProvider.java b/car/app/app-automotive/src/main/java/androidx/car/app/activity/renderer/surface/SurfaceWrapperProvider.java
index 713443d..ef0331c 100644
--- a/car/app/app-automotive/src/main/java/androidx/car/app/activity/renderer/surface/SurfaceWrapperProvider.java
+++ b/car/app/app-automotive/src/main/java/androidx/car/app/activity/renderer/surface/SurfaceWrapperProvider.java
@@ -51,6 +51,7 @@
return new SurfaceWrapper(hostToken, width, height, displayId, densityDpi, surface);
}
+ @SuppressWarnings("deprecation")
private int densityDpi() {
DisplayMetrics displayMetrics = new DisplayMetrics();
mSurfaceView.getDisplay().getRealMetrics(displayMetrics);
diff --git a/car/app/app-automotive/src/main/java/androidx/car/app/hardware/AutomotiveCarHardwareManager.java b/car/app/app-automotive/src/main/java/androidx/car/app/hardware/AutomotiveCarHardwareManager.java
index d8c7ee9..9f5e372 100644
--- a/car/app/app-automotive/src/main/java/androidx/car/app/hardware/AutomotiveCarHardwareManager.java
+++ b/car/app/app-automotive/src/main/java/androidx/car/app/hardware/AutomotiveCarHardwareManager.java
@@ -15,14 +15,12 @@
*/
package androidx.car.app.hardware;
-import static androidx.annotation.RestrictTo.Scope.LIBRARY;
-
import static java.util.Objects.requireNonNull;
import android.content.Context;
import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
+import androidx.car.app.annotations.ExperimentalCarApi;
import androidx.car.app.hardware.common.PropertyManager;
import androidx.car.app.hardware.info.AutomotiveCarInfo;
import androidx.car.app.hardware.info.AutomotiveCarSensors;
@@ -32,10 +30,8 @@
/**
* {@link CarHardwareManager} which uses Android Automotive OS APIs to access properties, sensors,
* and actions.
- *
- * @hide
*/
-@RestrictTo(LIBRARY)
+@ExperimentalCarApi
public final class AutomotiveCarHardwareManager implements CarHardwareManager {
private final AutomotiveCarInfo mCarInfo;
diff --git a/car/app/app-automotive/src/main/java/androidx/car/app/hardware/info/AutomotiveCarInfo.java b/car/app/app-automotive/src/main/java/androidx/car/app/hardware/info/AutomotiveCarInfo.java
index 05a2a8a..3e2db72 100644
--- a/car/app/app-automotive/src/main/java/androidx/car/app/hardware/info/AutomotiveCarInfo.java
+++ b/car/app/app-automotive/src/main/java/androidx/car/app/hardware/info/AutomotiveCarInfo.java
@@ -217,15 +217,18 @@
// Add "evConnector" and "fuel" type of the vehicle to the requests.
request.add(GetPropertyRequest.create(INFO_EV_BATTERY_CAPACITY));
request.add(GetPropertyRequest.create(INFO_FUEL_CAPACITY));
-
- ListenableFuture<List<CarPropertyResponse<?>>> future =
+ ListenableFuture<List<CarPropertyResponse<?>>> capacityFuture =
mPropertyManager.submitGetPropertyRequest(request, executor);
+ EnergyLevelListener energyLevelListener = new EnergyLevelListener(listener, executor);
- future.addListener(() -> {
+ // This future will get EV battery capacity and fuel capacity for calculating the
+ // percentage of battery level and fuel level. Without those values, we still can provide
+ // fuel_level_low, distance_units and range_remaining information in EnergyLevelListener.
+ capacityFuture.addListener(() -> {
try {
float evBatteryCapacity = UNKNOWN_CAPACITY;
float fuelCapacity = UNKNOWN_CAPACITY;
- List<CarPropertyResponse<?>> result = future.get();
+ List<CarPropertyResponse<?>> result = capacityFuture.get();
for (CarPropertyResponse<?> value : result) {
if (value.getValue() == null) {
Log.w(LogTags.TAG_CAR_HARDWARE,
@@ -233,18 +236,17 @@
+ value.getPropertyId());
continue;
}
- if (value.getPropertyId() == INFO_EV_BATTERY_CAPACITY) {
+ if (value.getPropertyId() == INFO_EV_BATTERY_CAPACITY
+ && value.getStatus() == CarValue.STATUS_SUCCESS) {
evBatteryCapacity = (Float) value.getValue();
+ energyLevelListener.updateEvBatteryCapacity(evBatteryCapacity);
}
- if (value.getPropertyId() == INFO_FUEL_CAPACITY) {
+ if (value.getPropertyId() == INFO_FUEL_CAPACITY
+ && value.getStatus() == CarValue.STATUS_SUCCESS) {
fuelCapacity = (Float) value.getValue();
+ energyLevelListener.updateFuelCapacity(fuelCapacity);
}
}
- EnergyLevelListener energyLevelListener = new EnergyLevelListener(listener,
- executor, evBatteryCapacity, fuelCapacity);
- mPropertyManager.submitRegisterListenerRequest(ENERGY_LEVEL_REQUEST,
- DEFAULT_SAMPLE_RATE, energyLevelListener, executor);
- mListenerMap.put(listener, energyLevelListener);
} catch (ExecutionException e) {
Log.e(LogTags.TAG_CAR_HARDWARE,
"Failed to get CarPropertyResponse for Energy Level", e);
@@ -254,6 +256,9 @@
Thread.currentThread().interrupt();
}
}, executor);
+ mPropertyManager.submitRegisterListenerRequest(ENERGY_LEVEL_REQUEST,
+ DEFAULT_SAMPLE_RATE, energyLevelListener, executor);
+ mListenerMap.put(listener, energyLevelListener);
}
private void populateModelData(@NonNull Executor executor,
@@ -510,14 +515,19 @@
private final OnCarDataAvailableListener<EnergyLevel>
mEnergyLevelOnCarDataAvailableListener;
private final Executor mExecutor;
- private float mEvBatteryCapacity;
- private float mFuelCapacity;
+ private float mEvBatteryCapacity = UNKNOWN_CAPACITY;
+ private float mFuelCapacity = UNKNOWN_CAPACITY;
- EnergyLevelListener(OnCarDataAvailableListener<EnergyLevel> listener, Executor executor,
- float evBatteryCapacity, float fuelCapacity) {
+ EnergyLevelListener(OnCarDataAvailableListener<EnergyLevel> listener, Executor executor) {
mEnergyLevelOnCarDataAvailableListener = listener;
mExecutor = executor;
+ }
+
+ void updateEvBatteryCapacity(float evBatteryCapacity) {
mEvBatteryCapacity = evBatteryCapacity;
+ }
+
+ void updateFuelCapacity(float fuelCapacity) {
mFuelCapacity = fuelCapacity;
}
diff --git a/car/app/app-automotive/src/test/java/androidx/car/app/hardware/info/AutomotiveCarInfoTest.java b/car/app/app-automotive/src/test/java/androidx/car/app/hardware/info/AutomotiveCarInfoTest.java
index 800c110..9919320 100644
--- a/car/app/app-automotive/src/test/java/androidx/car/app/hardware/info/AutomotiveCarInfoTest.java
+++ b/car/app/app-automotive/src/test/java/androidx/car/app/hardware/info/AutomotiveCarInfoTest.java
@@ -30,6 +30,7 @@
import static android.car.VehiclePropertyIds.RANGE_REMAINING;
import static androidx.car.app.hardware.common.CarValue.STATUS_SUCCESS;
+import static androidx.car.app.hardware.common.CarValue.STATUS_UNAVAILABLE;
import static androidx.car.app.hardware.info.AutomotiveCarInfo.DEFAULT_SAMPLE_RATE;
import static androidx.car.app.hardware.info.AutomotiveCarInfo.SPEED_DISPLAY_UNIT_ID;
import static androidx.car.app.hardware.info.AutomotiveCarInfo.TOLL_CARD_STATUS_ID;
@@ -328,4 +329,63 @@
5f);
assertThat(energyLevel.getDistanceDisplayUnit().getValue()).isEqualTo(7);
}
+
+ @Test
+ public void getEnergyLevel_withUnavailableCapacityValues() throws InterruptedException {
+ ArgumentCaptor<OnCarPropertyResponseListener> captor = ArgumentCaptor.forClass(
+ OnCarPropertyResponseListener.class);
+ float evBatteryCapacity = 100f;
+ float evBatteryLevelValue = 50f;
+ float fuelCapacity = 120f;
+ float fuelLevelValue = 50f;
+ List<CarPropertyResponse<?>> capacities = new ArrayList<>();
+ capacities.add(CarPropertyResponse.create(INFO_EV_BATTERY_CAPACITY,
+ STATUS_UNAVAILABLE, 1, evBatteryCapacity));
+ capacities.add(CarPropertyResponse.create(INFO_FUEL_CAPACITY,
+ STATUS_UNAVAILABLE, 1, fuelCapacity));
+ ListenableFuture<List<CarPropertyResponse<?>>> future =
+ Futures.immediateFuture(capacities);
+ when(mPropertyManager.submitGetPropertyRequest(any(), any())).thenReturn(future);
+
+ AtomicReference<EnergyLevel> loadedResult = new AtomicReference<>();
+ OnCarDataAvailableListener<EnergyLevel> listener = (data) -> {
+ loadedResult.set(data);
+ mCountDownLatch.countDown();
+ };
+
+ mAutomotiveCarInfo.addEnergyLevelListener(mExecutor, listener);
+
+ verify(mPropertyManager, times(1)).submitGetPropertyRequest(any(), any());
+ verify(mPropertyManager, times(1)).submitRegisterListenerRequest(any(),
+ eq(DEFAULT_SAMPLE_RATE), captor.capture(), any());
+
+ mResponse.add(CarPropertyResponse.create(EV_BATTERY_LEVEL,
+ STATUS_SUCCESS, 1, evBatteryLevelValue));
+ mResponse.add(CarPropertyResponse.create(FUEL_LEVEL,
+ STATUS_SUCCESS, 1, fuelLevelValue));
+ mResponse.add(CarPropertyResponse.create(FUEL_LEVEL_LOW,
+ STATUS_SUCCESS, 1, true));
+ mResponse.add(CarPropertyResponse.create(RANGE_REMAINING,
+ STATUS_SUCCESS, 1, 5f));
+ mResponse.add(CarPropertyResponse.create(DISTANCE_DISPLAY_UNITS,
+ STATUS_SUCCESS, 1, 7));
+ captor.getValue().onCarPropertyResponses(mResponse);
+ mCountDownLatch.await();
+
+ EnergyLevel energyLevel = loadedResult.get();
+
+ // Battery percent and fuel percent should be UNIMPLEMENTED_FLOAT since we can not get
+ // the capacity of battery and fuel property.
+ assertThat(energyLevel.getBatteryPercent().getValue()).isEqualTo(
+ CarValue.UNIMPLEMENTED_FLOAT.getValue());
+ assertThat(energyLevel.getFuelPercent().getValue()).isEqualTo(
+ CarValue.UNIMPLEMENTED_FLOAT.getValue());
+
+ // The other properties should still work without capacity values
+ assertThat(energyLevel.getEnergyIsLow().getValue()).isEqualTo(
+ true);
+ assertThat(energyLevel.getRangeRemainingMeters().getValue()).isEqualTo(
+ 5f);
+ assertThat(energyLevel.getDistanceDisplayUnit().getValue()).isEqualTo(7);
+ }
}
diff --git a/car/app/app-automotive/src/test/resources/robolectric.properties b/car/app/app-automotive/src/test/resources/robolectric.properties
index ce87047..ab64ba7 100644
--- a/car/app/app-automotive/src/test/resources/robolectric.properties
+++ b/car/app/app-automotive/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/car/app/app-projected/src/test/resources/robolectric.properties b/car/app/app-projected/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..5fad9a0
--- /dev/null
+++ b/car/app/app-projected/src/test/resources/robolectric.properties
@@ -0,0 +1,3 @@
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
+# sdk for now. Remove when no longer necessary.
+sdk=30
\ No newline at end of file
diff --git a/car/app/app-samples/helloworld/common/src/test/resources/robolectric.properties b/car/app/app-samples/helloworld/common/src/test/resources/robolectric.properties
index 89a6c8b..ab64ba7 100644
--- a/car/app/app-samples/helloworld/common/src/test/resources/robolectric.properties
+++ b/car/app/app-samples/helloworld/common/src/test/resources/robolectric.properties
@@ -1 +1,3 @@
-sdk=28
\ No newline at end of file
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
+# sdk for now. Remove when no longer necessary.
+sdk=30
diff --git a/car/app/app-samples/navigation/automotive/github_build.gradle b/car/app/app-samples/navigation/automotive/github_build.gradle
index 3ce7e5f..79bfe1b 100644
--- a/car/app/app-samples/navigation/automotive/github_build.gradle
+++ b/car/app/app-samples/navigation/automotive/github_build.gradle
@@ -23,8 +23,8 @@
applicationId "androidx.car.app.sample.navigation"
minSdkVersion 29
targetSdkVersion 29
- versionCode 100 // Increment this to generate signed builds for uploading to Playstore
- versionName "100"
+ versionCode 101 // Increment this to generate signed builds for uploading to Playstore
+ versionName "101"
}
buildTypes {
diff --git a/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml
index 725f8d1..a6c75ae 100644
--- a/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>
diff --git a/car/app/app-samples/navigation/common/lint-baseline.xml b/car/app/app-samples/navigation/common/lint-baseline.xml
index 1f16ba2..e927ed7 100644
--- a/car/app/app-samples/navigation/common/lint-baseline.xml
+++ b/car/app/app-samples/navigation/common/lint-baseline.xml
@@ -96,7 +96,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/car/app/sample/navigation/common/nav/NavigationService.java"
- line="502"
+ line="503"
column="21"/>
</issue>
@@ -107,7 +107,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/car/app/sample/navigation/common/nav/NavigationService.java"
- line="503"
+ line="504"
column="34"/>
</issue>
diff --git a/car/app/app-samples/navigation/mobile/github_build.gradle b/car/app/app-samples/navigation/mobile/github_build.gradle
index 1a96a4e..4295dea 100644
--- a/car/app/app-samples/navigation/mobile/github_build.gradle
+++ b/car/app/app-samples/navigation/mobile/github_build.gradle
@@ -23,8 +23,8 @@
applicationId "androidx.car.app.sample.navigation"
minSdkVersion 23
targetSdkVersion 29
- versionCode 100 // Increment this to generate signed builds for uploading to Playstore
- versionName "100"
+ versionCode 101 // Increment this to generate signed builds for uploading to Playstore
+ versionName "101"
}
buildTypes {
diff --git a/car/app/app-samples/navigation/mobile/src/main/AndroidManifest.xml b/car/app/app-samples/navigation/mobile/src/main/AndroidManifest.xml
index 98ff76c..99e5e3d 100644
--- a/car/app/app-samples/navigation/mobile/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/navigation/mobile/src/main/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>
diff --git a/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml
index 5add5d2..924d4ab 100644
--- a/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- For PlaceListMapTemplate -->
<uses-permission android:name="androidx.car.app.MAP_TEMPLATES"/>
diff --git a/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java b/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java
index 0d31407..044338a 100644
--- a/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java
+++ b/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java
@@ -16,12 +16,15 @@
package androidx.car.app.sample.places.common;
+import android.Manifest;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import androidx.car.app.CarAppService;
import androidx.car.app.Screen;
+import androidx.car.app.ScreenManager;
import androidx.car.app.Session;
import androidx.car.app.validation.HostValidator;
@@ -40,7 +43,16 @@
@Override
@NonNull
public Screen onCreateScreen(@NonNull Intent intent) {
- return PlaceCategoryListScreen.create(getCarContext());
+ if (getCarContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return PlaceCategoryListScreen.create(getCarContext());
+ }
+
+ // If we do not have the location permission, show the request permission screen.
+ ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
+ screenManager
+ .push(PlaceCategoryListScreen.create(getCarContext()));
+ return new RequestPermissionScreen(getCarContext(), () -> screenManager.pop());
}
};
}
diff --git a/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/RequestPermissionScreen.java b/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/RequestPermissionScreen.java
new file mode 100644
index 0000000..1a96701
--- /dev/null
+++ b/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/RequestPermissionScreen.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.sample.places.common;
+
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
+import androidx.annotation.NonNull;
+import androidx.car.app.CarContext;
+import androidx.car.app.CarToast;
+import androidx.car.app.Screen;
+import androidx.car.app.model.Action;
+import androidx.car.app.model.CarColor;
+import androidx.car.app.model.MessageTemplate;
+import androidx.car.app.model.OnClickListener;
+import androidx.car.app.model.ParkedOnlyOnClickListener;
+import androidx.car.app.model.Template;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Screen for asking the user to grant location permission. */
+public class RequestPermissionScreen extends Screen {
+
+ /** Callback called when the location permission is granted. */
+ public interface LocationPermissionCheckCallback {
+ /** Callback called when the location permission is granted. */
+ void onPermissionGranted();
+ }
+
+ LocationPermissionCheckCallback mLocationPermissionCheckCallback;
+
+ public RequestPermissionScreen(
+ @NonNull CarContext carContext, @NonNull LocationPermissionCheckCallback callback) {
+ super(carContext);
+ mLocationPermissionCheckCallback = callback;
+ }
+
+ @NonNull
+ @Override
+ public Template onGetTemplate() {
+ List<String> permissions = new ArrayList<>();
+ permissions.add(ACCESS_FINE_LOCATION);
+
+ String message = "This app needs access to location in order to show the map around you";
+
+ OnClickListener listener = ParkedOnlyOnClickListener.create(() ->
+ getCarContext().requestPermissions(
+ permissions,
+ (approved, rejected) -> {
+ CarToast.makeText(
+ getCarContext(),
+ String.format("Approved: %s Rejected: %s", approved, rejected),
+ CarToast.LENGTH_LONG).show();
+ if (!approved.isEmpty()) {
+ mLocationPermissionCheckCallback.onPermissionGranted();
+ finish();
+ }
+ }));
+
+ Action action = new Action.Builder()
+ .setTitle("Grant Access")
+ .setBackgroundColor(CarColor.GREEN)
+ .setOnClickListener(listener)
+ .build();
+
+ return new MessageTemplate.Builder(message).addAction(action).setHeaderAction(
+ Action.APP_ICON).build();
+ }
+}
diff --git a/car/app/app-samples/places/mobile/src/main/AndroidManifest.xml b/car/app/app-samples/places/mobile/src/main/AndroidManifest.xml
index 4a9b8274..0afec2a 100644
--- a/car/app/app-samples/places/mobile/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/places/mobile/src/main/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- For PlaceListMapTemplate -->
<uses-permission android:name="androidx.car.app.MAP_TEMPLATES"/>
diff --git a/car/app/app-samples/showcase/automotive/github_build.gradle b/car/app/app-samples/showcase/automotive/github_build.gradle
index 838cbc5..893f0e6 100644
--- a/car/app/app-samples/showcase/automotive/github_build.gradle
+++ b/car/app/app-samples/showcase/automotive/github_build.gradle
@@ -23,8 +23,8 @@
applicationId "androidx.car.app.sample.showcase"
minSdkVersion 29
targetSdkVersion 29
- versionCode 100 // Increment this to generate signed builds for uploading to Playstore
- versionName "100"
+ versionCode 101 // Increment this to generate signed builds for uploading to Playstore
+ versionName "101"
}
buildTypes {
diff --git a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
index 6c2e940..8c6a8d6 100644
--- a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
@@ -34,6 +34,7 @@
<!-- For Access to Car Hardware. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.car.permission.CAR_MILEAGE"/>
<uses-permission android:name="android.car.permission.CAR_SPEED"/>
<uses-permission android:name="android.car.permission.CAR_INFO"/>
diff --git a/car/app/app-samples/showcase/common/lint-baseline.xml b/car/app/app-samples/showcase/common/lint-baseline.xml
index 34ce884..41d7627 100644
--- a/car/app/app-samples/showcase/common/lint-baseline.xml
+++ b/car/app/app-samples/showcase/common/lint-baseline.xml
@@ -3,6 +3,17 @@
<issue
id="ClassVerificationFailure"
+ message="This call references a method added in API level 26; however, the containing class androidx.car.app.sample.showcase.common.navigation.NavigationNotificationService is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" new NotificationChannel("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationService.java"
+ line="112"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
message="This call references a method added in API level 26; however, the containing class androidx.car.app.sample.showcase.common.navigation.NavigationNotificationsDemoScreen is reachable from earlier API levels and will fail run-time class verification."
errorLine1=" context.startForegroundService(intent);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
@@ -12,4 +23,15 @@
column="49"/>
</issue>
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 26; however, the containing class androidx.car.app.sample.showcase.common.misc.NotificationDemoScreen is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" new NotificationChannel("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java"
+ line="228"
+ column="21"/>
+ </issue>
+
</issues>
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java
index 8adb771..2c125e2 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java
@@ -108,12 +108,11 @@
mEnergyProfile = null;
try {
- carInfo.fetchModel(mCarHardwareExecutor, mModelListener);
+ carInfo.fetchEnergyProfile(mCarHardwareExecutor, mEnergyProfileListener);
mHasEnergyProfilePermission = true;
} catch (SecurityException e) {
mHasEnergyProfilePermission = false;
}
- carInfo.fetchEnergyProfile(mCarHardwareExecutor, mEnergyProfileListener);
}
});
@@ -153,7 +152,7 @@
Row.Builder energyProfileRowBuilder = new Row.Builder()
.setTitle("Energy Profile");
- if (!mHasModelPermission) {
+ if (!mHasEnergyProfilePermission) {
energyProfileRowBuilder.addText("No Energy Profile Permission.");
} else {
StringBuilder fuelInfo = new StringBuilder();
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
index 49353cd..2dc5057 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
@@ -49,6 +49,7 @@
private static final int ROW_SPACING = 10;
private static final int LEFT_MARGIN = 15;
+ private static final int MAX_FONT_SIZE = 32;
private final Executor mCarHardwareExecutor;
private final Paint mCarInfoPaint = new Paint();
@@ -311,7 +312,7 @@
stableArea.set(0, 0, canvas.getWidth() - 1, canvas.getHeight() - 1);
}
- int height = stableArea.height() / 8;
+ int height = Math.min(stableArea.height() / 8, MAX_FONT_SIZE);
int updatedSize = height - ROW_SPACING;
mCarInfoPaint.setTextSize(updatedSize);
diff --git a/car/app/app-samples/showcase/mobile/github_build.gradle b/car/app/app-samples/showcase/mobile/github_build.gradle
index cc470ac..e8956cd 100644
--- a/car/app/app-samples/showcase/mobile/github_build.gradle
+++ b/car/app/app-samples/showcase/mobile/github_build.gradle
@@ -23,8 +23,8 @@
applicationId "androidx.car.app.sample.showcase"
minSdkVersion 23
targetSdkVersion 29
- versionCode 100 // Increment this to generate signed builds for uploading to Playstore
- versionName "100"
+ versionCode 101 // Increment this to generate signed builds for uploading to Playstore
+ versionName "101"
}
buildTypes {
diff --git a/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
index f39c463..519d9ef 100644
--- a/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
@@ -34,6 +34,7 @@
<!-- For Access to Car Hardware. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="com.google.android.gms.permission.CAR_MILEAGE"/>
<uses-permission android:name="com.google.android.gms.permission.CAR_SPEED"/>
<uses-permission android:name="com.google.android.gms.permission.CAR_FUEL"/>
diff --git a/car/app/app-testing/api/current.txt b/car/app/app-testing/api/current.txt
index 1b78781..2befd1d 100644
--- a/car/app/app-testing/api/current.txt
+++ b/car/app/app-testing/api/current.txt
@@ -6,7 +6,8 @@
}
public class ScreenController {
- ctor public ScreenController(androidx.car.app.testing.TestCarContext, androidx.car.app.Screen);
+ ctor public ScreenController(androidx.car.app.Screen);
+ ctor @Deprecated public ScreenController(androidx.car.app.testing.TestCarContext, androidx.car.app.Screen);
method public androidx.car.app.Screen getScreen();
method public Object? getScreenResult();
method public java.util.List<androidx.car.app.model.Template!> getTemplatesReturned();
diff --git a/car/app/app-testing/api/public_plus_experimental_current.txt b/car/app/app-testing/api/public_plus_experimental_current.txt
index 1b78781..2befd1d 100644
--- a/car/app/app-testing/api/public_plus_experimental_current.txt
+++ b/car/app/app-testing/api/public_plus_experimental_current.txt
@@ -6,7 +6,8 @@
}
public class ScreenController {
- ctor public ScreenController(androidx.car.app.testing.TestCarContext, androidx.car.app.Screen);
+ ctor public ScreenController(androidx.car.app.Screen);
+ ctor @Deprecated public ScreenController(androidx.car.app.testing.TestCarContext, androidx.car.app.Screen);
method public androidx.car.app.Screen getScreen();
method public Object? getScreenResult();
method public java.util.List<androidx.car.app.model.Template!> getTemplatesReturned();
diff --git a/car/app/app-testing/api/restricted_current.txt b/car/app/app-testing/api/restricted_current.txt
index 1b78781..2befd1d 100644
--- a/car/app/app-testing/api/restricted_current.txt
+++ b/car/app/app-testing/api/restricted_current.txt
@@ -6,7 +6,8 @@
}
public class ScreenController {
- ctor public ScreenController(androidx.car.app.testing.TestCarContext, androidx.car.app.Screen);
+ ctor public ScreenController(androidx.car.app.Screen);
+ ctor @Deprecated public ScreenController(androidx.car.app.testing.TestCarContext, androidx.car.app.Screen);
method public androidx.car.app.Screen getScreen();
method public Object? getScreenResult();
method public java.util.List<androidx.car.app.model.Template!> getTemplatesReturned();
diff --git a/car/app/app-testing/src/main/java/androidx/car/app/testing/ScreenController.java b/car/app/app-testing/src/main/java/androidx/car/app/testing/ScreenController.java
index 089e9e6..56f3d78 100644
--- a/car/app/app-testing/src/main/java/androidx/car/app/testing/ScreenController.java
+++ b/car/app/app-testing/src/main/java/androidx/car/app/testing/ScreenController.java
@@ -18,7 +18,6 @@
import static java.util.Objects.requireNonNull;
-import android.annotation.SuppressLint;
import android.util.Pair;
import androidx.annotation.NonNull;
@@ -32,12 +31,11 @@
import androidx.lifecycle.LifecycleOwner;
import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
- * A controller that allows testing of a {@link Screen}.
+ * {@link ScreenController} provides API that allows testing of a {@link Screen}.
*
* <p>This controller will allows:
*
@@ -55,14 +53,33 @@
/**
* Creates a ScreenController to control a {@link Screen} for testing.
*
- * @throws NullPointerException if either {@code testCarContext} or {@code screen} are null
+ * @throws NullPointerException if {@code screen} is null
+ * @throws IllegalArgumentException if {@code screen} was not created with a
+ * {@link TestCarContext}
*/
- public ScreenController(@NonNull TestCarContext testCarContext, @NonNull Screen screen) {
+ public ScreenController(@NonNull Screen screen) {
mScreen = requireNonNull(screen);
- mTestCarContext = requireNonNull(testCarContext);
+ TestCarContext carContext = (TestCarContext) mScreen.getCarContext();
+ if (carContext == null) {
+ throw new IllegalArgumentException(
+ "Screen should be created with TestCarContext for testing");
+ }
+ mTestCarContext = carContext;
mLifecycleOwner = new TestLifecycleOwner();
mLifecycleOwner.getRegistry().addObserver(new ScreenLifecycleObserver());
+ }
+
+ /**
+ * Creates a ScreenController to control a {@link Screen} for testing.
+ *
+ * @throws NullPointerException if either {@code testCarContext} or {@code screen} are null
+ * @deprecated use {@link ScreenController#ScreenController(Screen)} instead
+ */
+ @Deprecated
+ public ScreenController(@NonNull TestCarContext testCarContext, @NonNull Screen screen) {
+ mScreen = requireNonNull(screen);
+ mTestCarContext = requireNonNull(testCarContext);
// Use reflection to inject the TestCarContext into the Screen.
try {
@@ -72,6 +89,9 @@
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Failed to set a test car context for testing", e);
}
+
+ mLifecycleOwner = new TestLifecycleOwner();
+ mLifecycleOwner.getRegistry().addObserver(new ScreenLifecycleObserver());
}
/** Returns the {@link Screen} being controlled. */
@@ -109,22 +129,6 @@
}
/**
- * Returns the result that was set via {@link Screen#setResult(Object)}, or {@code null} if
- * one was not set.
- */
- @Nullable
- public Object getScreenResult() {
- try {
- Field result = Screen.class.getDeclaredField("mResult");
- result.setAccessible(true);
- return result.get(mScreen);
- } catch (ReflectiveOperationException e) {
- throw new IllegalStateException("Unable to access result from screen being "
- + "controlled", e);
- }
- }
-
- /**
* Moves the {@link Screen} being controlled to the input {@code state}.
*
* <p>Note that moving the {@link Screen} up a state will also push the {@link Screen} onto
@@ -141,6 +145,15 @@
return this;
}
+ /**
+ * Returns the result that was set via {@link Screen#setResult(Object)}, or {@code null} if
+ * one was not set.
+ */
+ @Nullable
+ public Object getScreenResult() {
+ return mScreen.getResultInternal();
+ }
+
void putScreenOnStackIfNotTop() {
TestScreenManager testScreenManager = mTestCarContext.getCarService(
TestScreenManager.class);
@@ -149,16 +162,8 @@
}
}
- @SuppressLint("BanUncheckedReflection")
void dispatchLifecycleEvent(Event event) {
- // Use reflection to call internal APIs for testing purposes.
- try {
- Method method = Screen.class.getDeclaredMethod("dispatchLifecycleEvent", Event.class);
- method.setAccessible(true);
- method.invoke(mScreen, event);
- } catch (ReflectiveOperationException e) {
- throw new IllegalStateException("Failed dispatching lifecycle event", e);
- }
+ mScreen.dispatchLifecycleEvent(event);
}
/**
diff --git a/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java b/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java
index e5f9396..3e44d4c 100644
--- a/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java
+++ b/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java
@@ -28,10 +28,8 @@
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
-import java.lang.reflect.Field;
-
/**
- * A controller that allows testing of a {@link Session}.
+ * {@link SessionController} provides API that allows testing of a {@link Session}.
*
* <p>This controller allows:
*
@@ -64,19 +62,8 @@
mLifecycleOwner = new TestLifecycleOwner();
mLifecycleOwner.getRegistry().addObserver(new SessionLifecycleObserver());
- // Use reflection to inject the TestCarContext into the Session.
- try {
- Field registry = Session.class.getDeclaredField("mRegistry");
- registry.setAccessible(true);
- registry.set(session, mTestCarContext.getLifecycleOwner().mRegistry);
-
- Field carContext = Session.class.getDeclaredField("mCarContext");
- carContext.setAccessible(true);
- carContext.set(session, mTestCarContext);
- } catch (ReflectiveOperationException e) {
- throw new IllegalStateException(
- "Failed to set internal Session values for testing", e);
- }
+ mSession.setCarContextInternal(mTestCarContext);
+ mSession.setLifecycleRegistryInternal(mTestCarContext.getLifecycleOwner().getRegistry());
}
/** Returns the {@link Session} that is being controlled. */
diff --git a/car/app/app-testing/src/main/java/androidx/car/app/testing/TestCarContext.java b/car/app/app-testing/src/main/java/androidx/car/app/testing/TestCarContext.java
index 83c964e..2878e94 100644
--- a/car/app/app-testing/src/main/java/androidx/car/app/testing/TestCarContext.java
+++ b/car/app/app-testing/src/main/java/androidx/car/app/testing/TestCarContext.java
@@ -20,7 +20,6 @@
import static java.util.Objects.requireNonNull;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
@@ -36,7 +35,6 @@
import androidx.car.app.testing.navigation.TestNavigationManager;
import androidx.car.app.utils.CollectionUtils;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -141,7 +139,6 @@
*
* @throws NullPointerException if {@code testContext} is null
*/
- @SuppressLint("BanUncheckedReflection")
@NonNull
public static TestCarContext createCarContext(@NonNull Context testContext) {
requireNonNull(testContext);
@@ -149,14 +146,7 @@
TestCarContext carContext = new TestCarContext(new TestLifecycleOwner(),
new HostDispatcher());
carContext.attachBaseContext(testContext);
-
- try {
- Method method = CarContext.class.getDeclaredMethod("setCarHost", ICarHost.class);
- method.setAccessible(true);
- method.invoke(carContext, carContext.mFakeHost.getCarHost());
- } catch (ReflectiveOperationException e) {
- throw new IllegalStateException("Failed to attach the base context", e);
- }
+ carContext.setCarHost(carContext.mFakeHost.getCarHost());
return carContext;
}
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/ScreenControllerTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/ScreenControllerTest.java
index bda6d01..2c21047 100644
--- a/car/app/app-testing/src/test/java/androidx/car/app/testing/ScreenControllerTest.java
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/ScreenControllerTest.java
@@ -47,16 +47,7 @@
private final Template mTemplate = new Template() {
};
- private final Screen mTestScreen =
- new Screen(
- TestCarContext.createCarContext(ApplicationProvider.getApplicationContext())) {
- @NonNull
- @Override
- public Template onGetTemplate() {
- return mTemplate;
- }
- };
-
+ private Screen mTestScreen;
private ScreenController mScreenController;
private TestCarContext mCarContext;
@@ -65,7 +56,14 @@
MockitoAnnotations.initMocks(this);
mCarContext = TestCarContext.createCarContext(ApplicationProvider.getApplicationContext());
- mScreenController = new ScreenController(mCarContext, mTestScreen);
+ mTestScreen = new Screen(mCarContext) {
+ @NonNull
+ @Override
+ public Template onGetTemplate() {
+ return mTemplate;
+ }
+ };
+ mScreenController = new ScreenController(mTestScreen);
mTestScreen.getLifecycle().addObserver(mMockObserver);
}
@@ -160,16 +158,6 @@
}
@Test
- public void getScreenResult() {
- Screen screen = mScreenController.getScreen();
- String result = "this is the result";
-
- screen.setResult(result);
-
- assertThat(mScreenController.getScreenResult()).isEqualTo(result);
- }
-
- @Test
public void reset() {
mScreenController.moveToState(Lifecycle.State.STARTED);
mScreenController.reset();
diff --git a/car/app/app-testing/src/test/resources/robolectric.properties b/car/app/app-testing/src/test/resources/robolectric.properties
index f129cbb..55de435 100644
--- a/car/app/app-testing/src/test/resources/robolectric.properties
+++ b/car/app/app-testing/src/test/resources/robolectric.properties
@@ -14,6 +14,6 @@
# limitations under the License.
#
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
\ No newline at end of file
+sdk=30
diff --git a/car/app/app/build.gradle b/car/app/app/build.gradle
index fa03af6..c6f85d4 100644
--- a/car/app/app/build.gradle
+++ b/car/app/app/build.gradle
@@ -174,7 +174,9 @@
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
- FileCollection inputSourceDirs = project.files() // Re-run on source changes
+ def getInputSource() {
+ return sourceDirs // Re-run on source changes
+ }
@OutputFile
File generatedApi
@@ -202,6 +204,10 @@
File currentApi
@InputFile
+ @Optional
+ File previousApi
+
+ @InputFile
File generatedApi
def summarizeDiff(File a, File b) {
@@ -226,15 +232,22 @@
@TaskAction
def exec() {
- if (currentApi == null) {
+ if (currentApi == null && previousApi == null) {
return
}
- if (!FileUtils.contentEquals(currentApi, generatedApi)) {
- String diff = summarizeDiff(currentApi, generatedApi)
+ File apiFile
+ if (currentApi != null) {
+ apiFile = currentApi
+ } else {
+ apiFile = previousApi
+ }
+
+ if (!FileUtils.contentEquals(apiFile, generatedApi)) {
+ String diff = summarizeDiff(apiFile, generatedApi)
String message = """API definition has changed
- Declared definition is $currentApi
+ Declared definition is $apiFile
True definition is $generatedApi
Please run `./gradlew updateProtocolApi` to confirm these changes are
@@ -283,14 +296,13 @@
// Update protocol API signature file for current Car API level to reflect the state of current
// protocol API in the project.
class UpdateProtocolApiTask extends DefaultTask {
- @InputDirectory
+ @Internal
File protocolDir
@InputFile
File generatedApi
- @InputFile
- @Optional
+ @Internal
File currentApi
@TaskAction
@@ -300,6 +312,10 @@
File updatedApi = new File(protocolDir, String.format(
"protocol-%s_%s.txt", project.latestCarAppApiLevel, project.version))
+ if (currentApi != null && FileUtils.contentEquals(currentApi, generatedApi)) {
+ return
+ }
+
// Determine whether this API level was previously released by checking whether the project
// version matches
boolean alreadyReleased = currentApi != updatedApi
@@ -308,13 +324,7 @@
// non-final)
boolean isCurrentApiFinal = false
if (currentApi != null) {
- String currentApiFileName = currentApi.name
- int versionStart = currentApiFileName.indexOf("_")
- int versionEnd = currentApiFileName.indexOf(".txt")
-
- String parsedCurrentVersion = currentApiFileName.substring(versionStart + 1, versionEnd)
- Version currentVersion = new Version(parsedCurrentVersion)
- isCurrentApiFinal = currentVersion.isFinalApi()
+ isCurrentApiFinal = ProtocolLocation.parseVersion(currentApi).isFinalApi()
}
if (currentApi != null && alreadyReleased && isCurrentApiFinal) {
@@ -322,7 +332,7 @@
"Car API level before making protocol API changes")
}
- // Overwrite protocol API signature file for current Car API level
+ // Create new protocol API signature file for current Car API level
Files.copy(generatedApi, updatedApi)
}
}
@@ -350,6 +360,13 @@
File currentApi
File previousApi
+ static Version parseVersion(File file) {
+ int versionStart = file.name.indexOf("_")
+ int versionEnd = file.name.indexOf(".txt")
+ String parsedCurrentVersion = file.name.substring(versionStart + 1, versionEnd)
+ return new Version(parsedCurrentVersion)
+ }
+
def getProtocolApiFile(int carApiLevel) {
File[] apiFiles = protocolDir.listFiles(new FilenameFilter() {
boolean accept(File dir, String name) {
@@ -360,15 +377,18 @@
if (apiFiles == null || apiFiles.size() == 0) {
return null
} else if (apiFiles.size() > 1) {
- StringBuilder builder = new StringBuilder()
- for (File file : currentApis) {
- builder.append(file.path)
- builder.append("\n")
- }
+ File latestApiFile = apiFiles[0]
+ Version latestVersion = parseVersion(latestApiFile)
+ for (int i = 1; i < apiFiles.size(); i++) {
+ File file = apiFiles[i]
+ Version fileVersion = parseVersion(file)
+ if (fileVersion > latestVersion) {
+ latestApiFile = file
+ latestVersion = fileVersion
+ }
- throw new GradleException(
- String.format("Multiple API signature files found for Car API level %s\n%s",
- carApiLevel, builder.toString()))
+ }
+ return latestApiFile
}
return apiFiles[0]
@@ -415,15 +435,14 @@
}
task checkProtocolApiCompat(type: CheckProtocolApiCompatibilityTask) {
description = "Check for BREAKING changes to the protocol API"
- if (projectProtocolLocation.previousApi != null) {
- previousApi = projectProtocolLocation.previousApi
- }
+ previousApi = projectProtocolLocation.previousApi
generatedApi = projectProtocolLocation.generatedApi
dependsOn(generateProtocolApi)
}
task checkProtocolApi(type: CheckProtocolApiTask) {
description = "Check for changes to the protocol API"
generatedApi = projectProtocolLocation.generatedApi
+ previousApi = projectProtocolLocation.previousApi
currentApi = projectProtocolLocation.currentApi
dependsOn(checkProtocolApiCompat)
}
diff --git a/car/app/app/src/main/java/androidx/car/app/CarContext.java b/car/app/app/src/main/java/androidx/car/app/CarContext.java
index 63ec084..239c2c5 100644
--- a/car/app/app/src/main/java/androidx/car/app/CarContext.java
+++ b/car/app/app/src/main/java/androidx/car/app/CarContext.java
@@ -488,6 +488,9 @@
/**
* Returns information about the host attached to this service.
*
+ * <p><b>This method should not be called until the {@link Lifecycle.State} of the context's
+ * {@link Session} is at least {@link Lifecycle.State#CREATED}</b>.
+ *
* @return The {@link HostInfo} of the connected host, or {@code null} if it is not available.
* @see HostInfo
*/
@@ -599,6 +602,14 @@
startActivity(intent);
}
+ /** @hide */
+ @RestrictTo(LIBRARY_GROUP) // Restrict to testing library
+ @MainThread
+ public void setCarHost(@NonNull ICarHost carHost) {
+ ThreadUtils.checkMainThread();
+ mHostDispatcher.setCarHost(requireNonNull(carHost));
+ }
+
/**
* Copies the fields from the provided {@link Configuration} into the {@link Configuration}
* contained in this object.
@@ -687,14 +698,6 @@
}
/** @hide */
- @RestrictTo(LIBRARY_GROUP) // Restrict to testing library
- @MainThread
- void setCarHost(@NonNull ICarHost carHost) {
- ThreadUtils.checkMainThread();
- mHostDispatcher.setCarHost(requireNonNull(carHost));
- }
-
- /** @hide */
@RestrictTo(LIBRARY_GROUP)
// Restrict to testing library
ManagerCache getManagers() {
diff --git a/car/app/app/src/main/java/androidx/car/app/Screen.java b/car/app/app/src/main/java/androidx/car/app/Screen.java
index 4ccc013..e5c85b2 100644
--- a/car/app/app/src/main/java/androidx/car/app/Screen.java
+++ b/car/app/app/src/main/java/androidx/car/app/Screen.java
@@ -136,6 +136,17 @@
}
/**
+ * Returns the result set via {@link #setResult}, or {@code null} if none is set.
+ *
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ @Nullable
+ public Object getResultInternal() {
+ return mResult;
+ }
+
+ /**
* Updates the marker for this screen.
*
* <p>Set the {@code marker} to {@code null} to clear it.
@@ -315,7 +326,7 @@
*/
@RestrictTo(LIBRARY_GROUP)
// Restrict to testing library
- void dispatchLifecycleEvent(Event event) {
+ public void dispatchLifecycleEvent(@NonNull Event event) {
ThreadUtils.runOnMain(
() -> {
State currentState = mLifecycleRegistry.getCurrentState();
diff --git a/car/app/app/src/main/java/androidx/car/app/Session.java b/car/app/app/src/main/java/androidx/car/app/Session.java
index de5960f..ecbe43c 100644
--- a/car/app/app/src/main/java/androidx/car/app/Session.java
+++ b/car/app/app/src/main/java/androidx/car/app/Session.java
@@ -21,11 +21,15 @@
import android.content.res.Configuration;
import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
+import java.util.Objects;
+
/**
* The base class for implementing a session for a car app.
*/
@@ -38,12 +42,14 @@
* guarantees that apps listening to the session's lifecycle will get the events in the correct
* order (e.g. start and destroy) compared to other artifacts within a session (e.g. screens).
*/
- private final LifecycleRegistry mRegistry;
+ private LifecycleRegistry mRegistry;
/**
* The external {@link LifecycleRegistry} that apps can register observers to.
*/
final LifecycleRegistry mRegistryPublic;
- private final CarContext mCarContext;
+ private CarContext mCarContext;
+
+ private final LifecycleObserver mLifecycleObserver = new LifecycleObserverImpl();
public Session() {
mRegistry = new LifecycleRegistry(this);
@@ -53,7 +59,7 @@
// LifecycleRegistry first, because that's the one apps will use to observer lifecycle
// events related to the Session, and we want them to wrap around the events of everything
// else that happens within the session (e.g. Screen lifecycles).
- mRegistry.addObserver(new LifecycleObserverImpl());
+ mRegistry.addObserver(mLifecycleObserver);
mCarContext = CarContext.create(mRegistry);
}
@@ -173,18 +179,35 @@
}
/**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // used by the testing library.
+ public void setLifecycleRegistryInternal(@NonNull LifecycleRegistry registry) {
+ mRegistry = registry;
+ mRegistry.addObserver(mLifecycleObserver);
+ }
+
+ /**
* Returns the {@link CarContext} for this session.
*
- * <p><b>The {@link CarContext} is not fully initialized until this session's {@link
- * Lifecycle.State} is at least {@link Lifecycle.State#CREATED}</b>. Some instance methods
- * should not be called before this state has been reached. See the documentation in
- * {@link CarContext} for details on any such restrictions.
+ * <p><b>The {@link CarContext} is not expected to be available until this session's {@link
+ * Lifecycle.State} is at least {@link Lifecycle.State#CREATED}</b>. Further, some instance
+ * methods within {@link CarContext} should not be called before this state has been reached.
+ * See the documentation in {@link CarContext} for details on any such restrictions.
*
* @see #getLifecycle
*/
@NonNull
public final CarContext getCarContext() {
- return mCarContext;
+ return Objects.requireNonNull(mCarContext);
+ }
+
+ /**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // used by the testing library.
+ public void setCarContextInternal(@NonNull CarContext carContext) {
+ mCarContext = carContext;
}
/**
diff --git a/car/app/app/src/main/java/androidx/car/app/hardware/CarHardwareManager.java b/car/app/app/src/main/java/androidx/car/app/hardware/CarHardwareManager.java
index 59d9f3f..dbb14bf7 100644
--- a/car/app/app/src/main/java/androidx/car/app/hardware/CarHardwareManager.java
+++ b/car/app/app/src/main/java/androidx/car/app/hardware/CarHardwareManager.java
@@ -24,10 +24,12 @@
import androidx.annotation.RestrictTo;
import androidx.car.app.CarContext;
import androidx.car.app.HostDispatcher;
+import androidx.car.app.HostException;
import androidx.car.app.annotations.RequiresCarApi;
import androidx.car.app.hardware.info.CarInfo;
import androidx.car.app.hardware.info.CarSensors;
import androidx.car.app.managers.Manager;
+import androidx.car.app.versioning.CarAppApiLevels;
import java.lang.reflect.Constructor;
@@ -59,13 +61,20 @@
*
* @throws IllegalStateException if none of the supported classes are found or if a supported
* class was found but the constructor was mismatched
+ * @throws HostException if the negotiated api level is less than
+ * {@link CarAppApiLevels#LEVEL_3}
* @hide
*/
@RestrictTo(LIBRARY)
@NonNull
static CarHardwareManager create(@NonNull CarContext context,
- @NonNull HostDispatcher hostDispatcher) throws IllegalStateException {
- // TODO(b/192493839) : Switch to using Manager.create
+ @NonNull HostDispatcher hostDispatcher) {
+ if (context.getCarAppApiLevel() < CarAppApiLevels.LEVEL_3) {
+ throw new HostException("Create CarHardwareManager failed",
+ new IllegalArgumentException("Attempted to retrieve CarHardwareManager "
+ + "service, but the host is less than " + CarAppApiLevels.LEVEL_3));
+ }
+
try { // Check for automotive library first.
Class<?> c = Class.forName("androidx.car.app.hardware.AutomotiveCarHardwareManager");
Constructor<?> ctor = c.getConstructor(Context.class);
@@ -78,7 +87,7 @@
throw new IllegalStateException("Mismatch with app-automotive artifact", e);
}
- try { // Check for automotive library first.
+ try { // Check for projected library.
Class<?> c = Class.forName("androidx.car.app.hardware.ProjectedCarHardwareManager");
Constructor<?> ctor = c.getConstructor(HostDispatcher.class);
Object object = ctor.newInstance(hostDispatcher);
diff --git a/car/app/app/src/main/java/androidx/car/app/model/ActionStrip.java b/car/app/app/src/main/java/androidx/car/app/model/ActionStrip.java
index 1909ecb..3d75968a 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/ActionStrip.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/ActionStrip.java
@@ -23,6 +23,7 @@
import androidx.annotation.Nullable;
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.model.Action.ActionType;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.utils.CollectionUtils;
import java.util.ArrayList;
@@ -122,7 +123,8 @@
*
* @throws IllegalArgumentException if the background color of the action is specified,
* or if {@code action} is a standard action and an
- * action of the same type has already been added
+ * action of the same type has already been added, of if
+ * the {@code action}'s title contains unsupported spans.
* @throws NullPointerException if {@code action} is {@code null}
*/
@NonNull
@@ -137,6 +139,11 @@
throw new IllegalArgumentException(
"Action strip actions don't support background colors");
}
+ CarText title = action.getTitle();
+ if (title != null) {
+ CarTextConstraints.CONSERVATIVE.validateOrThrow(title);
+ }
+
mAddedActionTypes.add(actionType);
mActions.add(action);
return this;
diff --git a/car/app/app/src/main/java/androidx/car/app/model/CarText.java b/car/app/app/src/main/java/androidx/car/app/model/CarText.java
index b31813b..560edb6 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/CarText.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/CarText.java
@@ -167,6 +167,24 @@
}
/**
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(LIBRARY)
+ public List<SpanWrapper> getSpans() {
+ return mSpans;
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(LIBRARY)
+ public List<List<SpanWrapper>> getSpansForVariants() {
+ return mSpansForVariants;
+ }
+
+ /**
* Returns a shortened string from the input {@code text}.
*
* @hide
@@ -255,8 +273,11 @@
/**
* Wraps a span to send it to the host.
+ *
+ * @hide
*/
- private static class SpanWrapper {
+ @RestrictTo(LIBRARY)
+ public static class SpanWrapper {
@Keep
private final int mStart;
@Keep
diff --git a/car/app/app/src/main/java/androidx/car/app/model/GridItem.java b/car/app/app/src/main/java/androidx/car/app/model/GridItem.java
index 9e191cd..4b410d0 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/GridItem.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/GridItem.java
@@ -31,6 +31,7 @@
import androidx.car.app.Screen;
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.model.constraints.CarIconConstraints;
+import androidx.car.app.model.constraints.CarTextConstraints;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -233,10 +234,12 @@
/**
* Sets the title of the {@link GridItem}.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
* @throws NullPointerException if {@code title} is {@code null}
- * @throws IllegalArgumentException if {@code title} is empty
+ * @throws IllegalArgumentException if {@code title} is empty, of if it contains
+ * unsupported spans
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
@@ -244,6 +247,7 @@
if (titleText.isEmpty()) {
throw new IllegalArgumentException("The title cannot be null or empty");
}
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(titleText);
mTitle = titleText;
return this;
}
@@ -251,16 +255,19 @@
/**
* Sets the title of the {@link GridItem}, with support for multiple length variants.,
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
* @throws NullPointerException if {@code title} is {@code null}
- * @throws IllegalArgumentException if {@code title} is empty
+ * @throws IllegalArgumentException if {@code title} is empty, of if it contains
+ * unsupported spans
*/
@NonNull
public Builder setTitle(@NonNull CarText title) {
if (CarText.isNullOrEmpty(title)) {
throw new IllegalArgumentException("The title cannot be null or empty");
}
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(title);
mTitle = title;
return this;
}
@@ -268,18 +275,22 @@
/**
* Sets a secondary text string to the grid item that is displayed below the title.
*
- * <p>The text's color can be customized with {@link ForegroundCarColorSpan} instances, any
- * other spans will be ignored by the host.
+ * <p>The text can be customized with {@link ForegroundCarColorSpan},
+ * {@link androidx.car.app.model.DistanceSpan}, and
+ * {@link androidx.car.app.model.DurationSpan} instances, any other spans will be ignored
+ * by the host.
*
* <h2>Text Wrapping</h2>
*
* This text is truncated at the end to fit in a single line below the title
*
- * @throws NullPointerException if {@code text} is {@code null}
+ * @throws NullPointerException if {@code text} is {@code null}
+ * @throws IllegalArgumentException if {@code text} contains unsupported spans
*/
@NonNull
public Builder setText(@NonNull CharSequence text) {
mText = CarText.create(requireNonNull(text));
+ CarTextConstraints.TEXT_WITH_COLORS.validateOrThrow(mText);
return this;
}
@@ -287,18 +298,22 @@
* Sets a secondary text string to the grid item that is displayed below the title, with
* support for multiple length variants.
*
- * <p>The text's color can be customized with {@link ForegroundCarColorSpan} instances, any
- * other spans will be ignored by the host.
+ * <p>The text can be customized with {@link ForegroundCarColorSpan},
+ * {@link androidx.car.app.model.DistanceSpan}, and
+ * {@link androidx.car.app.model.DurationSpan} instances, any other spans will be ignored
+ * by the host.
*
* <h2>Text Wrapping</h2>
*
* This text is truncated at the end to fit in a single line below the title
*
* @throws NullPointerException if {@code text} is {@code null}
+ * @throws IllegalArgumentException if {@code text} contains unsupported spans
*/
@NonNull
public Builder setText(@NonNull CarText text) {
mText = requireNonNull(text);
+ CarTextConstraints.TEXT_WITH_COLORS.validateOrThrow(mText);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
index 24a600c..82a41f5 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
@@ -25,6 +25,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.model.constraints.CarTextConstraints;
import java.util.Collections;
import java.util.Objects;
@@ -210,13 +211,16 @@
*
* <p>Unless set with this method, the template will not have a title.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is null
+ * @throws NullPointerException if {@code title} is null
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java
index 787edb6..93751f7 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java
@@ -27,6 +27,7 @@
import androidx.annotation.Nullable;
import androidx.car.app.Screen;
import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.utils.CollectionUtils;
import java.util.ArrayList;
@@ -241,13 +242,16 @@
*
* <p>Unless set with this method, the template will not have a title.
*
- * <p>Spans are not supported in the title of the action and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is null
+ * @throws NullPointerException if {@code title} is null
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/LongMessageTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/LongMessageTemplate.java
index 7c0498a..cd256a2 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/LongMessageTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/LongMessageTemplate.java
@@ -27,6 +27,7 @@
import androidx.annotation.Nullable;
import androidx.car.app.Screen;
import androidx.car.app.annotations.RequiresCarApi;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.utils.CollectionUtils;
import java.util.ArrayList;
@@ -175,14 +176,17 @@
*
* <p>Unless set with this method, the template will not have a title.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is {@code null}
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
@@ -238,8 +242,8 @@
* This template allows up to 2 {@link Action}s in its body, and they must use a
* {@link androidx.car.app.model.ParkedOnlyOnClickListener}.
*
- * <p>Each action's title color can be customized with {@link ForegroundCarColorSpan}
- * instances, any other spans will be ignored by the host.
+ * Each action's title color can be customized with {@link ForegroundCarColorSpan}
+ * instances. Any other span is not supported.
*
* @throws IllegalArgumentException if {@code action} does not meet the requirements
* @throws NullPointerException if {@code action} is {@code null}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java
index 0434b6e..0f94d25 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java
@@ -31,6 +31,7 @@
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.annotations.RequiresCarApi;
import androidx.car.app.model.constraints.CarIconConstraints;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.utils.CollectionUtils;
import java.util.ArrayList;
@@ -250,14 +251,17 @@
*
* <p>Unless set with this method, the template will not have a title.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is {@code null}
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
@@ -371,9 +375,9 @@
*
* <h4>Requirements</h4>
*
- * This template allows up to 2 {@link Action}s in its body. The action's title color can
- * be customized with {@link ForegroundCarColorSpan} instances, any other spans will be
- * ignored by the host.
+ * This template allows up to 2 {@link Action}s in its body. Each action's title color
+ * can be customized with {@link ForegroundCarColorSpan} instances. Any other span is not
+ * supported.
*
* @throws NullPointerException if {@code action} is {@code null}
* @throws IllegalArgumentException if {@code action} does not meet the requirements
diff --git a/car/app/app/src/main/java/androidx/car/app/model/Pane.java b/car/app/app/src/main/java/androidx/car/app/model/Pane.java
index 493f884..f2378f5 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/Pane.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/Pane.java
@@ -149,10 +149,7 @@
*
* <p>By default, no actions are displayed.
*
- * <p>The action's title color can be customized with {@link ForegroundCarColorSpan}
- * instances, any other spans will be ignored by the host.
- *
- * @throws NullPointerException if {@code action} is {@code null}
+ * @throws NullPointerException if {@code action} is {@code null}
*/
@NonNull
public Builder addAction(@NonNull Action action) {
diff --git a/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
index 9db41f9..27566cb 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
@@ -16,6 +16,7 @@
package androidx.car.app.model;
+import static androidx.car.app.model.constraints.ActionsConstraints.ACTIONS_CONSTRAINTS_BODY;
import static androidx.car.app.model.constraints.ActionsConstraints.ACTIONS_CONSTRAINTS_HEADER;
import static androidx.car.app.model.constraints.ActionsConstraints.ACTIONS_CONSTRAINTS_SIMPLE;
import static androidx.car.app.model.constraints.RowListConstraints.ROW_LIST_CONSTRAINTS_PANE;
@@ -26,6 +27,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.model.constraints.CarTextConstraints;
import java.util.Collections;
import java.util.Objects;
@@ -158,14 +160,17 @@
*
* <p>Unless set with this method, the template will not have a title.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is {@code null}
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
@@ -224,8 +229,11 @@
* via {@link Row.Builder#addText} and cannot contain either a {@link Toggle} or a {@link
* OnClickListener}.
*
- * <p>Up to 2 {@link Action}s are allowed in the {@link Pane}, and either a header
- * {@link Action} or title must be set on the template.
+ * <p>Up to 2 {@link Action}s are allowed in the {@link Pane}. Each action's title color
+ * can be customized with {@link ForegroundCarColorSpan} instances. Any other span is not
+ * supported.
+ *
+ * <p>Either a header {@link Action} or title must be set on the template.
*
* @throws IllegalArgumentException if the {@link Pane} does not meet the requirements
* @throws IllegalStateException if the template does not have either a title or header
@@ -235,6 +243,7 @@
@NonNull
public PaneTemplate build() {
ROW_LIST_CONSTRAINTS_PANE.validateOrThrow(mPane);
+ ACTIONS_CONSTRAINTS_BODY.validateOrThrow(mPane.getActions());
if (CarText.isNullOrEmpty(mTitle) && mHeaderAction == null) {
throw new IllegalStateException("Either the title or header action must be set");
diff --git a/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java
index a3130d1..d525866 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java
@@ -26,6 +26,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.model.constraints.CarTextConstraints;
import java.util.Collections;
import java.util.List;
@@ -259,28 +260,34 @@
/**
* Sets the title of the template.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is {@code null}
+ * @throws NullPointerException if {@code title} is null
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
/**
* Sets the title of the template, with support for multiple length variants.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is {@code null}
+ * @throws NullPointerException if {@code title} is null
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CarText title) {
mTitle = requireNonNull(title);
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/Row.java b/car/app/app/src/main/java/androidx/car/app/model/Row.java
index 5040901..101fe8c 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/Row.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/Row.java
@@ -31,6 +31,7 @@
import androidx.annotation.RestrictTo;
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.model.constraints.CarIconConstraints;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.utils.CollectionUtils;
import java.lang.annotation.Retention;
@@ -300,10 +301,12 @@
/**
* Sets the title of the row.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
* @throws NullPointerException if {@code title} is {@code null}
- * @throws IllegalArgumentException if {@code title} is empty
+ * @throws IllegalArgumentException if {@code title} is empty, of if it contains
+ * unsupported spans
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
@@ -311,6 +314,7 @@
if (titleText.isEmpty()) {
throw new IllegalArgumentException("The title cannot be null or empty");
}
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(titleText);
mTitle = titleText;
return this;
}
@@ -318,15 +322,19 @@
/**
* Sets the title of the row, with support for multiple length variants.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws IllegalArgumentException if {@code title} is {@code null} or empty
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} is empty, of if it contains
+ * unsupported spans
*/
@NonNull
public Builder setTitle(@NonNull CarText title) {
if (requireNonNull(title).isEmpty()) {
throw new IllegalArgumentException("The title cannot be null or empty");
}
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(title);
mTitle = title;
return this;
}
@@ -334,8 +342,10 @@
/**
* Adds a text string to the row below the title.
*
- * <p>The text's color can be customized with {@link ForegroundCarColorSpan} instances, any
- * other spans will be ignored by the host.
+ * <p>The text can be customized with {@link ForegroundCarColorSpan},
+ * {@link androidx.car.app.model.DistanceSpan}, and
+ * {@link androidx.car.app.model.DurationSpan} instances, any other spans will be ignored
+ * by the host.
*
* <p>Most templates allow up to 2 text strings, but this may vary. This limit is
* documented in each individual template.
@@ -393,11 +403,14 @@
* of text
* </pre>
*
- * @throws NullPointerException if {@code text} is {@code null}
+ * @throws NullPointerException if {@code text} is {@code null}
+ * @throws IllegalArgumentException if {@code text} contains unsupported spans
* @see ForegroundCarColorSpan
*/
@NonNull
public Builder addText(@NonNull CharSequence text) {
+ CarText carText = CarText.create(requireNonNull(text));
+ CarTextConstraints.TEXT_WITH_COLORS.validateOrThrow(carText);
mTexts.add(CarText.create(requireNonNull(text)));
return this;
}
@@ -405,12 +418,14 @@
/**
* Adds a text string to the row below the title, with support for multiple length variants.
*
- * @throws NullPointerException if {@code text} is {@code null}
+ * @throws NullPointerException if {@code text} is {@code null}
+ * @throws IllegalArgumentException if {@code text} contains unsupported spans
* @see Builder#addText(CharSequence)
*/
@NonNull
public Builder addText(@NonNull CarText text) {
- mTexts.add(requireNonNull(text));
+ CarTextConstraints.TEXT_WITH_COLORS.validateOrThrow(requireNonNull(text));
+ mTexts.add(text);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/SectionedItemList.java b/car/app/app/src/main/java/androidx/car/app/model/SectionedItemList.java
index b2f94b0..1c49eb5 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/SectionedItemList.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/SectionedItemList.java
@@ -22,6 +22,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.model.constraints.CarTextConstraints;
import java.util.Objects;
@@ -40,12 +41,17 @@
/**
* Creates an instance of a {@link SectionedItemList} with the given {@code itemList} and
* {@code sectionHeader}.
+ *
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the section header.
+ *
+ * @throws IllegalArgumentException if {@code sectionHeader} contains unsupported spans
*/
@NonNull
public static SectionedItemList create(
@NonNull ItemList itemList, @NonNull CharSequence sectionHeader) {
- return new SectionedItemList(requireNonNull(itemList),
- CarText.create(requireNonNull(sectionHeader)));
+ CarText sectionHeaderText = CarText.create(requireNonNull(sectionHeader));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(sectionHeaderText);
+ return new SectionedItemList(requireNonNull(itemList), sectionHeaderText);
}
/** Returns the {@link ItemList} for the section. */
diff --git a/car/app/app/src/main/java/androidx/car/app/model/constraints/ActionsConstraints.java b/car/app/app/src/main/java/androidx/car/app/model/constraints/ActionsConstraints.java
index 3350af3..b2ac358 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/constraints/ActionsConstraints.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/constraints/ActionsConstraints.java
@@ -44,7 +44,10 @@
/** Conservative constraints for most template types. */
@NonNull
private static final ActionsConstraints ACTIONS_CONSTRAINTS_CONSERVATIVE =
- new ActionsConstraints.Builder().setMaxActions(2).build();
+ new ActionsConstraints.Builder()
+ .setTitleTextConstraints(CarTextConstraints.CONSERVATIVE)
+ .setMaxActions(2)
+ .build();
/**
* Constraints for actions within the template body.
@@ -52,7 +55,9 @@
@NonNull
public static final ActionsConstraints ACTIONS_CONSTRAINTS_BODY =
new ActionsConstraints.Builder(ACTIONS_CONSTRAINTS_CONSERVATIVE)
- .setMaxCustomTitles(2).build();
+ .setTitleTextConstraints(CarTextConstraints.COLOR_ONLY)
+ .setMaxCustomTitles(2)
+ .build();
/**
* Constraints for template headers, where only the special-purpose back and app-icon standard
@@ -60,17 +65,21 @@
*/
@NonNull
public static final ActionsConstraints ACTIONS_CONSTRAINTS_HEADER =
- new ActionsConstraints.Builder().setMaxActions(1).addDisallowedActionType(
- Action.TYPE_CUSTOM).build();
+ new ActionsConstraints.Builder()
+ .setMaxActions(1)
+ .addDisallowedActionType(Action.TYPE_CUSTOM)
+ .build();
/**
* Default constraints that should be applied to most templates (2 actions, 1 can have
- * title).
+ * title)'s {@link androidx.car.app.model.ActionStrip}.
*/
@NonNull
public static final ActionsConstraints ACTIONS_CONSTRAINTS_SIMPLE =
- new ActionsConstraints.Builder(ACTIONS_CONSTRAINTS_CONSERVATIVE).setMaxCustomTitles(
- 1).build();
+ new ActionsConstraints.Builder(ACTIONS_CONSTRAINTS_CONSERVATIVE)
+ .setMaxCustomTitles(1)
+ .setTitleTextConstraints(CarTextConstraints.TEXT_ONLY)
+ .build();
/** Constraints for navigation templates. */
@NonNull
@@ -78,7 +87,9 @@
new ActionsConstraints.Builder(ACTIONS_CONSTRAINTS_CONSERVATIVE)
.setMaxActions(4)
.setMaxCustomTitles(1)
+ // Must specify a custom stop action.
.addRequiredActionType(Action.TYPE_CUSTOM)
+ .setTitleTextConstraints(CarTextConstraints.TEXT_ONLY)
.build();
/**
@@ -94,6 +105,7 @@
private final int mMaxActions;
private final int mMaxCustomTitles;
+ private final CarTextConstraints mTitleTextConstraints;
private final Set<Integer> mRequiredActionTypes;
private final Set<Integer> mDisallowedActionTypes;
@@ -107,6 +119,12 @@
return mMaxCustomTitles;
}
+ /** Returns the {@link CarTextConstraints} fpr the title. */
+ @NonNull
+ public CarTextConstraints getTitleTextConstraints() {
+ return mTitleTextConstraints;
+ }
+
/** Adds the set of required action types. */
@NonNull
public Set<Integer> getRequiredActionTypes() {
@@ -152,6 +170,8 @@
+ mMaxCustomTitles
+ " actions with custom titles");
}
+
+ mTitleTextConstraints.validateOrThrow(title);
}
if (--maxAllowedActions < 0) {
@@ -173,6 +193,7 @@
ActionsConstraints(Builder builder) {
mMaxActions = builder.mMaxActions;
mMaxCustomTitles = builder.mMaxCustomTitles;
+ mTitleTextConstraints = builder.mTitleTextConstraints;
mRequiredActionTypes = new HashSet<>(builder.mRequiredActionTypes);
if (!builder.mDisallowedActionTypes.isEmpty()) {
@@ -198,6 +219,7 @@
public static final class Builder {
int mMaxActions = Integer.MAX_VALUE;
int mMaxCustomTitles;
+ CarTextConstraints mTitleTextConstraints = CarTextConstraints.UNCONSTRAINED;
final Set<Integer> mRequiredActionTypes = new HashSet<>();
final Set<Integer> mDisallowedActionTypes = new HashSet<>();
@@ -215,6 +237,13 @@
return this;
}
+ /** Sets the {@link CarTextConstraints} for the title. */
+ @NonNull
+ public Builder setTitleTextConstraints(@NonNull CarTextConstraints carTextConstraints) {
+ mTitleTextConstraints = carTextConstraints;
+ return this;
+ }
+
/** Adds an action type to the set of required types. */
@NonNull
public Builder addRequiredActionType(@ActionType int actionType) {
@@ -251,6 +280,7 @@
requireNonNull(constraints);
mMaxActions = constraints.getMaxActions();
mMaxCustomTitles = constraints.getMaxCustomTitles();
+ mTitleTextConstraints = constraints.getTitleTextConstraints();
mRequiredActionTypes.addAll(constraints.getRequiredActionTypes());
mDisallowedActionTypes.addAll(constraints.getDisallowedActionTypes());
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/constraints/CarTextConstraints.java b/car/app/app/src/main/java/androidx/car/app/model/constraints/CarTextConstraints.java
new file mode 100644
index 0000000..bba4a06
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/model/constraints/CarTextConstraints.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model.constraints;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.car.app.model.CarIconSpan;
+import androidx.car.app.model.CarSpan;
+import androidx.car.app.model.CarText;
+import androidx.car.app.model.ClickableSpan;
+import androidx.car.app.model.DistanceSpan;
+import androidx.car.app.model.DurationSpan;
+import androidx.car.app.model.ForegroundCarColorSpan;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Encapsulates the constraints to apply when rendering a {@link CarText} on a template.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public final class CarTextConstraints {
+ /** No {@link CarSpan}s allowed. */
+ @NonNull
+ public static final CarTextConstraints CONSERVATIVE =
+ new CarTextConstraints(Collections.emptyList());
+
+ /** Allow all {@link CarSpan}s. */
+ @NonNull
+ public static final CarTextConstraints UNCONSTRAINED =
+ new CarTextConstraints(Arrays.asList(
+ CarIconSpan.class,
+ ClickableSpan.class,
+ DistanceSpan.class,
+ DurationSpan.class,
+ ForegroundCarColorSpan.class));
+
+ /** Allow clickable text-only {@link CarSpan}s. */
+ @NonNull
+ public static final CarTextConstraints CLICKABLE_TEXT_ONLY =
+ new CarTextConstraints(Arrays.asList(
+ ClickableSpan.class,
+ DistanceSpan.class,
+ DurationSpan.class));
+
+ /** Allow color-only {@link CarSpan}s. */
+ @NonNull
+ public static final CarTextConstraints COLOR_ONLY =
+ new CarTextConstraints(Arrays.asList(ForegroundCarColorSpan.class));
+
+ /** Allow text-only {@link CarSpan}s. */
+ @NonNull
+ public static final CarTextConstraints TEXT_ONLY =
+ new CarTextConstraints(Arrays.asList(
+ DistanceSpan.class,
+ DurationSpan.class));
+
+ /** Allow text and icon {@link CarSpan}s. */
+ @NonNull
+ public static final CarTextConstraints TEXT_AND_ICON =
+ new CarTextConstraints(Arrays.asList(
+ DistanceSpan.class,
+ DurationSpan.class,
+ CarIconSpan.class));
+
+ /** Allow text and color {@link CarSpan}s. */
+ @NonNull
+ public static final CarTextConstraints TEXT_WITH_COLORS =
+ new CarTextConstraints(Arrays.asList(
+ DistanceSpan.class,
+ DurationSpan.class,
+ ForegroundCarColorSpan.class));
+
+ private final HashSet<Class<? extends CarSpan>> mAllowedTypes;
+
+ /**
+ * Returns {@code true} if the {@link CarText} meets the constraints' requirement.
+ *
+ * @throws IllegalArgumentException if any span types are not allowed
+ */
+ public void validateOrThrow(@NonNull CarText carText) {
+ checkSupportedSpans(carText.getSpans());
+ for (List<CarText.SpanWrapper> variantSpans : carText.getSpansForVariants()) {
+ checkSupportedSpans(variantSpans);
+ }
+ }
+
+ private void checkSupportedSpans(List<CarText.SpanWrapper> spans) {
+ for (CarText.SpanWrapper span : spans) {
+ Class<? extends CarSpan> klass = span.getCarSpan().getClass();
+ if (!mAllowedTypes.contains(klass)) {
+ throw new IllegalArgumentException(
+ "CarSpan type is not allowed: " + klass.getSimpleName());
+ }
+ }
+ }
+
+ private CarTextConstraints(List<Class<? extends CarSpan>> allowedSpans) {
+ mAllowedTypes = new HashSet<>(allowedSpans);
+ }
+}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/signin/SignInTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/signin/SignInTemplate.java
index 4ea50c7..daa3e12 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/signin/SignInTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/signin/SignInTemplate.java
@@ -19,6 +19,7 @@
import static androidx.car.app.model.constraints.ActionsConstraints.ACTIONS_CONSTRAINTS_BODY;
import static androidx.car.app.model.constraints.ActionsConstraints.ACTIONS_CONSTRAINTS_HEADER;
import static androidx.car.app.model.constraints.ActionsConstraints.ACTIONS_CONSTRAINTS_SIMPLE;
+import static androidx.car.app.model.constraints.CarTextConstraints.CLICKABLE_TEXT_ONLY;
import static java.util.Objects.requireNonNull;
@@ -30,8 +31,11 @@
import androidx.car.app.model.Action;
import androidx.car.app.model.ActionStrip;
import androidx.car.app.model.CarText;
+import androidx.car.app.model.DistanceSpan;
+import androidx.car.app.model.DurationSpan;
import androidx.car.app.model.ForegroundCarColorSpan;
import androidx.car.app.model.Template;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.utils.CollectionUtils;
import java.util.ArrayList;
@@ -301,18 +305,15 @@
/**
* Adds an {@link Action} to display alongside the sign-in content.
*
- * <p>The action's title color can be customized with {@link ForegroundCarColorSpan}
- * instances, any other spans will be ignored by the host.
- *
* <h4>Requirements</h4>
*
* This template allows up to 2 {@link Action}s in its body, and they must use a
* {@link androidx.car.app.model.ParkedOnlyOnClickListener}.
*
* <p>Each action's title color can be customized with {@link ForegroundCarColorSpan}
- * instances, any other spans will be ignored by the host.
+ * instances. Any other span is not supported.
*
- * @throws NullPointerException if {@code action} is {@code null}
+ * @throws NullPointerException if {@code action} is {@code null}
* @throws IllegalArgumentException if {@code action} does not meet the requirements
*/
@NonNull
@@ -333,13 +334,16 @@
*
* <p>Unless set with this method, the template will not have a title.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is {@code null}
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
@@ -348,15 +352,19 @@
*
* <p>Unless set with this method, the template will not have instructions.
*
- * <p>Spans are supported in the input string.
+ * <p>{@link androidx.car.app.model.DistanceSpan},
+ * {@link androidx.car.app.model.DurationSpan}, and
+ * {@link androidx.car.app.model.ForegroundCarColorSpan} are
+ * supported in the input string.
*
- * @throws NullPointerException if {@code instructions} is {@code null}
+ * @throws NullPointerException if {@code instructions} is {@code null}
+ * @throws IllegalArgumentException if {@code instructions} contains unsupported spans
* @see CarText for details on text handling and span support.
*/
- // TODO(b/181569051): document supported span types.
@NonNull
public Builder setInstructions(@NonNull CharSequence instructions) {
mInstructions = CarText.create(requireNonNull(instructions));
+ CarTextConstraints.TEXT_WITH_COLORS.validateOrThrow(mInstructions);
return this;
}
@@ -366,15 +374,18 @@
*
* <p>Unless set with this method, the template will not have additional text.
*
- * <p>Spans are supported in the input string.
+ * <p>{@link androidx.car.app.model.ClickableSpan},
+ * {@link androidx.car.app.model.DistanceSpan}, and
+ * {@link androidx.car.app.model.DurationSpan} are supported in the input string.
*
- * @throws NullPointerException if {@code additionalText} is {@code null}
+ * @throws NullPointerException if {@code additionalText} is {@code null}
+ * @throws IllegalArgumentException if {@code additionalText} contains unsupported spans
* @see CarText
*/
- // TODO(b/181569051): document supported span types.
@NonNull
public Builder setAdditionalText(@NonNull CharSequence additionalText) {
mAdditionalText = CarText.create(requireNonNull(additionalText));
+ CLICKABLE_TEXT_ONLY.validateOrThrow(mAdditionalText);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java
index f2874b0..26e0a57 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java
@@ -24,7 +24,10 @@
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.model.CarIcon;
import androidx.car.app.model.CarText;
+import androidx.car.app.model.DistanceSpan;
+import androidx.car.app.model.DurationSpan;
import androidx.car.app.model.constraints.CarIconConstraints;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo;
import java.util.Objects;
@@ -123,42 +126,51 @@
/**
* Sets the title of the message.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code message} is {@code null}
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
/**
* Sets additional text on the message.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code text} is {@code null}
+ * @throws NullPointerException if {@code text} is {@code null}
+ * @throws IllegalArgumentException if {@code text} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setText(@NonNull CharSequence text) {
mText = CarText.create(requireNonNull(text));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mText);
return this;
}
/**
* Sets additional text on the message, with support for multiple length variants.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code text} is {@code null}
+ * @throws NullPointerException if {@code text} is {@code null}
+ * @throws IllegalArgumentException if {@code text} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setText(@NonNull CarText text) {
mText = requireNonNull(text);
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mText);
return this;
}
@@ -193,12 +205,15 @@
/**
* Returns a new instance of a {@link Builder}.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is {@code null}
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
*/
public Builder(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
}
/**
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java
index c161b2b..5e15393 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java
@@ -32,6 +32,7 @@
import androidx.car.app.model.ActionStrip;
import androidx.car.app.model.CarText;
import androidx.car.app.model.DistanceSpan;
+import androidx.car.app.model.DurationSpan;
import androidx.car.app.model.Item;
import androidx.car.app.model.ItemList;
import androidx.car.app.model.ModelUtils;
@@ -40,6 +41,7 @@
import androidx.car.app.model.Row;
import androidx.car.app.model.Template;
import androidx.car.app.model.Toggle;
+import androidx.car.app.model.constraints.CarTextConstraints;
import java.util.Collections;
import java.util.List;
@@ -194,28 +196,34 @@
/**
* Sets the title of the template.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is null
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
/**
* Sets the title of the template, with support for multiple length variants.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is null
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CarText title) {
mTitle = requireNonNull(title);
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java
index 4aac754..47d711d 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java
@@ -31,12 +31,15 @@
import androidx.car.app.model.Action;
import androidx.car.app.model.ActionStrip;
import androidx.car.app.model.CarText;
+import androidx.car.app.model.DistanceSpan;
+import androidx.car.app.model.DurationSpan;
import androidx.car.app.model.ItemList;
import androidx.car.app.model.ModelUtils;
import androidx.car.app.model.OnClickListener;
import androidx.car.app.model.Row;
import androidx.car.app.model.Template;
import androidx.car.app.model.Toggle;
+import androidx.car.app.model.constraints.CarTextConstraints;
import java.util.Collections;
import java.util.Objects;
@@ -223,28 +226,34 @@
/**
* Sets the title of the template.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is null
+ * @throws NullPointerException if {@code title} is {@code null}
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CharSequence title) {
mTitle = CarText.create(requireNonNull(title));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
/**
* Sets the title of the template, with support for multiple length variants.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code title} is null
+ * @throws NullPointerException if {@code title} is null
+ * @throws IllegalArgumentException if {@code title} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setTitle(@NonNull CarText title) {
mTitle = requireNonNull(title);
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
index b338c39..0b987a8 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
@@ -24,6 +24,9 @@
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.model.CarIcon;
import androidx.car.app.model.CarText;
+import androidx.car.app.model.DistanceSpan;
+import androidx.car.app.model.DurationSpan;
+import androidx.car.app.model.constraints.CarTextConstraints;
import androidx.car.app.utils.CollectionUtils;
import java.util.ArrayList;
@@ -194,11 +197,13 @@
*
* <p>See {@link Builder#setCue} for details on span support in the input string.
*
- * @throws NullPointerException if {@code cue} is {@code null}
+ * @throws NullPointerException if {@code cue} is {@code null}
+ * @throws IllegalArgumentException if {@code cue} contains unsupported spans
* @see Builder#setCue(CharSequence)
*/
public Builder(@NonNull CharSequence cue) {
mCue = CarText.create(requireNonNull(cue));
+ CarTextConstraints.TEXT_AND_ICON.validateOrThrow(mCue);
}
/**
@@ -207,11 +212,13 @@
*
* <p>See {@link Builder#setCue} for details on span support in the input string.
*
- * @throws NullPointerException if {@code cue} is {@code null}
+ * @throws NullPointerException if {@code cue} is {@code null}
+ * @throws IllegalArgumentException if {@code cue} contains unsupported spans
* @see Builder#Builder(CharSequence)
*/
public Builder(@NonNull CarText cue) {
mCue = requireNonNull(cue);
+ CarTextConstraints.TEXT_AND_ICON.validateOrThrow(mCue);
}
/**
@@ -279,9 +286,9 @@
* <p>For example "Turn left", "Make a U-Turn", "Sharp Right", or "Take the exit using
* the left lane"
*
- * <p>The {@code cue} string can contain images that replace spans of text by using {@link
- * androidx.car.app.model.CarIconSpan}. All other spans types are not supported and will be
- * ignored.
+ * <p>The {@code cue} string can contain {@link androidx.car.app.model.CarIconSpan}s,
+ * {@link androidx.car.app.model.DistanceSpan}s, and
+ * {@link androidx.car.app.model.DurationSpan}s.
*
* <p>In the following example, the "520" text is replaced with an icon:
*
@@ -306,12 +313,14 @@
* <p>See {@link CarIcon} for more details related to providing icon and image resources
* that work with different car screen pixel densities.
*
- * @throws NullPointerException if {@code cue} is {@code null}
+ * @throws NullPointerException if {@code cue} is {@code null}
+ * @throws IllegalArgumentException if {@code cue} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setCue(@NonNull CharSequence cue) {
mCue = CarText.create(requireNonNull(cue));
+ CarTextConstraints.TEXT_AND_ICON.validateOrThrow(mCue);
return this;
}
@@ -323,14 +332,17 @@
*
* <p>For example, a {@link Step} for a left turn might provide "State Street" for the road.
*
- * <p>Spans are not supported in the input string and will be ignored.
+ * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
+ * string.
*
- * @throws NullPointerException if {@code destinations} is {@code null}
+ * @throws NullPointerException if {@code road} is {@code null}
+ * @throws IllegalArgumentException if {@code road} contains unsupported spans
* @see CarText
*/
@NonNull
public Builder setRoad(@NonNull CharSequence road) {
mRoad = CarText.create(requireNonNull(road));
+ CarTextConstraints.TEXT_ONLY.validateOrThrow(mRoad);
return this;
}
diff --git a/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java b/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java
index 748a148..faa7bb1 100644
--- a/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java
@@ -81,6 +81,7 @@
private CarAppService mCarAppService;
private Intent mIntentSet;
+ private SessionController mSessionController;
@Captor
ArgumentCaptor<Bundleable> mBundleableArgumentCaptor;
@@ -103,8 +104,8 @@
mCarContext = TestCarContext.createCarContext(
ApplicationProvider.getApplicationContext());
Session session = createTestSession();
- // Injects the TestCarContext into the test session.
- new SessionController(session, mCarContext, new Intent());
+ mSessionController = new SessionController(session, mCarContext,
+ new Intent());
return session;
}
};
diff --git a/car/app/app/src/test/java/androidx/car/app/ScreenTest.java b/car/app/app/src/test/java/androidx/car/app/ScreenTest.java
index 1e9af84..4f9bb46 100644
--- a/car/app/app/src/test/java/androidx/car/app/ScreenTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/ScreenTest.java
@@ -83,7 +83,7 @@
}
};
- new ScreenController(mCarContext, mScreen).moveToState(State.RESUMED);
+ new ScreenController(mScreen).moveToState(State.RESUMED);
}
@Test
diff --git a/car/app/app/src/test/java/androidx/car/app/TestScreen.java b/car/app/app/src/test/java/androidx/car/app/TestScreen.java
index 83195c9..3428099 100644
--- a/car/app/app/src/test/java/androidx/car/app/TestScreen.java
+++ b/car/app/app/src/test/java/androidx/car/app/TestScreen.java
@@ -36,7 +36,7 @@
}
@Override
- void dispatchLifecycleEvent(Event event) {
+ public void dispatchLifecycleEvent(@NonNull Event event) {
// Calls the mock first, then the actual so that changes like finishing another screen
// due to a setResult callback go through in the expected order for the mock.
mScreenForMocking.dispatchLifecycleEvent(event);
diff --git a/car/app/app/src/test/java/androidx/car/app/TestUtils.java b/car/app/app/src/test/java/androidx/car/app/TestUtils.java
index 58e4b93..5a9c07c 100644
--- a/car/app/app/src/test/java/androidx/car/app/TestUtils.java
+++ b/car/app/app/src/test/java/androidx/car/app/TestUtils.java
@@ -17,6 +17,7 @@
package androidx.car.app;
import static androidx.car.app.model.CarIcon.BACK;
+import static androidx.car.app.model.Distance.UNIT_METERS;
import static com.google.common.truth.Truth.assertThat;
@@ -28,9 +29,16 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.car.app.model.Action;
+import androidx.car.app.model.CarColor;
import androidx.car.app.model.CarIcon;
+import androidx.car.app.model.CarIconSpan;
+import androidx.car.app.model.CarText;
+import androidx.car.app.model.ClickableSpan;
import androidx.car.app.model.DateTimeWithZone;
+import androidx.car.app.model.Distance;
import androidx.car.app.model.DistanceSpan;
+import androidx.car.app.model.DurationSpan;
+import androidx.car.app.model.ForegroundCarColorSpan;
import androidx.car.app.model.GridItem;
import androidx.car.app.model.ItemList;
import androidx.car.app.model.Pane;
@@ -175,6 +183,89 @@
return builder.build();
}
+ /**
+ * Returns a {@link CharSequence} with both a {@link DistanceSpan} and {@link DurationSpan} set.
+ */
+ public static CharSequence getCharSequenceWithDistanceAndDurationSpans(String text) {
+ SpannableString sequence = new SpannableString(text);
+ sequence.setSpan(DurationSpan.create(100),
+ /* start= */ 0,
+ /* end= */ 1,
+ /* flags=*/ 0);
+ sequence.setSpan(DistanceSpan.create(Distance.create(1, UNIT_METERS)),
+ /* start= */ 0,
+ /* end= */ 1,
+ /* flags=*/ 0);
+ return sequence;
+ }
+
+ /**
+ * Returns a {@link CharSequence} with a {@link ForegroundCarColorSpan} set.
+ */
+ public static CharSequence getCharSequenceWithColorSpan(String text) {
+ SpannableString sequence = new SpannableString(text);
+ sequence.setSpan(ForegroundCarColorSpan.create(CarColor.BLUE),
+ /* start= */ 0,
+ /* end= */ 1,
+ /* flags=*/ 0);
+ return sequence;
+ }
+
+ /**
+ * Returns a {@link CharSequence} with a {@link androidx.car.app.model.CarIconSpan} set.
+ */
+ public static CharSequence getCharSequenceWithIconSpan(String text) {
+ SpannableString sequence = new SpannableString(text);
+ sequence.setSpan(CarIconSpan.create(BACK),
+ /* start= */ 0,
+ /* end= */ 1,
+ /* flags=*/ 0);
+ return sequence;
+ }
+
+ /**
+ * Returns a {@link CharSequence} with a {@link androidx.car.app.model.ClickableSpan} set.
+ */
+ public static CharSequence getCharSequenceWithClickableSpan(String text) {
+ SpannableString sequence = new SpannableString(text);
+ sequence.setSpan(ClickableSpan.create(() -> {
+ }),
+ /* start= */ 0,
+ /* end= */ 1,
+ /* flags=*/ 0);
+ return sequence;
+ }
+
+ /**
+ * Returns a {@link CarText} with both a {@link DistanceSpan} and {@link DurationSpan} set in
+ * its variant.
+ */
+ public static CarText getCarTextVariantsWithDistanceAndDurationSpans(String text) {
+ return new CarText.Builder(text).addVariant(
+ getCharSequenceWithDistanceAndDurationSpans(text)).build();
+ }
+
+ /**
+ * Returns a {@link CarText} with a {@link ForegroundCarColorSpan} set in its variant.
+ */
+ public static CarText getCarTextVariantsWithColorSpan(String text) {
+ return new CarText.Builder(text).addVariant(getCharSequenceWithColorSpan(text)).build();
+ }
+
+ /**
+ * Returns a {@link CarText} with a {@link ForegroundCarColorSpan} set in its variant.
+ */
+ public static CarText getCarTextVariantsWithClickableSpan(String text) {
+ return new CarText.Builder(text).addVariant(getCharSequenceWithClickableSpan(text)).build();
+ }
+
+ /**
+ * Returns a {@link CarText} with a {@link CarIconSpan} set in its variant.
+ */
+ public static CarText getCarTextVariantsWithIconSpan(String text) {
+ return new CarText.Builder(text).addVariant(getCharSequenceWithIconSpan(text)).build();
+ }
+
@RequiresApi(26)
public static void assertDateTimeWithZoneEquals(
ZonedDateTime zonedDateTime, DateTimeWithZone dateTimeWithZone) {
diff --git a/car/app/app/src/test/java/androidx/car/app/model/ActionStripTest.java b/car/app/app/src/test/java/androidx/car/app/model/ActionStripTest.java
index cdd13da..528e945 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/ActionStripTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/ActionStripTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertThrows;
+import androidx.car.app.TestUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -62,6 +64,21 @@
}
@Test
+ public void unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ Action action1 = new Action.Builder().setTitle(title).build();
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new ActionStrip.Builder().addAction(action1));
+
+ CarText title2 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ Action action2 = new Action.Builder().setTitle(title2).build();
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new ActionStrip.Builder().addAction(action2));
+ }
+
+ @Test
public void createActions() {
Action action1 = Action.BACK;
Action action2 = new Action.Builder().setTitle("Test").setOnClickListener(() -> {
diff --git a/car/app/app/src/test/java/androidx/car/app/model/GridItemTest.java b/car/app/app/src/test/java/androidx/car/app/model/GridItemTest.java
index 3c4c45f..049605b 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/GridItemTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/GridItemTest.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import androidx.car.app.OnDoneCallback;
+import androidx.car.app.TestUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,6 +74,24 @@
}
@Test
+ public void title_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new GridItem.Builder().setTitle(title));
+ CarText title2 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new GridItem.Builder().setTitle(title2));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new GridItem.Builder().setTitle(title3).setImage(BACK).build();
+ CarText title4 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ new GridItem.Builder().setTitle(title4).setImage(BACK).build();
+ }
+
+ @Test
public void title_throwsIfNotSet() {
// Not set
assertThrows(IllegalStateException.class,
@@ -111,6 +130,24 @@
}
@Test
+ public void text_unsupportedSpans_throws() {
+ CharSequence text = TestUtils.getCharSequenceWithClickableSpan("Text");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new GridItem.Builder().setTitle("Title").setText(text));
+ CarText text2 = TestUtils.getCarTextVariantsWithClickableSpan("Text");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new GridItem.Builder().setTitle("Title").setText(text2));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence text3 = TestUtils.getCharSequenceWithColorSpan("Text");
+ new GridItem.Builder().setTitle("Title").setText(text3).setImage(BACK).build();
+ CarText text4 = TestUtils.getCarTextVariantsWithColorSpan("Text");
+ new GridItem.Builder().setTitle("Title").setText(text4).setImage(BACK).build();
+ }
+
+ @Test
public void setIsLoading_contentsSet_throws() {
assertThrows(
IllegalStateException.class,
diff --git a/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java
index b44eb6d..804850a 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java
@@ -72,6 +72,19 @@
}
@Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new GridTemplate.Builder().setTitle(title));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new GridTemplate.Builder().setTitle(title2).setSingleList(
+ TestUtils.getGridItemList(2)).build();
+ }
+
+ @Test
public void createInstance_setSingleList() {
ItemList list = TestUtils.getGridItemList(2);
GridTemplate template = new GridTemplate.Builder().setTitle("Title").setSingleList(
diff --git a/car/app/app/src/test/java/androidx/car/app/model/ListTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/ListTemplateTest.java
index 0a5269d..1e6b215 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/ListTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/ListTemplateTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertThrows;
+import androidx.car.app.TestUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -120,6 +122,18 @@
}
@Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new ListTemplate.Builder().setTitle(title));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new ListTemplate.Builder().setTitle(title2).setSingleList(getList()).build();
+ }
+
+ @Test
public void createInstance_setSingleList() {
ItemList list = getList();
ListTemplate template = new ListTemplate.Builder().setTitle("Title").setSingleList(
diff --git a/car/app/app/src/test/java/androidx/car/app/model/LongMessageTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/LongMessageTemplateTest.java
index 2e20f55..ed96bba 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/LongMessageTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/LongMessageTemplateTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertThrows;
+import androidx.car.app.TestUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -57,6 +59,18 @@
}
@Test
+ public void header_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new LongMessageTemplate.Builder(mMessage).setTitle(title));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new LongMessageTemplate.Builder(mMessage).setTitle(title2).build();
+ }
+
+ @Test
public void moreThanTwoActions_throws() {
assertThrows(IllegalArgumentException.class,
() -> new LongMessageTemplate.Builder(mMessage)
@@ -66,6 +80,38 @@
}
@Test
+ public void action_unsupportedSpans_throws() {
+ CharSequence title1 = TestUtils.getCharSequenceWithClickableSpan("Title");
+ Action action1 =
+ new Action.Builder().setTitle(title1).setOnClickListener(
+ ParkedOnlyOnClickListener.create(() -> {
+ })).build();
+ assertThrows(IllegalArgumentException.class,
+ () -> new LongMessageTemplate.Builder(mMessage).addAction(action1));
+ CarText title2 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ Action action2 =
+ new Action.Builder().setTitle(title2).setOnClickListener(
+ ParkedOnlyOnClickListener.create(() -> {
+ })).build();
+ assertThrows(IllegalArgumentException.class,
+ () -> new LongMessageTemplate.Builder(mMessage).addAction(action2));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithColorSpan("Title");
+ Action action3 =
+ new Action.Builder().setTitle(title3).setOnClickListener(
+ ParkedOnlyOnClickListener.create(() -> {
+ })).build();
+ new LongMessageTemplate.Builder(mMessage).setTitle("Title").addAction(action3).build();
+ CarText title4 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ Action action4 =
+ new Action.Builder().setTitle(title4).setOnClickListener(
+ ParkedOnlyOnClickListener.create(() -> {
+ })).build();
+ new LongMessageTemplate.Builder(mMessage).setTitle("Title").addAction(action4).build();
+ }
+
+ @Test
public void createDefault_valuesAreNull() {
LongMessageTemplate template = new LongMessageTemplate.Builder(mMessage)
.setTitle(mTitle)
diff --git a/car/app/app/src/test/java/androidx/car/app/model/MessageTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/MessageTemplateTest.java
index 01ff47c..ca48595 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/MessageTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/MessageTemplateTest.java
@@ -26,6 +26,7 @@
import android.net.Uri;
import android.util.Log;
+import androidx.car.app.TestUtils;
import androidx.core.graphics.drawable.IconCompat;
import org.junit.Test;
@@ -86,6 +87,18 @@
}
@Test
+ public void header_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new MessageTemplate.Builder(mMessage).setTitle(title));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new MessageTemplate.Builder(mMessage).setTitle(title2).build();
+ }
+
+ @Test
public void moreThanTwoActions_throws() {
assertThrows(IllegalArgumentException.class,
() -> new MessageTemplate.Builder(mMessage)
@@ -95,6 +108,26 @@
}
@Test
+ public void action_unsupportedSpans_throws() {
+ CharSequence title1 = TestUtils.getCharSequenceWithClickableSpan("Title");
+ Action action1 = new Action.Builder().setTitle(title1).build();
+ assertThrows(IllegalArgumentException.class,
+ () -> new MessageTemplate.Builder(mMessage).setTitle("Title").addAction(action1));
+ CarText title2 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ Action action2 = new Action.Builder().setTitle(title2).build();
+ assertThrows(IllegalArgumentException.class,
+ () -> new MessageTemplate.Builder(mMessage).setTitle("Title").addAction(action2));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithColorSpan("Title");
+ Action action3 = new Action.Builder().setTitle(title3).build();
+ new MessageTemplate.Builder(mMessage).setTitle("Title").addAction(action3).build();
+ CarText title4 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ Action action4 = new Action.Builder().setTitle(title4).build();
+ new MessageTemplate.Builder(mMessage).setTitle("Title").addAction(action4).build();
+ }
+
+ @Test
public void createDefault_valuesAreNull() {
MessageTemplate template = new MessageTemplate.Builder(mMessage).setTitle(mTitle).build();
assertThat(template.getMessage().toString()).isEqualTo(mMessage);
diff --git a/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java
index 0843d84..c5a8cd2 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java
@@ -44,6 +44,34 @@
}
@Test
+ public void pane_action_unsupportedSpans_throws() {
+ CharSequence title1 = TestUtils.getCharSequenceWithClickableSpan("Title");
+ Action action1 = new Action.Builder().setTitle(title1).build();
+ Pane pane1 = getPane().addAction(action1).build();
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new PaneTemplate.Builder(pane1).setTitle("Title").build());
+
+ CarText title2 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ Action action2 = new Action.Builder().setTitle(title2).build();
+ Pane pane2 = getPane().addAction(action2).build();
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new PaneTemplate.Builder(pane2).setTitle("Title").build());
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithColorSpan("Title");
+ Action action3 = new Action.Builder().setTitle(title3).build();
+ Pane pane3 = getPane().addAction(action3).build();
+ new PaneTemplate.Builder(pane3).setTitle("Title").build();
+
+ CarText title4 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ Action action4 = new Action.Builder().setTitle(title4).build();
+ Pane pane4 = getPane().addAction(action4).build();
+ new PaneTemplate.Builder(pane4).setTitle("Title").build();
+ }
+
+ @Test
public void pane_moreThanMaxTexts_throws() {
Row rowExceedsMaxTexts =
new Row.Builder().setTitle("Title").addText("text1").addText("text2").addText(
@@ -96,16 +124,28 @@
@Test
public void createInstance_noHeaderTitleOrAction_throws() {
assertThrows(IllegalStateException.class,
- () -> new PaneTemplate.Builder(getPane()).build());
+ () -> new PaneTemplate.Builder(getPane().build()).build());
// Positive cases.
- new PaneTemplate.Builder(getPane()).setTitle("Title").build();
- new PaneTemplate.Builder(getPane()).setHeaderAction(Action.BACK).build();
+ new PaneTemplate.Builder(getPane().build()).setTitle("Title").build();
+ new PaneTemplate.Builder(getPane().build()).setHeaderAction(Action.BACK).build();
+ }
+
+ @Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new PaneTemplate.Builder(getPane().build()).setTitle(title));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new PaneTemplate.Builder(getPane().build()).setTitle(title2).build();
}
@Test
public void createInstance_setPane() {
- Pane pane = getPane();
+ Pane pane = getPane().build();
PaneTemplate template = new PaneTemplate.Builder(pane).setTitle("Title").build();
assertThat(template.getPane()).isEqualTo(pane);
}
@@ -115,7 +155,7 @@
assertThrows(
IllegalArgumentException.class,
() ->
- new PaneTemplate.Builder(getPane())
+ new PaneTemplate.Builder(getPane().build())
.setHeaderAction(
new Action.Builder().setTitle("Action").setOnClickListener(
() -> {
@@ -124,7 +164,7 @@
@Test
public void createInstance_setHeaderAction() {
- PaneTemplate template = new PaneTemplate.Builder(getPane()).setHeaderAction(
+ PaneTemplate template = new PaneTemplate.Builder(getPane().build()).setHeaderAction(
Action.BACK).build();
assertThat(template.getHeaderAction()).isEqualTo(Action.BACK);
}
@@ -133,7 +173,7 @@
public void createInstance_setActionStrip() {
ActionStrip actionStrip = new ActionStrip.Builder().addAction(Action.BACK).build();
PaneTemplate template =
- new PaneTemplate.Builder(getPane()).setTitle("Title").setActionStrip(
+ new PaneTemplate.Builder(getPane().build()).setTitle("Title").setActionStrip(
actionStrip).build();
assertThat(template.getActionStrip()).isEqualTo(actionStrip);
}
@@ -224,9 +264,9 @@
"bar").build());
}
- private static Pane getPane() {
+ private static Pane.Builder getPane() {
Row row1 = new Row.Builder().setTitle("Bananas").build();
Row row2 = new Row.Builder().setTitle("Oranges").build();
- return new Pane.Builder().addRow(row1).addRow(row2).build();
+ return new Pane.Builder().addRow(row1).addRow(row2);
}
}
diff --git a/car/app/app/src/test/java/androidx/car/app/model/PlaceListMapTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/PlaceListMapTemplateTest.java
index b137b1a..3c19cf1 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/PlaceListMapTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/PlaceListMapTemplateTest.java
@@ -302,6 +302,26 @@
}
@Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ ItemList itemList = TestUtils.createItemListWithDistanceSpan(6, false, mDistanceSpan);
+
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ CarText title2 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new PlaceListMapTemplate.Builder().setItemList(itemList).setTitle(title));
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new PlaceListMapTemplate.Builder().setItemList(itemList).setTitle(title2));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ CarText title4 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ new PlaceListMapTemplate.Builder().setItemList(itemList).setTitle(title3).build();
+ new PlaceListMapTemplate.Builder().setItemList(itemList).setTitle(title4).build();
+ }
+
+ @Test
public void equals() {
ActionStrip actionStrip = new ActionStrip.Builder().addAction(Action.BACK).build();
String title = "foo";
diff --git a/car/app/app/src/test/java/androidx/car/app/model/RowTest.java b/car/app/app/src/test/java/androidx/car/app/model/RowTest.java
index 35d82dd..6bd8869 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/RowTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/RowTest.java
@@ -88,6 +88,42 @@
}
@Test
+ public void title_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new Row.Builder().setTitle(title).build());
+ CarText title2 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new Row.Builder().setTitle(title2).build());
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new Row.Builder().setTitle(title3).build();
+ CarText title4 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ new Row.Builder().setTitle(title4).build();
+ }
+
+ @Test
+ public void text_unsupportedSpans_throws() {
+ CharSequence text = TestUtils.getCharSequenceWithClickableSpan("Text");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new Row.Builder().setTitle("Title").addText(text).build());
+ CarText text2 = TestUtils.getCarTextVariantsWithClickableSpan("Text");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new Row.Builder().setTitle("Title").addText(text2).build());
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence text3 = TestUtils.getCharSequenceWithColorSpan("Text");
+ new Row.Builder().setTitle("Title").addText(text3).build();
+ CarText text4 = TestUtils.getCarTextVariantsWithColorSpan("Text");
+ new Row.Builder().setTitle("Title").addText(text4).build();
+ }
+
+ @Test
public void setImage() {
CarIcon image1 = BACK;
Row row = new Row.Builder().setTitle("Title").setImage(image1).build();
diff --git a/car/app/app/src/test/java/androidx/car/app/model/SectionedItemListTest.java b/car/app/app/src/test/java/androidx/car/app/model/SectionedItemListTest.java
index 396bc81..75e9913 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/SectionedItemListTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/SectionedItemListTest.java
@@ -18,6 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+
+import androidx.car.app.TestUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -29,6 +33,19 @@
public class SectionedItemListTest {
@Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ ItemList list = new ItemList.Builder().build();
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> SectionedItemList.create(list, title));
+
+ // DistanceSpan and DurationSpan are supported.
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ SectionedItemList.create(list, title2);
+ }
+
+ @Test
public void createInstance() {
ItemList list = new ItemList.Builder().build();
SectionedItemList sectionList = SectionedItemList.create(list, "header");
diff --git a/car/app/app/src/test/java/androidx/car/app/model/signin/SignInTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/signin/SignInTemplateTest.java
index 71884df..fa4bc79 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/signin/SignInTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/signin/SignInTemplateTest.java
@@ -20,8 +20,10 @@
import static org.junit.Assert.assertThrows;
+import androidx.car.app.TestUtils;
import androidx.car.app.model.Action;
import androidx.car.app.model.ActionStrip;
+import androidx.car.app.model.CarText;
import androidx.car.app.model.ParkedOnlyOnClickListener;
import org.junit.Test;
@@ -50,6 +52,19 @@
}
@Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ PinSignInMethod signInMethod = new PinSignInMethod("ABC");
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new SignInTemplate.Builder(signInMethod).setTitle(title).build());
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new SignInTemplate.Builder(signInMethod).setTitle(title2).build();
+ }
+
+ @Test
public void moreThanTwoActions_throws() {
PinSignInMethod signInMethod = new PinSignInMethod("ABC");
assertThrows(IllegalArgumentException.class,
@@ -60,6 +75,30 @@
}
@Test
+ public void action_unsupportedSpans_throws() {
+ PinSignInMethod signInMethod = new PinSignInMethod("ABC");
+ ParkedOnlyOnClickListener listener = ParkedOnlyOnClickListener.create(
+ () -> {
+ });
+ CharSequence title1 = TestUtils.getCharSequenceWithClickableSpan("Title");
+ Action action1 = new Action.Builder().setTitle(title1).setOnClickListener(listener).build();
+ assertThrows(IllegalArgumentException.class,
+ () -> new SignInTemplate.Builder(signInMethod).addAction(action1));
+ CarText title2 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ Action action2 = new Action.Builder().setTitle(title2).setOnClickListener(listener).build();
+ assertThrows(IllegalArgumentException.class,
+ () -> new SignInTemplate.Builder(signInMethod).addAction(action2));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithColorSpan("Title");
+ Action action3 = new Action.Builder().setTitle(title3).setOnClickListener(listener).build();
+ new SignInTemplate.Builder(signInMethod).setTitle("Title").addAction(action3);
+ CarText title4 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ Action action4 = new Action.Builder().setTitle(title4).setOnClickListener(listener).build();
+ new SignInTemplate.Builder(signInMethod).setTitle("Title").addAction(action4);
+ }
+
+ @Test
public void createInstance_defaultValues() {
PinSignInMethod signInMethod = new PinSignInMethod("ABC");
SignInTemplate template = new SignInTemplate.Builder(signInMethod)
@@ -77,6 +116,32 @@
}
@Test
+ public void instructions_unsupportedSpans_throws() {
+ PinSignInMethod signInMethod = new PinSignInMethod("ABC");
+ CharSequence instructions = TestUtils.getCharSequenceWithClickableSpan("Text");
+ assertThrows(IllegalArgumentException.class,
+ () -> new SignInTemplate.Builder(signInMethod).setInstructions(instructions));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence instructions2 = TestUtils.getCharSequenceWithColorSpan("Text");
+ new SignInTemplate.Builder(signInMethod).setTitle("Title").setInstructions(
+ instructions2).build();
+ }
+
+ @Test
+ public void additionalText_unsupportedSpans_throws() {
+ PinSignInMethod signInMethod = new PinSignInMethod("ABC");
+ CharSequence text = TestUtils.getCharSequenceWithColorSpan("Text");
+ assertThrows(IllegalArgumentException.class,
+ () -> new SignInTemplate.Builder(signInMethod).setAdditionalText(text));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence text2 = TestUtils.getCharSequenceWithClickableSpan("Text");
+ new SignInTemplate.Builder(signInMethod).setTitle("Title3").setAdditionalText(
+ text2).build();
+ }
+
+ @Test
public void createInstance_setHeaderAction_invalidActionThrows() {
PinSignInMethod signInMethod = new PinSignInMethod("ABC");
assertThrows(
diff --git a/car/app/app/src/test/java/androidx/car/app/navigation/model/MessageInfoTest.java b/car/app/app/src/test/java/androidx/car/app/navigation/model/MessageInfoTest.java
index fa379a7..5524ee6 100644
--- a/car/app/app/src/test/java/androidx/car/app/navigation/model/MessageInfoTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/navigation/model/MessageInfoTest.java
@@ -23,6 +23,7 @@
import android.content.ContentResolver;
import android.net.Uri;
+import androidx.car.app.TestUtils;
import androidx.car.app.model.CarIcon;
import androidx.car.app.model.CarText;
import androidx.core.graphics.drawable.IconCompat;
@@ -94,6 +95,30 @@
}
@Test
+ public void title_unsupportedSpans_throws() {
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new MessageInfo.Builder(title));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ new MessageInfo.Builder(title2).build();
+ }
+
+ @Test
+ public void text_unsupportedSpans_throws() {
+ CharSequence text = TestUtils.getCharSequenceWithColorSpan("Text");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new MessageInfo.Builder("title").setText(text));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence text2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Text");
+ new MessageInfo.Builder("title").setText(text2).build();
+ }
+
+ @Test
public void equals() {
final String title = "Primary";
final String text = "Secondary";
diff --git a/car/app/app/src/test/java/androidx/car/app/navigation/model/PlaceListNavigationTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/navigation/model/PlaceListNavigationTemplateTest.java
index 1126c91..82764d7 100644
--- a/car/app/app/src/test/java/androidx/car/app/navigation/model/PlaceListNavigationTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/navigation/model/PlaceListNavigationTemplateTest.java
@@ -162,6 +162,28 @@
}
@Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ ItemList itemList = new ItemList.Builder().build();
+
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ CarText title2 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new PlaceListNavigationTemplate.Builder().setItemList(itemList).setTitle(
+ title));
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new PlaceListNavigationTemplate.Builder().setItemList(itemList).setTitle(
+ title2));
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ CarText title4 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ new PlaceListNavigationTemplate.Builder().setItemList(itemList).setTitle(title3).build();
+ new PlaceListNavigationTemplate.Builder().setItemList(itemList).setTitle(title4).build();
+ }
+
+ @Test
public void createEmpty() {
PlaceListNavigationTemplate template =
new PlaceListNavigationTemplate.Builder()
diff --git a/car/app/app/src/test/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplateTest.java
index e6eb66f..302eec5 100644
--- a/car/app/app/src/test/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplateTest.java
@@ -200,6 +200,45 @@
}
@Test
+ public void createInstance_header_unsupportedSpans_throws() {
+ ItemList itemList = TestUtils.createItemListWithDistanceSpan(2, true, DISTANCE);
+ Action navigationAction = new Action.Builder().setTitle("Navigate").setOnClickListener(
+ () -> {
+ }).build();
+
+ CharSequence title = TestUtils.getCharSequenceWithColorSpan("Title");
+ CarText title2 = TestUtils.getCarTextVariantsWithColorSpan("Title");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new RoutePreviewNavigationTemplate.Builder()
+ .setItemList(itemList)
+ .setTitle(title)
+ .setNavigateAction(navigationAction)
+ .build());
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new RoutePreviewNavigationTemplate.Builder()
+ .setItemList(itemList)
+ .setTitle(title2)
+ .setNavigateAction(navigationAction)
+ .build());
+
+ // DurationSpan and DistanceSpan do not throw
+ CharSequence title3 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+ CarText title4 = TestUtils.getCarTextVariantsWithDistanceAndDurationSpans("Title");
+ new RoutePreviewNavigationTemplate.Builder()
+ .setItemList(itemList)
+ .setTitle(title3)
+ .setNavigateAction(navigationAction)
+ .build();
+ new RoutePreviewNavigationTemplate.Builder()
+ .setItemList(itemList)
+ .setTitle(title4)
+ .setNavigateAction(navigationAction)
+ .build();
+ }
+
+ @Test
public void setOnNavigateAction() {
OnClickListener mockListener = mock(OnClickListener.class);
RoutePreviewNavigationTemplate template =
diff --git a/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java b/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java
index ea2a1d5..c46c85c 100644
--- a/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertThrows;
+import androidx.car.app.TestUtils;
import androidx.car.app.model.CarIcon;
import androidx.car.app.model.CarText;
@@ -77,18 +78,46 @@
}
@Test
+ public void createInstance_cue_unsupportedSpans_throws() {
+ CharSequence cue1 = TestUtils.getCharSequenceWithClickableSpan("Cue");
+ CarText cue2 = TestUtils.getCarTextVariantsWithColorSpan("Cue");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new Step.Builder(cue1).build());
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new Step.Builder(cue2).build());
+
+ CharSequence cue3 = TestUtils.getCharSequenceWithIconSpan("Cue");
+ CarText cue4 = TestUtils.getCarTextVariantsWithIconSpan("Cue");
+ new Step.Builder(cue3).build();
+ new Step.Builder(cue4).build();
+ }
+
+ @Test
public void createInstance_noCue() {
Lane lane = new Lane.Builder().addDirection(
LaneDirection.create(SHAPE_SHARP_LEFT, true)).build();
Step step =
new Step.Builder()
- .addLane(lane)
- .build();
+ .addLane(lane)
+ .build();
assertThat(step.getCue()).isNull();
}
+ @Test
+ public void createInstance_road_unsupportedSpans_throws() {
+ CharSequence road1 = TestUtils.getCharSequenceWithClickableSpan("Road");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new Step.Builder().setRoad(road1).build());
+
+ CharSequence road2 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Road");
+ new Step.Builder().setRoad(road2).build();
+ }
+
@Test(expected = NullPointerException.class)
public void createInstance_cueIsNullInBuilder() {
Lane lane = new Lane.Builder().addDirection(
diff --git a/car/app/app/src/test/resources/robolectric.properties b/car/app/app/src/test/resources/robolectric.properties
index ce87047..ab64ba7 100644
--- a/car/app/app/src/test/resources/robolectric.properties
+++ b/car/app/app/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/TransitionDetectorTest.kt b/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/TransitionDetectorTest.kt
index 47fffe8..268c145 100644
--- a/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/TransitionDetectorTest.kt
+++ b/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/TransitionDetectorTest.kt
@@ -23,7 +23,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -44,6 +43,7 @@
private val TransitionStub = compiledStub(
filename = "Transition.kt",
filepath = "androidx/compose/animation/core",
+ checksum = 0x313a900e,
"""
package androidx.compose.animation.core
@@ -61,32 +61,10 @@
): Float = 5f
""",
"""
- androidx/compose/animation/core/TransitionKt.class:
- H4sIAAAAAAAAAMVVT1MjRRR/PZkknSHAMAsI2d24stldYGEnZDHqJovLIsho
- iJZBLhysJmmyA5MeamZCsRcLvfgFvOzN8uDRg6ctD1aKLS9+Jsvy9ZCEQKzC
- eDFV6fev3++91/36zR9//fobACzDJwQWmKh5rl07Matu48j1ucmE3WCB7QrU
- eNzc9pjwbSl/GsSBENAP2DEzHSbq5md7B7yK2giB5Lkb33BcFhD4Zrb074EL
- pUM3cGxhHhw3zP2mqEqlb260uaVC6SJkJfBsUb/WY26DwJ/FypPS1WQLK4Nk
- VtyuFFauC1ZcHAAxU+H1BhfBZeQvhR1IcdA6i4sI0+MVnj4CyfLv9WflNUVg
- N7i5Fspsz+EFAndLrlc3D3iw5zEbwZkQbsDOA5XdoNx0HNwVKwYvbH+FgkYg
- 3ZOULQLuCeaYlpAZ+3bVj0OSwET1Ba8etv0/Zx5rcNxI4MFs/5X0lz23k4QR
- GNVgGHQCI0H3+CpHvErBIBB12B53KIwTMALm1Xmww5wmf/6ygrlzCpPqsx8A
- CIxl7Mx+5nJzEgudMrKeK4aFQZqWwJ3ruhDD9NdGYLw3aqbG91nTwejf/89v
- xuq/GdlHhUEmxKUDzSzF4R0C1CpXtlfLa+sEng5QYR9YIQl3IZOAGbh3uQf/
- oZg4PMC+CR1XOwEozBG43X/vXzVzy91LGOuc0hYPWI0FDO9LaRxHcF4SuUSx
- fQ4lo6D+xJZcFrnaEoHfW6c5rXWqKXo8JFNKh4R/Xeny4aaRrpUqqUBvnaaU
- LJlRaetUV+apoRrKppKN5DJU09VU2tCMji4maTaejZ79GFMoDddEjlJF1xBi
- KHdfT6ZmjBvG2KaCtiQdNigdMVRKZ0dDT9Lx3Dz7jr55TVqnZ98qcS1Kz17l
- skQWkyPy6ZCK7N/2cfQ29fJ/mHfolu5grZ8EHM2u6IBuvzySk2iys6E7L8pI
- 0KAKpPjmffm2CQxfwD86xDtT19waqkdLtuDlZmOPe9tytsns3SpzdphnS7mt
- TFTsumBB00P+5hfnE9ESx7Zvo3n1YvgRyFy1dvO6tG0YR071cIsdtQMkLSG4
- t+Yw3+do1ipu06vyDVvaptuQO33hYAkUUEH+FJiGKMRQeobSEcpRpOl5Y+g1
- jD00buC6YEzgumi8hWskrxpTP4d+q7jG8Opuwig8Dz/xUeQjiJcKsdMo3Qpj
- pMGA27hTcuP4V0JuEnURWAux4vBRG40iXcf/tIpCQr6Eq6uegLfhDvIy4Z/Q
- OYY0P6GqX78C7Re434LZ0oQaRSlmzG9dW0gENnBVQRlJhCWlQrwhTEl+FoZg
- Ar8LU0gf95T5uKfMPDxsl5nvlpnvlplvlxmBj1HS0DoT7p2GzbDwD8FCuov6
- BcRd3IWIBY8sMHGFrIX3lLMw2jJu8OFdyO+C7mNrwns+vO/DLR8MHz7w4Umo
- oT4UfBgP+Ukfij489WHlb+6OIxeBCQAA
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3Apc8ln5iXUpSfmVKhl5yfW5BfnKqX
+ mJeZm1iSmZ8HFClKFeIJKUrMK84ECXiXcPFyMafl5wuxhaQWl3iXKDFoMQAA
+ iDN6X1gAAAA=
""",
"""
androidx/compose/animation/core/Transition$Segment.class:
@@ -103,6 +81,20 @@
AAA=
""",
"""
+ androidx/compose/animation/core/Transition.class:
+ H4sIAAAAAAAAAI1RTW8TMRB99m52023apuUr4atAeygRYtuIU6gqQSWkSAtI
+ bJVLTk7WCm52vWjtVD3mt/APOCFxQBFHfhRivFRCgkt9eOP3PG88Hv/89e07
+ gBfYY+gJnVWlyi7jaVl8Ko2MhVaFsKrUpFQyPquENsrxEIzh4DgdJOfiQsS5
+ 0LP4/eRcTu3Lk/8lhva/WgifIThWWtkTBu/g6aiFAGGEBpoMvv2oDMOz5Pod
+ 0SXbyby0udLxW2lFJqwgjRcXHr2POWgwsDlJl8qxQ9plR3TJarkZ8Q6PVsuI
+ tx00eWe17PnN1bLN+vyQD5j/uvHjc8DbnvP0qUzKqCbCVM4KqS1D//qN7l+Z
+ QnQZNv7qz+dUxz8tM8mwlSgt3y2KiazOxCQnZScppyIfiUo5fiW2hlrL6jQX
+ xkga11qqZlrYRUVHUVouqql8o1xe98NCW1XIkTKKjK+0Lm3dm8EROI3cLXqV
+ +wHC+8TimtPMel+x9oU2HA8Ig1oM8JCw9ScBEdYp+tgljEi7S7kddPGodnl4
+ XMd7eEJxQOct8myM4Q2xOcQWIdoOtofYwY0xmMFN3BqjYbBucNvgjkFo0PkN
+ zab+FKoCAAA=
+ """,
+ """
androidx/compose/animation/core/TransitionKt$animateFloat$1.class:
H4sIAAAAAAAAAKVVXW8bRRQ9s3ZsZ7Mljpt+JIUSGtM6dujGIbRQuwGT2mSJ
ayocIqE8je2ps/F6ttpdW+EtD/0J/BAKEkUgIT/zo1DvrF03VkPbhJeZO3fu
@@ -128,28 +120,35 @@
HwUf114AvnRqlvwHAAA=
""",
"""
- androidx/compose/animation/core/Transition.class:
- H4sIAAAAAAAAAI1RTW8TMRB99m52023apuUr4atAeygRYtuIU6gqQSWkSAtI
- bJVLTk7WCm52vWjtVD3mt/APOCFxQBFHfhRivFRCgkt9eOP3PG88Hv/89e07
- gBfYY+gJnVWlyi7jaVl8Ko2MhVaFsKrUpFQyPquENsrxEIzh4DgdJOfiQsS5
- 0LP4/eRcTu3Lk/8lhva/WgifIThWWtkTBu/g6aiFAGGEBpoMvv2oDMOz5Pod
- 0SXbyby0udLxW2lFJqwgjRcXHr2POWgwsDlJl8qxQ9plR3TJarkZ8Q6PVsuI
- tx00eWe17PnN1bLN+vyQD5j/uvHjc8DbnvP0qUzKqCbCVM4KqS1D//qN7l+Z
- QnQZNv7qz+dUxz8tM8mwlSgt3y2KiazOxCQnZScppyIfiUo5fiW2hlrL6jQX
- xkga11qqZlrYRUVHUVouqql8o1xe98NCW1XIkTKKjK+0Lm3dm8EROI3cLXqV
- +wHC+8TimtPMel+x9oU2HA8Ig1oM8JCw9ScBEdYp+tgljEi7S7kddPGodnl4
- XMd7eEJxQOct8myM4Q2xOcQWIdoOtofYwY0xmMFN3BqjYbBucNvgjkFo0PkN
- zab+FKoCAAA=
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3Apc8ln5iXUpSfmVKhl5yfW5BfnKqX
- mJeZm1iSmZ8HFClKFeIJKUrMK84ECXiXcPFyMafl5wuxhaQWl3iXKDFoMQAA
- iDN6X1gAAAA=
+ androidx/compose/animation/core/TransitionKt.class:
+ H4sIAAAAAAAAAMVVT1MjRRR/PZkknSHAMAsI2d24stldYGEnZDHqJovLIsho
+ iJZBLhysJmmyA5MeamZCsRcLvfgFvOzN8uDRg6ctD1aKLS9+Jsvy9ZCEQKzC
+ eDFV6fev3++91/36zR9//fobACzDJwQWmKh5rl07Matu48j1ucmE3WCB7QrU
+ eNzc9pjwbSl/GsSBENAP2DEzHSbq5md7B7yK2giB5Lkb33BcFhD4Zrb074EL
+ pUM3cGxhHhw3zP2mqEqlb260uaVC6SJkJfBsUb/WY26DwJ/FypPS1WQLK4Nk
+ VtyuFFauC1ZcHAAxU+H1BhfBZeQvhR1IcdA6i4sI0+MVnj4CyfLv9WflNUVg
+ N7i5Fspsz+EFAndLrlc3D3iw5zEbwZkQbsDOA5XdoNx0HNwVKwYvbH+FgkYg
+ 3ZOULQLuCeaYlpAZ+3bVj0OSwET1Ba8etv0/Zx5rcNxI4MFs/5X0lz23k4QR
+ GNVgGHQCI0H3+CpHvErBIBB12B53KIwTMALm1Xmww5wmf/6ygrlzCpPqsx8A
+ CIxl7Mx+5nJzEgudMrKeK4aFQZqWwJ3ruhDD9NdGYLw3aqbG91nTwejf/89v
+ xuq/GdlHhUEmxKUDzSzF4R0C1CpXtlfLa+sEng5QYR9YIQl3IZOAGbh3uQf/
+ oZg4PMC+CR1XOwEozBG43X/vXzVzy91LGOuc0hYPWI0FDO9LaRxHcF4SuUSx
+ fQ4lo6D+xJZcFrnaEoHfW6c5rXWqKXo8JFNKh4R/Xeny4aaRrpUqqUBvnaaU
+ LJlRaetUV+apoRrKppKN5DJU09VU2tCMji4maTaejZ79GFMoDddEjlJF1xBi
+ KHdfT6ZmjBvG2KaCtiQdNigdMVRKZ0dDT9Lx3Dz7jr55TVqnZ98qcS1Kz17l
+ skQWkyPy6ZCK7N/2cfQ29fJ/mHfolu5grZ8EHM2u6IBuvzySk2iys6E7L8pI
+ 0KAKpPjmffm2CQxfwD86xDtT19waqkdLtuDlZmOPe9tytsns3SpzdphnS7mt
+ TFTsumBB00P+5hfnE9ESx7Zvo3n1YvgRyFy1dvO6tG0YR071cIsdtQMkLSG4
+ t+Yw3+do1ipu06vyDVvaptuQO33hYAkUUEH+FJiGKMRQeobSEcpRpOl5Y+g1
+ jD00buC6YEzgumi8hWskrxpTP4d+q7jG8Opuwig8Dz/xUeQjiJcKsdMo3Qpj
+ pMGA27hTcuP4V0JuEnURWAux4vBRG40iXcf/tIpCQr6Eq6uegLfhDvIy4Z/Q
+ OYY0P6GqX78C7Re434LZ0oQaRSlmzG9dW0gENnBVQRlJhCWlQrwhTEl+FoZg
+ Ar8LU0gf95T5uKfMPDxsl5nvlpnvlplvlxmBj1HS0DoT7p2GzbDwD8FCuov6
+ BcRd3IWIBY8sMHGFrIX3lLMw2jJu8OFdyO+C7mNrwns+vO/DLR8MHz7w4Umo
+ oT4UfBgP+Ukfij489WHlb+6OIxeBCQAA
"""
)
- @Ignore // Started failing with AGP 7.1.0-alpha03 upgrade
@Test
fun unreferencedParameters() {
lint().files(
@@ -204,7 +203,6 @@
)
}
- @Ignore // Started failing with AGP 7.1.0-alpha03 upgrade
@Test
fun unreferencedParameter_shadowedNames() {
lint().files(
diff --git a/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/UnrememberedAnimatableDetectorTest.kt b/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/UnrememberedAnimatableDetectorTest.kt
index df853a7..e4b2d27 100644
--- a/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/UnrememberedAnimatableDetectorTest.kt
+++ b/compose/animation/animation-core-lint/src/test/java/androidx/compose/animation/core/lint/UnrememberedAnimatableDetectorTest.kt
@@ -43,6 +43,7 @@
private val AnimatableStub = compiledStub(
filename = "Animatable.kt",
filepath = "androidx/compose/animation/core",
+ checksum = 0xfbab86fa,
"""
package androidx.compose.animation.core
@@ -54,6 +55,13 @@
fun Animatable(initialValue: Float): Animatable<Float, Any> = Animatable(initialValue)
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAHWLuwrCQBBFR6IIo9UWIiIIKRQs1sYfEMt0CraySYY4sI+w
+ D/DzXVGrYHG5cDgHAAoAGOVNvg94xJWyrXfcPmXjTO8CSWXZqMjOisWVbafp
+ pnSi049WEQ+4+V9l4knMP76qNeVgi8tB4JONbEjghQyZmnz2drgeeIll51X/
+ 4CaI6dlp9xZnOI4UoijuVSxhDy8wojKE3QAAAA==
+ """,
+ """
androidx/compose/animation/core/Animatable.class:
H4sIAAAAAAAAAI1SW08TQRT+ZrvdtmsLSwUpeENFbQuyaHwgQky8xKRJQQJN
X4gPQzvitNtdsjNt8MXwN3z1F2iiIfHBEB/9UcYz23qjPpjNzrnMmfN95/Lt
@@ -86,13 +94,6 @@
tfTyHyFOyNEa3EMyZzF8HBDihJnz7eg7gm/ONzym2KjIFp5QbN8IsEUZ8LTS
NHG4Vt2p8LMqRnhO+zvXPum3R/AH2BkgpIjdATq4N8B9PBiBFXiIRyPUC7f2
CuxXa+sP0YZpjAsDAAA=
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAHWLuwrCQBBFR3zBIBZbiIgQsFCwWBt/QCzTqdhvkiEO7CPs
- A/x8V9QqWNx74XIOAAwBYJAz/i7gEVfKNt5x85S1M50LJJVloyI7KxZXtq2m
- u9KJTr+3jHjA4r+VH09i9uFVpSkLW1z2BJ9sZEMCL2TIVOQzt8N1j0ssW6+6
- B9dBTM9Ouzc4x1GkEMXklruMG9jDC9/F7r/gAAAA
"""
)
@@ -100,6 +101,7 @@
private val AnimatableColorStub = compiledStub(
filename = "SingleValueAnimation.kt",
filepath = "androidx/compose/animation",
+ checksum = 0x285b4455,
"""
package androidx.compose.animation
@@ -109,6 +111,13 @@
fun Animatable(initialValue: Color): Animatable<Color, Any> = Animatable(initialValue)
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAHWLuwrCQBBFR3zBIBZbiIgQsFCwWBt/QCzTqdhvkiEO7CPs
+ A/x8V9QqWNx74XIOAAwBYJAz/i7gEVfKNt5x85S1M50LJJVloyI7KxZXtq2m
+ u9KJTr+3jHjA4r+VH09i9uFVpSkLW1z2BJ9sZEMCL2TIVOQzt8N1j0ssW6+6
+ B9dBTM9Ouzc4x1GkEMXklruMG9jDC9/F7r/gAAAA
+ """,
+ """
androidx/compose/animation/SingleValueAnimationKt.class:
H4sIAAAAAAAAAJVTXU8TQRQ9s223Zam0VFEoigooHwLbEh8wJUSCMSkWTESb
GB7MtF3rtNsZMjvb8Ej8J/oLfJNoYgi++aOMdwuExBKFTfbOuXfPnXPvzN1f
@@ -125,13 +134,6 @@
dzhvJw6RZQn2FTe+RDeEWbI2JQBJzJFN93AGI7hJ63yPk8SjU1aq5y/07EMs
0vo0OhISG91FrIyxMvJkMV7GbdwpYwJ3d8EC3MP9XSQDTAaYCjAd4EGAkQCJ
APYfAm5eAJQEAAA=
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAHWLuwrCQBBFR3zBIBZbiIgQsFCwWBt/QCzTqdhvkiEO7CPs
- A/x8V9QqWNx74XIOAAwBYJAz/i7gEVfKNt5x85S1M50LJJVloyI7KxZXtq2m
- u9KJTr+3jHjA4r+VH09i9uFVpSkLW1z2BJ9sZEMCL2TIVOQzt8N1j0ssW6+6
- B9dBTM9Ouzc4x1GkEMXklruMG9jDC9/F7r/gAAAA
"""
)
diff --git a/compose/animation/animation-core/api/current.ignore b/compose/animation/animation-core/api/current.ignore
index 612e66b..aa35d9e 100644
--- a/compose/animation/animation-core/api/current.ignore
+++ b/compose/animation/animation-core/api/current.ignore
@@ -1,3 +1,17 @@
// Baseline format: 1.0
RemovedInterface: androidx.compose.animation.core.InfiniteAnimationPolicy:
Removed class androidx.compose.animation.core.InfiniteAnimationPolicy
+
+
+RemovedMethod: androidx.compose.animation.core.AnimationSpecKt#infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed method androidx.compose.animation.core.AnimationSpecKt.infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.AnimationSpecKt#repeatable(int, androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed method androidx.compose.animation.core.AnimationSpecKt.repeatable(int,androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.InfiniteRepeatableSpec#InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.RepeatableSpec#RepeatableSpec(int, androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.RepeatableSpec(int,androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.VectorizedInfiniteRepeatableSpec#VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.VectorizedRepeatableSpec#VectorizedRepeatableSpec(int, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.VectorizedRepeatableSpec(int,androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>,androidx.compose.animation.core.RepeatMode)
diff --git a/compose/animation/animation-core/api/current.txt b/compose/animation/animation-core/api/current.txt
index a1ad4b5..28694e4 100644
--- a/compose/animation/animation-core/api/current.txt
+++ b/compose/animation/animation-core/api/current.txt
@@ -113,9 +113,9 @@
}
public final class AnimationSpecKt {
- method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.KeyframesSpec<T> keyframes(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T>,kotlin.Unit> init);
- method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SnapSpec<T> snap(optional int delayMillis);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SpringSpec<T> spring(optional float dampingRatio, optional float stiffness, optional T? visibilityThreshold);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.TweenSpec<T> tween(optional int durationMillis, optional int delayMillis, optional androidx.compose.animation.core.Easing easing);
@@ -334,11 +334,13 @@
}
public final class InfiniteRepeatableSpec<T> implements androidx.compose.animation.core.AnimationSpec<T> {
- ctor public InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public androidx.compose.animation.core.DurationBasedAnimationSpec<T> getAnimation();
+ method public long getInitialStartOffset();
method public androidx.compose.animation.core.RepeatMode getRepeatMode();
method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
property public final androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation;
+ property public final long initialStartOffset;
property public final androidx.compose.animation.core.RepeatMode repeatMode;
}
@@ -388,12 +390,14 @@
}
@androidx.compose.runtime.Immutable public final class RepeatableSpec<T> implements androidx.compose.animation.core.FiniteAnimationSpec<T> {
- ctor public RepeatableSpec(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public RepeatableSpec(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public androidx.compose.animation.core.DurationBasedAnimationSpec<T> getAnimation();
+ method public long getInitialStartOffset();
method public int getIterations();
method public androidx.compose.animation.core.RepeatMode getRepeatMode();
method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
property public final androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation;
+ property public final long initialStartOffset;
property public final int iterations;
property public final androidx.compose.animation.core.RepeatMode repeatMode;
}
@@ -436,6 +440,21 @@
property public final T? visibilityThreshold;
}
+ public final inline class StartOffset {
+ ctor public StartOffset();
+ }
+
+ public final inline class StartOffsetType {
+ ctor public StartOffsetType();
+ }
+
+ public static final class StartOffsetType.Companion {
+ method public int getDelay();
+ method public int getFastForward();
+ property public final int Delay;
+ property public final int FastForward;
+ }
+
public final class SuspendAnimationKt {
method public static suspend Object? animate(float initialValue, float targetValue, optional float initialVelocity, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function2<? super java.lang.Float,? super java.lang.Float,kotlin.Unit> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
method public static suspend <T, V extends androidx.compose.animation.core.AnimationVector> Object? animate(androidx.compose.animation.core.TwoWayConverter<T,V> typeConverter, T? initialValue, T? targetValue, optional T? initialVelocity, optional androidx.compose.animation.core.AnimationSpec<T> animationSpec, kotlin.jvm.functions.Function2<? super T,? super T,kotlin.Unit> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
@@ -568,7 +587,7 @@
}
public final class VectorizedInfiniteRepeatableSpec<V extends androidx.compose.animation.core.AnimationVector> implements androidx.compose.animation.core.VectorizedAnimationSpec<V> {
- ctor public VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public long getDurationNanos(V initialValue, V targetValue, V initialVelocity);
method public V getValueFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
method public V getVelocityFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
@@ -587,7 +606,7 @@
}
public final class VectorizedRepeatableSpec<V extends androidx.compose.animation.core.AnimationVector> implements androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> {
- ctor public VectorizedRepeatableSpec(int iterations, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public VectorizedRepeatableSpec(int iterations, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public long getDurationNanos(V initialValue, V targetValue, V initialVelocity);
method public V getValueFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
method public V getVelocityFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
diff --git a/compose/animation/animation-core/api/public_plus_experimental_current.txt b/compose/animation/animation-core/api/public_plus_experimental_current.txt
index 18a423e..1c2ab0b 100644
--- a/compose/animation/animation-core/api/public_plus_experimental_current.txt
+++ b/compose/animation/animation-core/api/public_plus_experimental_current.txt
@@ -113,9 +113,9 @@
}
public final class AnimationSpecKt {
- method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.KeyframesSpec<T> keyframes(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T>,kotlin.Unit> init);
- method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SnapSpec<T> snap(optional int delayMillis);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SpringSpec<T> spring(optional float dampingRatio, optional float stiffness, optional T? visibilityThreshold);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.TweenSpec<T> tween(optional int durationMillis, optional int delayMillis, optional androidx.compose.animation.core.Easing easing);
@@ -337,11 +337,13 @@
}
public final class InfiniteRepeatableSpec<T> implements androidx.compose.animation.core.AnimationSpec<T> {
- ctor public InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public androidx.compose.animation.core.DurationBasedAnimationSpec<T> getAnimation();
+ method public long getInitialStartOffset();
method public androidx.compose.animation.core.RepeatMode getRepeatMode();
method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
property public final androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation;
+ property public final long initialStartOffset;
property public final androidx.compose.animation.core.RepeatMode repeatMode;
}
@@ -396,12 +398,14 @@
}
@androidx.compose.runtime.Immutable public final class RepeatableSpec<T> implements androidx.compose.animation.core.FiniteAnimationSpec<T> {
- ctor public RepeatableSpec(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public RepeatableSpec(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public androidx.compose.animation.core.DurationBasedAnimationSpec<T> getAnimation();
+ method public long getInitialStartOffset();
method public int getIterations();
method public androidx.compose.animation.core.RepeatMode getRepeatMode();
method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
property public final androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation;
+ property public final long initialStartOffset;
property public final int iterations;
property public final androidx.compose.animation.core.RepeatMode repeatMode;
}
@@ -444,6 +448,21 @@
property public final T? visibilityThreshold;
}
+ public final inline class StartOffset {
+ ctor public StartOffset();
+ }
+
+ public final inline class StartOffsetType {
+ ctor public StartOffsetType();
+ }
+
+ public static final class StartOffsetType.Companion {
+ method public int getDelay();
+ method public int getFastForward();
+ property public final int Delay;
+ property public final int FastForward;
+ }
+
public final class SuspendAnimationKt {
method public static suspend Object? animate(float initialValue, float targetValue, optional float initialVelocity, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function2<? super java.lang.Float,? super java.lang.Float,kotlin.Unit> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
method public static suspend <T, V extends androidx.compose.animation.core.AnimationVector> Object? animate(androidx.compose.animation.core.TwoWayConverter<T,V> typeConverter, T? initialValue, T? targetValue, optional T? initialVelocity, optional androidx.compose.animation.core.AnimationSpec<T> animationSpec, kotlin.jvm.functions.Function2<? super T,? super T,kotlin.Unit> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
@@ -577,7 +596,7 @@
}
public final class VectorizedInfiniteRepeatableSpec<V extends androidx.compose.animation.core.AnimationVector> implements androidx.compose.animation.core.VectorizedAnimationSpec<V> {
- ctor public VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public long getDurationNanos(V initialValue, V targetValue, V initialVelocity);
method public V getValueFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
method public V getVelocityFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
@@ -596,7 +615,7 @@
}
public final class VectorizedRepeatableSpec<V extends androidx.compose.animation.core.AnimationVector> implements androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> {
- ctor public VectorizedRepeatableSpec(int iterations, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public VectorizedRepeatableSpec(int iterations, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public long getDurationNanos(V initialValue, V targetValue, V initialVelocity);
method public V getValueFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
method public V getVelocityFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
diff --git a/compose/animation/animation-core/api/restricted_current.ignore b/compose/animation/animation-core/api/restricted_current.ignore
index 612e66b..aa35d9e 100644
--- a/compose/animation/animation-core/api/restricted_current.ignore
+++ b/compose/animation/animation-core/api/restricted_current.ignore
@@ -1,3 +1,17 @@
// Baseline format: 1.0
RemovedInterface: androidx.compose.animation.core.InfiniteAnimationPolicy:
Removed class androidx.compose.animation.core.InfiniteAnimationPolicy
+
+
+RemovedMethod: androidx.compose.animation.core.AnimationSpecKt#infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed method androidx.compose.animation.core.AnimationSpecKt.infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.AnimationSpecKt#repeatable(int, androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed method androidx.compose.animation.core.AnimationSpecKt.repeatable(int,androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.InfiniteRepeatableSpec#InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.RepeatableSpec#RepeatableSpec(int, androidx.compose.animation.core.DurationBasedAnimationSpec<T>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.RepeatableSpec(int,androidx.compose.animation.core.DurationBasedAnimationSpec<T>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.VectorizedInfiniteRepeatableSpec#VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>,androidx.compose.animation.core.RepeatMode)
+RemovedMethod: androidx.compose.animation.core.VectorizedRepeatableSpec#VectorizedRepeatableSpec(int, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>, androidx.compose.animation.core.RepeatMode):
+ Removed constructor androidx.compose.animation.core.VectorizedRepeatableSpec(int,androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V>,androidx.compose.animation.core.RepeatMode)
diff --git a/compose/animation/animation-core/api/restricted_current.txt b/compose/animation/animation-core/api/restricted_current.txt
index 157c61f..d13e3ed 100644
--- a/compose/animation/animation-core/api/restricted_current.txt
+++ b/compose/animation/animation-core/api/restricted_current.txt
@@ -113,9 +113,9 @@
}
public final class AnimationSpecKt {
- method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.KeyframesSpec<T> keyframes(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T>,kotlin.Unit> init);
- method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SnapSpec<T> snap(optional int delayMillis);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SpringSpec<T> spring(optional float dampingRatio, optional float stiffness, optional T? visibilityThreshold);
method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.TweenSpec<T> tween(optional int durationMillis, optional int delayMillis, optional androidx.compose.animation.core.Easing easing);
@@ -334,11 +334,13 @@
}
public final class InfiniteRepeatableSpec<T> implements androidx.compose.animation.core.AnimationSpec<T> {
- ctor public InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public InfiniteRepeatableSpec(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public androidx.compose.animation.core.DurationBasedAnimationSpec<T> getAnimation();
+ method public long getInitialStartOffset();
method public androidx.compose.animation.core.RepeatMode getRepeatMode();
method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
property public final androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation;
+ property public final long initialStartOffset;
property public final androidx.compose.animation.core.RepeatMode repeatMode;
}
@@ -388,12 +390,14 @@
}
@androidx.compose.runtime.Immutable public final class RepeatableSpec<T> implements androidx.compose.animation.core.FiniteAnimationSpec<T> {
- ctor public RepeatableSpec(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public RepeatableSpec(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public androidx.compose.animation.core.DurationBasedAnimationSpec<T> getAnimation();
+ method public long getInitialStartOffset();
method public int getIterations();
method public androidx.compose.animation.core.RepeatMode getRepeatMode();
method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
property public final androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation;
+ property public final long initialStartOffset;
property public final int iterations;
property public final androidx.compose.animation.core.RepeatMode repeatMode;
}
@@ -436,6 +440,21 @@
property public final T? visibilityThreshold;
}
+ public final inline class StartOffset {
+ ctor public StartOffset();
+ }
+
+ public final inline class StartOffsetType {
+ ctor public StartOffsetType();
+ }
+
+ public static final class StartOffsetType.Companion {
+ method public int getDelay();
+ method public int getFastForward();
+ property public final int Delay;
+ property public final int FastForward;
+ }
+
public final class SuspendAnimationKt {
method public static suspend Object? animate(float initialValue, float targetValue, optional float initialVelocity, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function2<? super java.lang.Float,? super java.lang.Float,kotlin.Unit> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
method public static suspend <T, V extends androidx.compose.animation.core.AnimationVector> Object? animate(androidx.compose.animation.core.TwoWayConverter<T,V> typeConverter, T? initialValue, T? targetValue, optional T? initialVelocity, optional androidx.compose.animation.core.AnimationSpec<T> animationSpec, kotlin.jvm.functions.Function2<? super T,? super T,kotlin.Unit> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
@@ -572,7 +591,7 @@
}
public final class VectorizedInfiniteRepeatableSpec<V extends androidx.compose.animation.core.AnimationVector> implements androidx.compose.animation.core.VectorizedAnimationSpec<V> {
- ctor public VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public VectorizedInfiniteRepeatableSpec(androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public long getDurationNanos(V initialValue, V targetValue, V initialVelocity);
method public V getValueFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
method public V getVelocityFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
@@ -591,7 +610,7 @@
}
public final class VectorizedRepeatableSpec<V extends androidx.compose.animation.core.AnimationVector> implements androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> {
- ctor public VectorizedRepeatableSpec(int iterations, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
+ ctor public VectorizedRepeatableSpec(int iterations, androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
method public long getDurationNanos(V initialValue, V targetValue, V initialVelocity);
method public V getValueFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
method public V getVelocityFromNanos(long playTimeNanos, V initialValue, V targetValue, V initialVelocity);
diff --git a/compose/animation/animation-core/samples/build.gradle b/compose/animation/animation-core/samples/build.gradle
index d69fec1..27a31f4 100644
--- a/compose/animation/animation-core/samples/build.gradle
+++ b/compose/animation/animation-core/samples/build.gradle
@@ -35,6 +35,7 @@
implementation("androidx.compose.ui:ui:1.0.0")
implementation("androidx.compose.ui:ui-unit:1.0.0")
implementation("androidx.compose.foundation:foundation:1.0.0")
+ implementation("androidx.compose.foundation:foundation-layout:1.0.0")
implementation("androidx.compose.material:material:1.0.0")
}
diff --git a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/AnimationSpecSamples.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/AnimationSpecSamples.kt
new file mode 100644
index 0000000..272a82d
--- /dev/null
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/AnimationSpecSamples.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required = applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.animation.core.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.StartOffset
+import androidx.compose.animation.core.StartOffsetType
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.unit.dp
+
+@Sampled
+@Composable
+fun InfiniteProgressIndicator() {
+ // This is an infinite progress indicator with 3 pulsing dots that grow and shrink.
+ @Composable
+ fun Dot(scale: State<Float>) {
+ Box(
+ Modifier.padding(5.dp).size(20.dp).graphicsLayer {
+ scaleX = scale.value
+ scaleY = scale.value
+ }.background(Color.Gray, shape = CircleShape)
+ )
+ }
+
+ val infiniteTransition = rememberInfiniteTransition()
+ val scale1 = infiniteTransition.animateFloat(
+ 0.2f,
+ 1f,
+ // No offset for the 1st animation
+ infiniteRepeatable(tween(600), RepeatMode.Reverse)
+ )
+ val scale2 = infiniteTransition.animateFloat(
+ 0.2f,
+ 1f,
+ infiniteRepeatable(
+ tween(600), RepeatMode.Reverse,
+ // Offsets the 2nd animation by starting from 150ms of the animation
+ // This offset will not be repeated.
+ initialStartOffset = StartOffset(offsetMillis = 150, StartOffsetType.FastForward)
+ )
+ )
+ val scale3 = infiniteTransition.animateFloat(
+ 0.2f,
+ 1f,
+ infiniteRepeatable(
+ tween(600), RepeatMode.Reverse,
+ // Offsets the 3rd animation by starting from 300ms of the animation. This
+ // offset will be not repeated.
+ initialStartOffset = StartOffset(offsetMillis = 300, StartOffsetType.FastForward)
+ )
+ )
+ Row {
+ Dot(scale1)
+ Dot(scale2)
+ Dot(scale3)
+ }
+}
\ No newline at end of file
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
index 12208b8..5e22a32 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
@@ -21,6 +21,7 @@
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.ui.unit.IntOffset
+import kotlin.math.abs
object AnimationConstants {
/**
@@ -161,6 +162,72 @@
}
/**
+ * This class defines the two types of [StartOffset]: [StartOffsetType.Delay] and
+ * [StartOffsetType.FastForward].
+ * [StartOffsetType.Delay] delays the start of the animation, whereas [StartOffsetType.FastForward]
+ * starts the animation right away from a given play time in the animation.
+ *
+ * @see repeatable
+ * @see infiniteRepeatable
+ * @see StartOffset
+ */
+@Suppress("INLINE_CLASS_DEPRECATED")
+inline class StartOffsetType private constructor(internal val value: Int) {
+ companion object {
+ /**
+ * Delays the start of the animation.
+ */
+ val Delay = StartOffsetType(-1)
+
+ /**
+ * Fast forwards the animation to a given play time, and starts it immediately.
+ */
+ val FastForward = StartOffsetType(1)
+ }
+}
+
+/**
+ * This class defines a start offset for [repeatable] and [infiniteRepeatable]. There are two types
+ * of start offsets: [StartOffsetType.Delay] and [StartOffsetType.FastForward].
+ * [StartOffsetType.Delay] delays the start of the animation, whereas [StartOffsetType.FastForward]
+ * fast forwards the animation to a given play time and starts it right away.
+ *
+ * @sample androidx.compose.animation.core.samples.InfiniteProgressIndicator
+ */
+@Suppress("INLINE_CLASS_DEPRECATED")
+// This is an inline of Long so that when adding a StartOffset param to the end of constructor
+// param list, it won't be confused with/clash with the mask param generated by constructors.
+inline class StartOffset private constructor(internal val value: Long) {
+ /**
+ * This creates a start offset for [repeatable] and [infiniteRepeatable]. [offsetType] can be
+ * either of the following: [StartOffsetType.Delay] and [StartOffsetType.FastForward].
+ * [offsetType] defaults to [StartOffsetType.Delay].
+ *
+ * [StartOffsetType.Delay] delays the start of the animation by [offsetMillis], whereas
+ * [StartOffsetType.FastForward] starts the animation right away from [offsetMillis] in the
+ * animation.
+ */
+ constructor(offsetMillis: Int, offsetType: StartOffsetType = StartOffsetType.Delay) : this(
+ (offsetMillis * offsetType.value).toLong()
+ )
+
+ /**
+ * Returns the number of milliseconds to offset the start of the animation.
+ */
+ val offsetMillis: Int
+ get() = abs(this.value.toInt())
+
+ /**
+ * Returns the offset type of the provided [StartOffset].
+ */
+ val offsetType: StartOffsetType
+ get() = when (this.value > 0) {
+ true -> StartOffsetType.FastForward
+ false -> StartOffsetType.Delay
+ }
+}
+
+/**
* [RepeatableSpec] takes another [DurationBasedAnimationSpec] and plays it [iterations] times. For
* creating infinitely repeating animation spec, consider using [InfiniteRepeatableSpec].
*
@@ -168,6 +235,10 @@
* __odd__ number of iterations. Otherwise, the animation may jump to the end value when it finishes
* the last iteration.
*
+ * [initialStartOffset] can be used to either delay the start of the animation or to fast forward
+ * the animation to a given play time. This start offset will **not** be repeated, whereas the delay
+ * in the [animation] (if any) will be repeated. By default, the amount of offset is 0.
+ *
* @see repeatable
* @see InfiniteRepeatableSpec
* @see infiniteRepeatable
@@ -176,30 +247,47 @@
* @param animation the [AnimationSpec] to be repeated
* @param repeatMode whether animation should repeat by starting from the beginning (i.e.
* [RepeatMode.Restart]) or from the end (i.e. [RepeatMode.Reverse])
+ * @param initialStartOffset offsets the start of the animation
*/
@Immutable
class RepeatableSpec<T>(
val iterations: Int,
val animation: DurationBasedAnimationSpec<T>,
- val repeatMode: RepeatMode = RepeatMode.Restart
+ val repeatMode: RepeatMode = RepeatMode.Restart,
+ val initialStartOffset: StartOffset = StartOffset(0)
) : FiniteAnimationSpec<T> {
+
+ @Deprecated(
+ level = DeprecationLevel.HIDDEN,
+ message = "This constructor has been deprecated"
+ )
+ constructor(
+ iterations: Int,
+ animation: DurationBasedAnimationSpec<T>,
+ repeatMode: RepeatMode = RepeatMode.Restart
+ ) : this(iterations, animation, repeatMode, StartOffset(0))
+
override fun <V : AnimationVector> vectorize(
converter: TwoWayConverter<T, V>
): VectorizedFiniteAnimationSpec<V> {
- return VectorizedRepeatableSpec(iterations, animation.vectorize(converter), repeatMode)
+ return VectorizedRepeatableSpec(
+ iterations, animation.vectorize(converter), repeatMode, initialStartOffset
+ )
}
override fun equals(other: Any?): Boolean =
if (other is RepeatableSpec<*>) {
other.iterations == this.iterations &&
other.animation == this.animation &&
- other.repeatMode == this.repeatMode
+ other.repeatMode == this.repeatMode &&
+ other.initialStartOffset == this.initialStartOffset
} else {
false
}
override fun hashCode(): Int {
- return (iterations * 31 + animation.hashCode()) * 31 + repeatMode.hashCode()
+ return ((iterations * 31 + animation.hashCode()) * 31 + repeatMode.hashCode()) * 31 +
+ initialStartOffset.hashCode()
}
}
@@ -211,31 +299,53 @@
*
* For non-infinite repeating animations, consider [RepeatableSpec].
*
+ * [initialStartOffset] can be used to either delay the start of the animation or to fast forward
+ * the animation to a given play time. This start offset will **not** be repeated, whereas the delay
+ * in the [animation] (if any) will be repeated. By default, the amount of offset is 0.
+ *
+ * @sample androidx.compose.animation.core.samples.InfiniteProgressIndicator
+ *
* @param animation the [AnimationSpec] to be repeated
* @param repeatMode whether animation should repeat by starting from the beginning (i.e.
* [RepeatMode.Restart]) or from the end (i.e. [RepeatMode.Reverse])
+ * @param initialStartOffset offsets the start of the animation
* @see infiniteRepeatable
*/
// TODO: Consider supporting repeating spring specs
class InfiniteRepeatableSpec<T>(
val animation: DurationBasedAnimationSpec<T>,
- val repeatMode: RepeatMode = RepeatMode.Restart
+ val repeatMode: RepeatMode = RepeatMode.Restart,
+ val initialStartOffset: StartOffset = StartOffset(0)
) : AnimationSpec<T> {
+
+ @Deprecated(
+ level = DeprecationLevel.HIDDEN,
+ message = "This constructor has been deprecated"
+ )
+ constructor(
+ animation: DurationBasedAnimationSpec<T>,
+ repeatMode: RepeatMode = RepeatMode.Restart
+ ) : this(animation, repeatMode, StartOffset(0))
+
override fun <V : AnimationVector> vectorize(
converter: TwoWayConverter<T, V>
): VectorizedAnimationSpec<V> {
- return VectorizedInfiniteRepeatableSpec(animation.vectorize(converter), repeatMode)
+ return VectorizedInfiniteRepeatableSpec(
+ animation.vectorize(converter), repeatMode, initialStartOffset
+ )
}
override fun equals(other: Any?): Boolean =
if (other is InfiniteRepeatableSpec<*>) {
- other.animation == this.animation && other.repeatMode == this.repeatMode
+ other.animation == this.animation && other.repeatMode == this.repeatMode &&
+ other.initialStartOffset == this.initialStartOffset
} else {
false
}
override fun hashCode(): Int {
- return animation.hashCode() * 31 + repeatMode.hashCode()
+ return (animation.hashCode() * 31 + repeatMode.hashCode()) * 31 +
+ initialStartOffset.hashCode()
}
}
@@ -452,18 +562,36 @@
* __odd__ number of iterations. Otherwise, the animation may jump to the end value when it finishes
* the last iteration.
*
+ * [initialStartOffset] can be used to either delay the start of the animation or to fast forward
+ * the animation to a given play time. This start offset will **not** be repeated, whereas the delay
+ * in the [animation] (if any) will be repeated. By default, the amount of offset is 0.
+ *
* @param iterations the total count of iterations, should be greater than 1 to repeat.
* @param animation animation that will be repeated
* @param repeatMode whether animation should repeat by starting from the beginning (i.e.
* [RepeatMode.Restart]) or from the end (i.e. [RepeatMode.Reverse])
+ * @param initialStartOffset offsets the start of the animation
*/
@Stable
fun <T> repeatable(
iterations: Int,
animation: DurationBasedAnimationSpec<T>,
- repeatMode: RepeatMode = RepeatMode.Restart
+ repeatMode: RepeatMode = RepeatMode.Restart,
+ initialStartOffset: StartOffset = StartOffset(0)
): RepeatableSpec<T> =
- RepeatableSpec(iterations, animation, repeatMode)
+ RepeatableSpec(iterations, animation, repeatMode, initialStartOffset)
+
+@Stable
+@Deprecated(
+ level = DeprecationLevel.HIDDEN,
+ message = "This method has been deprecated in favor of the repeatable function that accepts" +
+ " start offset."
+)
+fun <T> repeatable(
+ iterations: Int,
+ animation: DurationBasedAnimationSpec<T>,
+ repeatMode: RepeatMode = RepeatMode.Restart
+) = RepeatableSpec(iterations, animation, repeatMode, StartOffset(0))
/**
* Creates a [InfiniteRepeatableSpec] that plays a [DurationBasedAnimationSpec] (e.g.
@@ -471,16 +599,35 @@
*
* For non-infinitely repeating animations, consider [repeatable].
*
+ * [initialStartOffset] can be used to either delay the start of the animation or to fast forward
+ * the animation to a given play time. This start offset will **not** be repeated, whereas the delay
+ * in the [animation] (if any) will be repeated. By default, the amount of offset is 0.
+ *
+ * @sample androidx.compose.animation.core.samples.InfiniteProgressIndicator
+ *
* @param animation animation that will be repeated
* @param repeatMode whether animation should repeat by starting from the beginning (i.e.
* [RepeatMode.Restart]) or from the end (i.e. [RepeatMode.Reverse])
+ * @param initialStartOffset offsets the start of the animation
*/
@Stable
fun <T> infiniteRepeatable(
animation: DurationBasedAnimationSpec<T>,
- repeatMode: RepeatMode = RepeatMode.Restart
+ repeatMode: RepeatMode = RepeatMode.Restart,
+ initialStartOffset: StartOffset = StartOffset(0)
): InfiniteRepeatableSpec<T> =
- InfiniteRepeatableSpec(animation, repeatMode)
+ InfiniteRepeatableSpec(animation, repeatMode, initialStartOffset)
+
+@Stable
+@Deprecated(
+ level = DeprecationLevel.HIDDEN,
+ message = "This method has been deprecated in favor of the infinite repeatable function that" +
+ " accepts start offset."
+)
+fun <T> infiniteRepeatable(
+ animation: DurationBasedAnimationSpec<T>,
+ repeatMode: RepeatMode = RepeatMode.Restart
+) = InfiniteRepeatableSpec(animation, repeatMode, StartOffset(0))
/**
* Creates a Snap animation for immediately switching the animating value to the end value.
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
index a0d1b1e..367b7a0 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
@@ -353,14 +353,30 @@
* This animation takes another [VectorizedDurationBasedAnimationSpec] and plays it
* __infinite__ times.
*
+ * initialStartOffset can be used to either delay the start of the animation or to fast forward
+ * the animation to a given play time. This start offset will **not** be repeated, whereas the delay
+ * in the [animation] (if any) will be repeated. By default, the amount of offset is 0.
+ *
* @param animation the [VectorizedAnimationSpec] describing each repetition iteration.
* @param repeatMode whether animation should repeat by starting from the beginning (i.e.
* [RepeatMode.Restart]) or from the end (i.e. [RepeatMode.Reverse])
+ * @param initialStartOffset offsets the start of the animation
*/
class VectorizedInfiniteRepeatableSpec<V : AnimationVector>(
private val animation: VectorizedDurationBasedAnimationSpec<V>,
- private val repeatMode: RepeatMode = RepeatMode.Restart
+ private val repeatMode: RepeatMode = RepeatMode.Restart,
+ initialStartOffset: StartOffset = StartOffset(0)
) : VectorizedAnimationSpec<V> {
+ @Deprecated(
+ level = DeprecationLevel.HIDDEN,
+ message = "This method has been deprecated in favor of the constructor that" +
+ " accepts start offset."
+ )
+ constructor(
+ animation: VectorizedDurationBasedAnimationSpec<V>,
+ repeatMode: RepeatMode = RepeatMode.Restart
+ ) : this(animation, repeatMode, StartOffset(0))
+
override val isInfinite: Boolean get() = true
/**
@@ -369,12 +385,19 @@
internal val durationNanos: Long =
(animation.delayMillis + animation.durationMillis) * MillisToNanos
+ private val initialOffsetNanos = initialStartOffset.value * MillisToNanos
+
private fun repetitionPlayTimeNanos(playTimeNanos: Long): Long {
- val repeatsCount = playTimeNanos / durationNanos
- if (repeatMode == RepeatMode.Restart || repeatsCount % 2 == 0L) {
- return playTimeNanos - repeatsCount * durationNanos
+ if (playTimeNanos + initialOffsetNanos <= 0) {
+ return 0
} else {
- return (repeatsCount + 1) * durationNanos - playTimeNanos
+ val postOffsetPlayTimeNanos = playTimeNanos + initialOffsetNanos
+ val repeatsCount = postOffsetPlayTimeNanos / durationNanos
+ if (repeatMode == RepeatMode.Restart || repeatsCount % 2 == 0L) {
+ return postOffsetPlayTimeNanos - repeatsCount * durationNanos
+ } else {
+ return (repeatsCount + 1) * durationNanos - postOffsetPlayTimeNanos
+ }
}
}
@@ -383,10 +406,10 @@
start: V,
startVelocity: V,
end: V
- ): V = if (playTimeNanos > durationNanos) {
+ ): V = if (playTimeNanos + initialOffsetNanos > durationNanos) {
// Start velocity of the 2nd and subsequent iteration will be the velocity at the end
// of the first iteration, instead of the initial velocity.
- getVelocityFromNanos(durationNanos, start, startVelocity, end)
+ getVelocityFromNanos(durationNanos - initialOffsetNanos, start, startVelocity, end)
} else {
startVelocity
}
@@ -433,16 +456,33 @@
* __odd__ number of iterations. Otherwise, the animation may jump to the end value when it finishes
* the last iteration.
*
+ * initialStartOffset can be used to either delay the start of the animation or to fast forward
+ * the animation to a given play time. This start offset will **not** be repeated, whereas the delay
+ * in the [animation] (if any) will be repeated. By default, the amount of offset is 0.
+ *
+ *
* @param iterations the count of iterations. Should be at least 1.
* @param animation the [VectorizedAnimationSpec] describing each repetition iteration.
* @param repeatMode whether animation should repeat by starting from the beginning (i.e.
* [RepeatMode.Restart]) or from the end (i.e. [RepeatMode.Reverse])
+ * @param initialStartOffset offsets the start of the animation
*/
class VectorizedRepeatableSpec<V : AnimationVector>(
private val iterations: Int,
private val animation: VectorizedDurationBasedAnimationSpec<V>,
- private val repeatMode: RepeatMode = RepeatMode.Restart
+ private val repeatMode: RepeatMode = RepeatMode.Restart,
+ initialStartOffset: StartOffset = StartOffset(0)
) : VectorizedFiniteAnimationSpec<V> {
+ @Deprecated(
+ level = DeprecationLevel.HIDDEN,
+ message = "This method has been deprecated in favor of the constructor that accepts" +
+ " start offset."
+ )
+ constructor(
+ iterations: Int,
+ animation: VectorizedDurationBasedAnimationSpec<V>,
+ repeatMode: RepeatMode = RepeatMode.Restart
+ ) : this(iterations, animation, repeatMode, StartOffset(0))
init {
if (iterations < 1) {
@@ -450,15 +490,24 @@
}
}
+ // Per-iteration duration
internal val durationNanos: Long =
(animation.delayMillis + animation.durationMillis) * MillisToNanos
+ // Fast forward amount. Delay type => negative offset
+ private val initialOffsetNanos = initialStartOffset.value * MillisToNanos
+
private fun repetitionPlayTimeNanos(playTimeNanos: Long): Long {
- val repeatsCount = min(playTimeNanos / durationNanos, iterations - 1L)
- if (repeatMode == RepeatMode.Restart || repeatsCount % 2 == 0L) {
- return playTimeNanos - repeatsCount * durationNanos
+ if (playTimeNanos + initialOffsetNanos <= 0) {
+ return 0
} else {
- return (repeatsCount + 1) * durationNanos - playTimeNanos
+ val postOffsetPlayTimeNanos = playTimeNanos + initialOffsetNanos
+ val repeatsCount = min(postOffsetPlayTimeNanos / durationNanos, iterations - 1L)
+ if (repeatMode == RepeatMode.Restart || repeatsCount % 2 == 0L) {
+ return postOffsetPlayTimeNanos - repeatsCount * durationNanos
+ } else {
+ return (repeatsCount + 1) * durationNanos - postOffsetPlayTimeNanos
+ }
}
}
@@ -467,10 +516,10 @@
start: V,
startVelocity: V,
end: V
- ): V = if (playTimeNanos > durationNanos) {
+ ): V = if (playTimeNanos + initialOffsetNanos > durationNanos) {
// Start velocity of the 2nd and subsequent iteration will be the velocity at the end
// of the first iteration, instead of the initial velocity.
- getVelocityFromNanos(durationNanos, start, startVelocity, end)
+ getVelocityFromNanos(durationNanos - initialOffsetNanos, start, startVelocity, end)
} else
startVelocity
@@ -504,7 +553,7 @@
@Suppress("MethodNameUnits")
override fun getDurationNanos(initialValue: V, targetValue: V, initialVelocity: V): Long {
- return iterations * durationNanos
+ return iterations * durationNanos - initialOffsetNanos
}
}
diff --git a/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt
index 2761e91..919aedb 100644
--- a/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt
+++ b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt
@@ -173,6 +173,122 @@
)
}
+ @Test
+ fun testStartOffsetRepeatable() {
+ val duration = 600
+ val offset = duration / 2
+
+ val repeatable = TargetBasedAnimation(
+ repeatable<Float>(5, tween(duration, easing = LinearEasing), RepeatMode.Restart),
+ Float.VectorConverter,
+ 0f,
+ 1000f
+ )
+ val delayedRepeatable = TargetBasedAnimation(
+ repeatable<Float>(
+ 5,
+ tween(duration, easing = LinearEasing),
+ RepeatMode.Restart, StartOffset(offset)
+ ),
+ Float.VectorConverter,
+ 0f,
+ 1000f
+ )
+ val fastForwardedRepeatable = TargetBasedAnimation(
+ repeatable<Float>(
+ 5,
+ tween(duration, easing = LinearEasing),
+ RepeatMode.Restart, StartOffset(offset, StartOffsetType.FastForward)
+ ),
+ Float.VectorConverter,
+ 0f,
+ 1000f
+ )
+
+ assertEquals(
+ repeatable.durationNanos, delayedRepeatable.durationNanos - offset * 1_000_000L
+ )
+ assertEquals(
+ repeatable.durationNanos, fastForwardedRepeatable.durationNanos + offset * 1_000_000L
+ )
+
+ for (playtimeMillis in 0..duration * 3 step 17) {
+ assertEquals(
+ repeatable.getValueFromNanos(playtimeMillis * MillisToNanos),
+ delayedRepeatable.getValueFromNanos((playtimeMillis + offset) * MillisToNanos)
+ )
+ }
+
+ // Check that during the delayed time, the value is unchanged
+ for (playTimeMillis in 0..offset step 10) {
+ assertEquals(
+ repeatable.getValueFromNanos(0),
+ delayedRepeatable.getValueFromNanos(playTimeMillis * MillisToNanos)
+ )
+ }
+
+ for (playtimeMillis in 0..duration * 3 step 17) {
+ assertEquals(
+ repeatable.getValueFromNanos(playtimeMillis * MillisToNanos),
+ fastForwardedRepeatable.getValueFromNanos((playtimeMillis - offset) * MillisToNanos)
+ )
+ }
+ }
+
+ @Test
+ fun testStartOffsetInfiniteRepeatable() {
+ val duration = 600
+ val offset = 31
+
+ val repeatable = TargetBasedAnimation(
+ infiniteRepeatable(tween(duration), RepeatMode.Restart),
+ Float.VectorConverter,
+ 0f,
+ 1000f
+ )
+ val delayedRepeatable = TargetBasedAnimation(
+ infiniteRepeatable(tween(duration), RepeatMode.Restart, StartOffset(offset)),
+ Float.VectorConverter,
+ 0f,
+ 1000f
+ )
+ val fastForwardedRepeatable = TargetBasedAnimation(
+ infiniteRepeatable(
+ tween(duration),
+ RepeatMode.Restart, StartOffset(offset, StartOffsetType.FastForward)
+ ),
+ Float.VectorConverter,
+ 0f,
+ 1000f
+ )
+
+ // Duration should be infinite for delay or fast forward
+ assertEquals(repeatable.durationNanos, delayedRepeatable.durationNanos)
+ assertEquals(repeatable.durationNanos, fastForwardedRepeatable.durationNanos)
+
+ for (playtimeMillis in 0..duration * 3 step 17) {
+ assertEquals(
+ repeatable.getValueFromNanos(playtimeMillis * MillisToNanos),
+ delayedRepeatable.getValueFromNanos((playtimeMillis + offset) * MillisToNanos)
+ )
+ }
+
+ // Check that during the delayed time, the value is unchanged
+ for (playTimeMillis in 0..offset step 10) {
+ assertEquals(
+ repeatable.getValueFromNanos(0),
+ delayedRepeatable.getValueFromNanos(playTimeMillis * MillisToNanos)
+ )
+ }
+
+ for (playtimeMillis in 0..duration * 3 step 17) {
+ assertEquals(
+ repeatable.getValueFromNanos(playtimeMillis * MillisToNanos),
+ fastForwardedRepeatable.getValueFromNanos((playtimeMillis - offset) * MillisToNanos)
+ )
+ }
+ }
+
private companion object {
private val DelayDuration = 13
private val Duration = 50
diff --git a/compose/animation/animation-lint/src/test/java/androidx/compose/animation/lint/CrossfadeDetectorTest.kt b/compose/animation/animation-lint/src/test/java/androidx/compose/animation/lint/CrossfadeDetectorTest.kt
index c7cd1a4..3cbd5de 100644
--- a/compose/animation/animation-lint/src/test/java/androidx/compose/animation/lint/CrossfadeDetectorTest.kt
+++ b/compose/animation/animation-lint/src/test/java/androidx/compose/animation/lint/CrossfadeDetectorTest.kt
@@ -23,7 +23,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -44,6 +43,7 @@
private val CrossfadeStub = compiledStub(
filename = "Transition.kt",
filepath = "androidx/compose/animation",
+ checksum = 0x33cac1e3,
"""
package androidx.compose.animation
@@ -56,6 +56,12 @@
) {}
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcUllZiXUpSfmVKhl5yfW5BfnKqX
+ mJeZm1iSmZ8nxBNSlJhXnAlie5dw8XIxp+XnC7GFpBaXeJcoMWgxAACekN3e
+ UwAAAA==
+ """,
+ """
androidx/compose/animation/TransitionKt.class:
H4sIAAAAAAAAAIVSW08TQRT+ZnvZdgFZyr0oIhcBUbcQfLHExJAQGisYW3nh
abpd6vQya3amDY/9Lf4D34wPpvHRH2U8s1RBasIme86Zb77znTNn5uevb98B
@@ -72,16 +78,9 @@
Gg4eUzx3RUEO07GETfgM7W/GbBtbQ36G/Db9WSuuk423n8R2DTvkDwmdpepz
50iUMF/CAlkslpDHUgn38eAcTGEZD8+RUUgprCg8UsgpOAqryoDp38bsatcp
BAAA
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcUllZiXUpSfmVKhl5yfW5BfnKqX
- mJeZm1iSmZ8nxBNSlJhXnAlie5dw8XIxp+XnC7GFpBaXeJcoMWgxAACekN3e
- UwAAAA==
"""
)
- @Ignore // b/193270279
@Test
fun unreferencedParameters() {
lint().files(
@@ -134,7 +133,6 @@
)
}
- @Ignore // b/193270279
@Test
fun unreferencedParameter_shadowedNames() {
lint().files(
@@ -246,7 +244,6 @@
CrossfadeStub,
Stubs.Composable
)
- .allowCompilationErrors(true) // b/193270279
.run()
.expectClean()
}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index 10f7d77..ffa354f 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -81,13 +81,20 @@
),
DemoCategory(
+ "Visual Aid \uD83D\uDC40 \uD83D\uDC40",
+ listOf(
+ ComposableDemo("Column Arrangements Demo") { ColumnConfigurationDemo() },
+ ComposableDemo("Row Arrangements Demo (Landscape)") { RowConfigurationDemo() },
+ )
+ ),
+
+ DemoCategory(
"\uD83C\uDF89 Fun Demos",
listOf(
ComposableDemo("Animated clock") { AnimatedClockDemo() },
ComposableDemo("Animated dots") { AnimatedDotsDemo() },
ComposableDemo("Chat screen") { ChatScreen() },
ComposableDemo("Game of fling") { FlingGame() },
- ComposableDemo("Row Configuration Demo (Landscape)") { RowConfigurationDemo() },
ComposableDemo("Spring chain") { SpringChainDemo() },
)
)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/ColumnConfigurationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/ColumnConfigurationDemo.kt
new file mode 100644
index 0000000..5662e19
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/ColumnConfigurationDemo.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.animation.demos
+
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.animate
+import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.produceState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.InfiniteAnimationPolicy
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import kotlinx.coroutines.delay
+
+@Composable
+fun ColumnConfigurationDemo() {
+ val height by produceState(250.dp) {
+ // Skip the animations in tests.
+ while (coroutineContext[InfiniteAnimationPolicy] == null) {
+ animate(
+ Dp.VectorConverter, 250.dp, 520.dp,
+ animationSpec = spring(Spring.DampingRatioMediumBouncy, Spring.StiffnessLow)
+ ) { value, _ ->
+ this.value = value
+ }
+ delay(1000)
+ animate(
+ Dp.VectorConverter, 520.dp, 250.dp,
+ animationSpec = tween(520)
+ ) { value, _ ->
+ this.value = value
+ }
+ delay(1000)
+ }
+ }
+ ResizableColumn(height)
+}
+
+@Composable
+fun ResizableColumn(height: Dp) {
+ Column(
+ Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Row(
+ verticalAlignment = Alignment.Bottom,
+ modifier = Modifier.background(Color.White, RoundedCornerShape(5.dp)).padding(10.dp)
+ ) {
+ Text(
+ text = "Equal\nWeight",
+ modifier = Modifier.width(50.dp).padding(2.dp),
+ fontSize = 12.sp, textAlign = TextAlign.Center
+ )
+ Text(
+ text = "Space\nBetween",
+ modifier = Modifier.width(50.dp).padding(2.dp),
+ fontSize = 11.sp,
+ textAlign = TextAlign.Center
+ )
+ Text(
+ text = "Space\nAround",
+ modifier = Modifier.width(50.dp).padding(2.dp),
+ fontSize = 12.sp,
+ textAlign = TextAlign.Center
+ )
+ Text(
+ text = "Space\nEvenly",
+ modifier = Modifier.width(50.dp).padding(2.dp),
+ fontSize = 12.sp,
+ textAlign = TextAlign.Center
+ )
+ Text(
+ text = "Top",
+ modifier = Modifier.width(50.dp).padding(2.dp),
+ fontSize = 12.sp,
+ textAlign = TextAlign.Center
+ )
+ Text(
+ text = "Center",
+ modifier = Modifier.width(50.dp).padding(2.dp),
+ fontSize = 12.sp,
+ textAlign = TextAlign.Center
+ )
+ Text(
+ text = "Bottom",
+ modifier = Modifier.width(50.dp).padding(2.dp),
+ fontSize = 12.sp,
+ textAlign = TextAlign.Center
+ )
+ }
+ Row(Modifier.height(520.dp).requiredHeight(height)) {
+ Column(Modifier.default(androidBlue)) {
+ ColumnItem("A", fixedSize = false)
+ ColumnItem("B", fixedSize = false)
+ ColumnItem("C", fixedSize = false)
+ }
+ Column(Modifier.default(androidDark), verticalArrangement = Arrangement.SpaceBetween) {
+ ColumnItem(text = "A")
+ ColumnItem(text = "B")
+ ColumnItem(text = "C")
+ }
+ Column(Modifier.default(androidGreen), verticalArrangement = Arrangement.SpaceAround) {
+ ColumnItem(text = "A")
+ ColumnItem(text = "B")
+ ColumnItem(text = "C")
+ }
+ Column(Modifier.default(androidBlue), verticalArrangement = Arrangement.SpaceEvenly) {
+ ColumnItem(text = "A")
+ ColumnItem(text = "B")
+ ColumnItem(text = "C")
+ }
+ Column(Modifier.default(androidDark), verticalArrangement = Arrangement.Top) {
+ ColumnItem(text = "A")
+ ColumnItem(text = "B")
+ ColumnItem(text = "C")
+ }
+ Column(Modifier.default(androidGreen), verticalArrangement = Arrangement.Center) {
+ ColumnItem(text = "A")
+ ColumnItem(text = "B")
+ ColumnItem(text = "C")
+ }
+ Column(Modifier.default(androidBlue), verticalArrangement = Arrangement.Bottom) {
+ ColumnItem(text = "A")
+ ColumnItem(text = "B")
+ ColumnItem(text = "C")
+ }
+ }
+ }
+}
+
+private fun Modifier.default(backgroundColor: Color) =
+ this.width(50.dp).padding(2.dp)
+ .background(backgroundColor, RoundedCornerShape(5.dp)).padding(top = 3.dp, bottom = 3.dp)
+ .fillMaxHeight()
+
+@Composable
+fun ColumnScope.ColumnItem(text: String, fixedSize: Boolean = true) {
+ val modifier = if (fixedSize) Modifier.height(80.dp) else Modifier.weight(1f)
+ Box(
+ modifier.width(50.dp).padding(5.dp).shadow(10.dp)
+ .background(Color.White, shape = RoundedCornerShape(5.dp))
+ .padding(top = 5.dp, bottom = 5.dp)
+ ) {
+ Text(text, Modifier.align(Alignment.Center), color = androidDark)
+ }
+}
+
+val androidBlue = Color(0xff4282f2)
\ No newline at end of file
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/InfiniteTransitionDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/InfiniteTransitionDemo.kt
index 34e6bb1..68885278 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/InfiniteTransitionDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/InfiniteTransitionDemo.kt
@@ -17,14 +17,24 @@
package androidx.compose.animation.demos
import androidx.compose.animation.animateColor
+import androidx.compose.animation.core.InfiniteTransition
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.StartOffset
+import androidx.compose.animation.core.StartOffsetType
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
@@ -34,9 +44,22 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.unit.dp
@Composable
fun InfiniteTransitionDemo() {
+ Column(
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ InfinitePulsingHeart()
+ Spacer(Modifier.size(200.dp))
+ InfiniteProgress()
+ }
+}
+
+@Composable
+fun InfinitePulsingHeart() {
val infiniteTransition = rememberInfiniteTransition()
val scale by infiniteTransition.animateFloat(
@@ -57,16 +80,38 @@
)
)
- Box(Modifier.fillMaxSize()) {
- Icon(
- Icons.Filled.Favorite,
- null,
- Modifier.align(Alignment.Center)
- .graphicsLayer(
- scaleX = scale,
- scaleY = scale
- ),
- tint = color
- )
+ Icon(
+ Icons.Filled.Favorite,
+ null,
+ Modifier.graphicsLayer(
+ scaleX = scale,
+ scaleY = scale
+ ),
+ tint = color
+ )
+}
+
+@Composable
+fun InfiniteProgress() {
+ val infiniteTransition = rememberInfiniteTransition()
+ Row {
+ infiniteTransition.PulsingDot(StartOffset(0))
+ infiniteTransition.PulsingDot(StartOffset(150, StartOffsetType.FastForward))
+ infiniteTransition.PulsingDot(StartOffset(300, StartOffsetType.FastForward))
}
}
+
+@Composable
+fun InfiniteTransition.PulsingDot(startOffset: StartOffset) {
+ val scale by animateFloat(
+ 0.2f,
+ 1f,
+ infiniteRepeatable(tween(600), RepeatMode.Reverse, initialStartOffset = startOffset)
+ )
+ Box(
+ Modifier.padding(5.dp).size(20.dp).graphicsLayer {
+ scaleX = scale
+ scaleY = scale
+ }.background(Color.Gray, shape = CircleShape)
+ )
+}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RowConfigurationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RowConfigurationDemo.kt
index 27e353f..19d6e3e 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RowConfigurationDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RowConfigurationDemo.kt
@@ -26,10 +26,12 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredWidth
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -42,24 +44,27 @@
import androidx.compose.ui.platform.InfiniteAnimationPolicy
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.delay
@Composable
fun RowConfigurationDemo() {
- val width by produceState(240.dp) {
+ val width by produceState(250.dp) {
// Skip the animations in tests.
while (coroutineContext[InfiniteAnimationPolicy] == null) {
animate(
- Dp.VectorConverter, 240.dp, 500.dp,
- animationSpec = spring(Spring.DampingRatioHighBouncy, Spring.StiffnessLow)
+ Dp.VectorConverter, 250.dp, 520.dp,
+ animationSpec = spring(Spring.DampingRatioMediumBouncy, Spring.StiffnessLow)
) { value, _ ->
this.value = value
}
+ delay(1000)
animate(
- Dp.VectorConverter, 500.dp, 240.dp,
- animationSpec = tween(500)
+ Dp.VectorConverter, 520.dp, 250.dp,
+ animationSpec = tween(520)
) { value, _ ->
this.value = value
}
+ delay(1000)
}
}
ResizableLayout(width)
@@ -76,44 +81,42 @@
Text(text = "Space Between", modifier = Modifier.padding(12.dp))
Text(text = "Space Around", modifier = Modifier.padding(12.dp))
Text(text = "Space Evenly", modifier = Modifier.padding(12.dp))
- Text(text = "Align to End", modifier = Modifier.padding(12.dp))
+ Text(text = "End (LTR)", modifier = Modifier.padding(12.dp))
Text(text = "Center", modifier = Modifier.padding(12.dp))
- Text(text = "Align to Start", modifier = Modifier.padding(12.dp))
+ Text(text = "Start (LTR)", modifier = Modifier.padding(12.dp))
}
Column(Modifier.weight(1f).requiredWidth(width)) {
- val rowModifier =
- Modifier.padding(2.dp).background(Color.Blue, RoundedCornerShape(5.dp))
- Row(rowModifier.fillMaxWidth()) {
- RowItem(Modifier.weight(1f), "A")
- RowItem(Modifier.weight(1f), "B")
- RowItem(Modifier.weight(1f), "C")
+ Row(Modifier.default(androidBlue)) {
+ RowItem("A", fixedSize = false)
+ RowItem("B", fixedSize = false)
+ RowItem("C", fixedSize = false)
}
- Row(rowModifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
+ Row(Modifier.default(androidDark), horizontalArrangement = Arrangement.SpaceBetween) {
RowItem(text = "A")
RowItem(text = "B")
RowItem(text = "C")
}
- Row(rowModifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround) {
+ Row(Modifier.default(androidGreen), horizontalArrangement = Arrangement.SpaceAround) {
RowItem(text = "A")
RowItem(text = "B")
RowItem(text = "C")
}
- Row(rowModifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
+ Row(Modifier.default(androidBlue), horizontalArrangement = Arrangement.SpaceEvenly) {
RowItem(text = "A")
RowItem(text = "B")
RowItem(text = "C")
}
- Row(rowModifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
+ Row(Modifier.default(androidDark), horizontalArrangement = Arrangement.End) {
RowItem(text = "A")
RowItem(text = "B")
RowItem(text = "C")
}
- Row(rowModifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
+ Row(Modifier.default(androidGreen), horizontalArrangement = Arrangement.Center) {
RowItem(text = "A")
RowItem(text = "B")
RowItem(text = "C")
}
- Row(rowModifier.fillMaxWidth(), horizontalArrangement = Arrangement.Start) {
+ Row(Modifier.default(androidBlue), horizontalArrangement = Arrangement.Start) {
RowItem(text = "A")
RowItem(text = "B")
RowItem(text = "C")
@@ -122,13 +125,21 @@
}
}
+private fun Modifier.default(background: Color) = this.padding(2.dp)
+ .background(background, RoundedCornerShape(5.dp)).padding(start = 3.dp, end = 3.dp)
+ .fillMaxWidth()
+
@Composable
-fun RowItem(modifier: Modifier = Modifier, text: String, background: Color = Color.Yellow) {
+fun RowScope.RowItem(text: String, fixedSize: Boolean = true) {
+ val modifier = if (fixedSize) Modifier.width(80.dp) else Modifier.weight(1f)
Box(
modifier.padding(5.dp).shadow(10.dp)
- .background(background, shape = RoundedCornerShape(5.dp))
- .padding(start = 30.dp, end = 30.dp, top = 5.dp, bottom = 5.dp)
+ .background(Color.White, shape = RoundedCornerShape(5.dp))
+ .padding(top = 5.dp, bottom = 5.dp)
) {
- Text(text, Modifier.align(Alignment.Center))
+ Text(text, Modifier.align(Alignment.Center), color = androidDark)
}
}
+
+internal val androidGreen = Color(0xff3ddb85)
+internal val androidDark = Color(0xff083042)
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
index 99e32a1..6271581 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
@@ -52,19 +52,20 @@
3302 to "1.0.2",
4000 to "1.1.0-alpha01",
4100 to "1.1.0-alpha02",
+ 4200 to "1.1.0-alpha03",
)
/**
* The minimum version int that this compiler is guaranteed to be compatible with. Typically
* this will match the version int that is in ComposeVersion.kt in the runtime.
*/
- private val minimumRuntimeVersionInt: Int = 4100
+ private val minimumRuntimeVersionInt: Int = 4200
/**
* The maven version string of this compiler. This string should be updated before/after every
* release.
*/
- val compilerVersion: String = "1.1.0-alpha02"
+ val compilerVersion: String = "1.1.0-alpha03"
private val minimumRuntimeVersion: String
get() = versionTable[minimumRuntimeVersionInt] ?: "unknown"
}
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
index 2831520..6393c20 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
@@ -20,7 +20,9 @@
import androidx.compose.compiler.plugins.kotlin.analysis.ComposeWritableSlices
import androidx.compose.compiler.plugins.kotlin.irTrace
import androidx.compose.compiler.plugins.kotlin.lower.decoys.copyWithNewTypeParams
+import androidx.compose.compiler.plugins.kotlin.lower.decoys.didDecoyHaveDefaultForValueParameter
import androidx.compose.compiler.plugins.kotlin.lower.decoys.isDecoy
+import androidx.compose.compiler.plugins.kotlin.lower.decoys.isDecoyImplementation
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
@@ -87,6 +89,7 @@
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -500,6 +503,11 @@
// have it as well...
if (this !is IrSimpleFunction) return false
if (valueParameters[index].defaultValue != null) return true
+
+ if (context.platform.isJs() && this.isDecoyImplementation()) {
+ if (didDecoyHaveDefaultForValueParameter(index)) return true
+ }
+
return overriddenSymbols.any {
it.owner.hasDefaultExpressionDefinedForValueParameter(index)
}
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
index b323edd..4e6436d 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
@@ -49,6 +49,7 @@
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.hasAnnotation
+import org.jetbrains.kotlin.ir.util.hasDefaultValue
import org.jetbrains.kotlin.ir.util.isLocal
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.name.Name
@@ -100,6 +101,9 @@
getTopLevelClass(DecoyFqNames.DecoyImplementation).owner
}
+ private val decoyImplementationDefaultsBitmaskAnnotation =
+ getTopLevelClass(DecoyFqNames.DecoyImplementationDefaultsBitMask).owner
+
private val decoyStub by lazy {
getInternalFunction("illegalDecoyCallException").owner
}
@@ -245,6 +249,18 @@
it.putValueArgument(0, irConst(name))
it.putValueArgument(1, irConst(signatureId))
}
+
+ annotations = annotations +
+ IrConstructorCallImpl.fromSymbolOwner(
+ type = decoyImplementationDefaultsBitmaskAnnotation.defaultType,
+ constructorSymbol =
+ decoyImplementationDefaultsBitmaskAnnotation.constructors.first().symbol
+ ).also {
+ val paramsWithDefaultsBitMask = bitMask(
+ *valueParameters.map { it.hasDefaultValue() }.toBooleanArray()
+ )
+ it.putValueArgument(0, irConst(paramsWithDefaultsBitMask))
+ }
}
private fun IrFunction.shouldBeRemapped(): Boolean =
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt
index 44977cd..71ab098 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt
@@ -21,5 +21,8 @@
object DecoyFqNames {
val Decoy = ComposeFqNames.internalFqNameFor("Decoy")
val DecoyImplementation = ComposeFqNames.internalFqNameFor("DecoyImplementation")
- val CurrentComposerIntrinsic = ComposeFqNames.fqNameFor("\$get-currentComposer\$\$composable")
+ val DecoyImplementationDefaultsBitMask =
+ ComposeFqNames.internalFqNameFor("DecoyImplementationDefaultsBitMask")
+ val CurrentComposerIntrinsic =
+ ComposeFqNames.fqNameFor("\$get-currentComposer\$\$composable")
}
\ No newline at end of file
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt
index 23be234..be60339 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt
@@ -176,6 +176,25 @@
fun IrDeclaration.isDecoy(): Boolean =
hasAnnotationSafe(DecoyFqNames.Decoy)
+@OptIn(ObsoleteDescriptorBasedAPI::class)
+fun IrDeclaration.isDecoyImplementation(): Boolean =
+ hasAnnotationSafe(DecoyFqNames.DecoyImplementation)
+
+private fun IrFunction.getDecoyImplementationDefaultValuesBitMask(): Int? {
+ val annotation = getAnnotation(DecoyFqNames.DecoyImplementationDefaultsBitMask) ?: return null
+
+ @Suppress("UNCHECKED_CAST")
+ val paramsDefaultsBitMask = annotation.getValueArgument(0) as IrConst<Int>
+
+ return paramsDefaultsBitMask.value
+}
+
+fun IrFunction.didDecoyHaveDefaultForValueParameter(paramIndex: Int): Boolean {
+ return getDecoyImplementationDefaultValuesBitMask()?.let {
+ it.shr(paramIndex).and(1) == 1
+ } ?: false
+}
+
inline fun <reified T : IrElement> T.copyWithNewTypeParams(
source: IrFunction,
target: IrFunction
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt
index d230351..b855b16 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package androidx.compose.desktop.examples.example1
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.TweenSpec
-import androidx.compose.desktop.AppWindow
import androidx.compose.desktop.DesktopMaterialTheme
import androidx.compose.foundation.ExperimentalDesktopApi
import androidx.compose.foundation.ExperimentalFoundationApi
@@ -80,8 +80,6 @@
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.plus
-import androidx.compose.ui.input.key.shortcuts
import androidx.compose.ui.input.pointer.isAltPressed
import androidx.compose.ui.input.pointer.isCtrlPressed
import androidx.compose.ui.input.pointer.isMetaPressed
@@ -89,6 +87,10 @@
import androidx.compose.ui.input.pointer.isSecondaryPressed
import androidx.compose.ui.input.pointer.isShiftPressed
import androidx.compose.ui.input.pointer.isTertiaryPressed
+import androidx.compose.ui.input.key.isMetaPressed
+import androidx.compose.ui.input.key.isShiftPressed
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.pointer.pointerMoveFilter
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
@@ -104,13 +106,18 @@
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextDecoration.Companion.Underline
import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
-import androidx.compose.ui.window.singleWindowApplication
+import androidx.compose.ui.window.Window
import androidx.compose.ui.window.FrameWindowScope
+import androidx.compose.ui.window.WindowSize
import androidx.compose.ui.window.WindowState
+import androidx.compose.ui.window.launchApplication
+import androidx.compose.ui.window.rememberWindowState
+import androidx.compose.ui.window.singleWindowApplication
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.GlobalScope
import kotlin.random.Random
private const val title = "Desktop Compose Elements"
@@ -126,7 +133,6 @@
FontFamily.SansSerif
}
-@OptIn(ExperimentalComposeUiApi::class)
fun main() = singleWindowApplication(
title = title,
state = WindowState(width = 1024.dp, height = 850.dp)
@@ -409,12 +415,22 @@
Button(
modifier = Modifier.padding(4.dp),
onClick = {
- AppWindow(size = IntSize(400, 200)).also {
- it.keyboard.setShortcut(Key.Escape) {
- it.close()
+ @OptIn(DelicateCoroutinesApi::class)
+ GlobalScope.launchApplication {
+ Window(
+ onCloseRequest = ::exitApplication,
+ state = rememberWindowState(size = WindowSize(400.dp, 200.dp)),
+ onPreviewKeyEvent = {
+ if (it.key == Key.Escape) {
+ exitApplication()
+ true
+ } else {
+ false
+ }
+ }
+ ) {
+ Animations(isCircularEnabled = animation.value)
}
- }.show {
- Animations(isCircularEnabled = animation.value)
}
}
) {
@@ -447,12 +463,17 @@
Text(text = "Important input")
},
maxLines = 1,
- modifier = Modifier.shortcuts {
- on(Key.MetaLeft + Key.ShiftLeft + Key.Enter) {
- text.value = "Cleared with shift!"
- }
- on(Key.MetaLeft + Key.Enter) {
- text.value = "Cleared!"
+ modifier = Modifier.onPreviewKeyEvent {
+ when {
+ (it.isMetaPressed && it.key == Key.Enter) -> {
+ if (it.isShiftPressed) {
+ text.value = "Cleared with shift!"
+ } else {
+ text.value = "Cleared!"
+ }
+ true
+ }
+ else -> false
}
}.focusOrder(focusItem1) {
next = focusItem2
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example2/Main.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example2/Main.jvm.kt
index f2333a5..c133dee 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example2/Main.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example2/Main.jvm.kt
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package androidx.compose.desktop.examples.example2
-import androidx.compose.desktop.Window
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
@@ -23,12 +23,15 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.inset
import androidx.compose.ui.graphics.drawscope.withTransform
-import androidx.compose.ui.unit.IntSize
-
-private const val title = "Desktop Compose Canvas"
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.WindowState
+import androidx.compose.ui.window.singleWindowApplication
fun main() {
- Window(title, IntSize(1024, 768)) {
+ singleWindowApplication(
+ title = "Desktop Compose Canvas",
+ state = WindowState(width = 1024.dp, height = 850.dp)
+ ) {
Canvas(modifier = Modifier.fillMaxSize()) {
drawRect(Color.Magenta)
inset(10.0f) {
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.jvm.kt
index 19a3ec5..01700ee 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.jvm.kt
@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package androidx.compose.desktop.examples.popupexample
-import androidx.compose.desktop.AppManager
-import androidx.compose.desktop.AppWindow
-import androidx.compose.desktop.SwingPanel
import androidx.compose.foundation.background
import androidx.compose.foundation.BoxWithTooltip
import androidx.compose.foundation.TooltipPlacement
+import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -34,6 +33,7 @@
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.window.WindowDraggableArea
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
@@ -41,6 +41,7 @@
import androidx.compose.material.ContextMenu
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
+import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.RadioButton
import androidx.compose.material.Surface
import androidx.compose.material.Text
@@ -51,38 +52,33 @@
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.SwingPanel
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.window.Notifier
+import androidx.compose.ui.window.ApplicationScope
+import androidx.compose.ui.window.Dialog
+import androidx.compose.ui.window.Notification
import androidx.compose.ui.window.Popup
-import androidx.compose.ui.window.WindowDraggableArea
-import androidx.compose.ui.window.v1.Dialog
-import androidx.compose.ui.window.v1.DialogProperties
-import androidx.compose.ui.window.v1.Tray
-import java.awt.Toolkit
+import androidx.compose.ui.window.TrayState
+import androidx.compose.ui.window.Window
+import androidx.compose.ui.window.WindowPlacement
+import androidx.compose.ui.window.WindowScope
+import androidx.compose.ui.window.WindowSize
+import androidx.compose.ui.window.WindowState
+import androidx.compose.ui.window.rememberWindowState
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import javax.swing.JButton
+@OptIn(ExperimentalMaterialApi::class)
@Composable
-fun content() {
- DisposableEffect(Unit) {
- val tray = Tray().apply {
- icon(AppState.image())
- menu(
- MenuItems.Notify,
- MenuItems.Increment,
- MenuItems.Exit
- )
- }
- onDispose {
- tray.remove()
- }
- }
-
+fun WindowScope.Content(
+ windowState: WindowState,
+ trayState: TrayState,
+) {
val dialogState = remember { mutableStateOf(false) }
Surface(
@@ -107,15 +103,15 @@
color = Color(210, 210, 210),
size = IntSize(16, 16),
onClick = {
- AppManager.focusedWindow?.makeFullscreen()
+ windowState.placement = WindowPlacement.Fullscreen
}
)
- Spacer(modifier = Modifier.width(30.dp))
+ Spacer(modifier = Modifier.width(3.dp))
Button(
color = Color(232, 182, 109),
size = IntSize(16, 16),
onClick = {
- AppManager.focusedWindow?.minimize()
+ windowState.isMinimized = true
}
)
Spacer(modifier = Modifier.width(3.dp))
@@ -123,12 +119,12 @@
color = Color(150, 232, 150),
size = IntSize(16, 16),
onClick = {
- AppManager.focusedWindow?.maximize()
+ windowState.placement = WindowPlacement.Maximized
}
)
Spacer(modifier = Modifier.width(3.dp))
Button(
- onClick = { AppManager.exit() },
+ onClick = AppState::closeMainWindow,
color = Color(232, 100, 100),
size = IntSize(16, 16)
)
@@ -142,28 +138,7 @@
Spacer(modifier = Modifier.height(30.dp))
Button(
text = "New window...",
- onClick = {
- AppWindow(
- title = "Second window",
- size = IntSize(400, 200),
- undecorated = AppState.undecorated.value,
- onDismissRequest = {
- println("Second window is dismissed.")
- }
- ).show {
- WindowContent(
- amount = AppState.amount,
- onClose = {
- AppManager.focusedWindow?.close()
- }
- )
- DisposableEffect(Unit) {
- onDispose {
- println("Dispose composition")
- }
- }
- }
- },
+ onClick = AppState::openSecondaryWindow,
color = Color(26, 198, 188)
)
Spacer(modifier = Modifier.height(30.dp))
@@ -171,12 +146,16 @@
text = "Send notification",
onClick = {
val message = "There should be your message."
- if (AppState.notify.value) {
- Notifier().notify("Notification.", message)
- } else if (AppState.warn.value) {
- Notifier().warn("Warning.", message)
- } else {
- Notifier().error("Error.", message)
+ when {
+ AppState.notify.value -> trayState.sendNotification(
+ Notification("Notification.", message)
+ )
+ AppState.warn.value -> trayState.sendNotification(
+ Notification("Warning.", message, Notification.Type.Warning)
+ )
+ else -> trayState.sendNotification(
+ Notification("Error.", message, Notification.Type.Error)
+ )
}
},
color = Color(196, 136, 255)
@@ -184,7 +163,7 @@
Spacer(modifier = Modifier.height(30.dp))
Button("Increment amount", { AppState.amount.value++ }, Color(150, 232, 150))
Spacer(modifier = Modifier.height(30.dp))
- Button("Exit app", { AppManager.exit() }, Color(232, 100, 100))
+ Button("Exit app", AppState::closeAll, Color(232, 100, 100))
Spacer(modifier = Modifier.height(30.dp))
SwingActionButton("JButton", { AppState.amount.value++ })
}
@@ -246,7 +225,7 @@
) {
Row(modifier = Modifier.padding(start = 20.dp)) {
TextBox(
- text = "Size: ${AppState.wndSize.value} Location: ${AppState.wndPos.value}"
+ text = "Size: ${windowState.size} Location: ${windowState.position}"
)
}
}
@@ -293,13 +272,11 @@
}
},
shape = RoundedCornerShape(0.dp),
- backgroundColor = Color(70, 70, 70),
- modifier = Modifier.fillMaxSize(),
- properties = DialogProperties(title = "Alert Dialog")
+ backgroundColor = Color(70, 70, 70)
)
} else {
Dialog(
- onDismissRequest = dismiss
+ onCloseRequest = dismiss
) {
WindowContent(
AppState.amount,
@@ -538,10 +515,6 @@
TextBox(text = text)
}
-private fun image(url: String): java.awt.Image {
- return Toolkit.getDefaultToolkit().getImage(url)
-}
-
@Composable
fun SwingActionButton(text: String, action: (() -> Unit)? = null) {
SwingPanel(
@@ -561,3 +534,20 @@
}
)
}
+
+@Composable
+fun ApplicationScope.SecondaryWindow(onCloseRequest: () -> Unit) = Window(
+ onCloseRequest = onCloseRequest,
+ state = rememberWindowState(size = WindowSize(400.dp, 200.dp)),
+ undecorated = AppState.undecorated.value,
+) {
+ WindowContent(
+ amount = AppState.amount,
+ onClose = onCloseRequest
+ )
+ DisposableEffect(Unit) {
+ onDispose {
+ println("Dispose composition")
+ }
+ }
+}
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppState.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppState.jvm.kt
index 05900ab..5119ec7 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppState.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppState.jvm.kt
@@ -15,17 +15,42 @@
*/
package androidx.compose.desktop.examples.popupexample
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.MutableState
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.IntSize
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
-import java.lang.Exception
object AppState {
private val imageRes: String = "androidx/compose/desktop/example/tray.png"
private var icon: BufferedImage? = null
+
+ var isMainWindowOpen by mutableStateOf(true)
+ private set
+
+ val secondaryWindowIds = mutableStateListOf<Int>()
+
+ private var lastId = 0
+
+ fun openSecondaryWindow() {
+ secondaryWindowIds.add(lastId++)
+ }
+
+ fun closeMainWindow() {
+ isMainWindowOpen = false
+ }
+
+ fun closeSecondaryWindow(id: Int) {
+ secondaryWindowIds.remove(id)
+ }
+
+ fun closeAll() {
+ isMainWindowOpen = false
+ secondaryWindowIds.clear()
+ }
+
fun image(): BufferedImage {
if (icon != null) {
return icon!!
@@ -44,8 +69,6 @@
}
val wndTitle = mutableStateOf("Desktop Compose Popup")
- val wndSize = mutableStateOf(IntSize.Zero)
- val wndPos = mutableStateOf(IntOffset.Zero)
val popupState = mutableStateOf(false)
val amount = mutableStateOf(0)
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/Main.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/Main.jvm.kt
index fd8dd5c..80bcbee 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/Main.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/Main.jvm.kt
@@ -13,79 +13,57 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package androidx.compose.desktop.examples.popupexample
-import androidx.compose.desktop.AppManager
-import androidx.compose.desktop.AppWindow
-import androidx.compose.desktop.WindowEvents
import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.window.v1.Menu
-import androidx.compose.ui.window.v1.MenuBar
-import javax.swing.SwingUtilities
+import androidx.compose.runtime.key
+import androidx.compose.ui.graphics.asPainter
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Tray
+import androidx.compose.ui.window.Window
+import androidx.compose.ui.window.WindowSize
+import androidx.compose.ui.window.application
+import androidx.compose.ui.window.rememberTrayState
+import androidx.compose.ui.window.rememberWindowState
-fun main() = SwingUtilities.invokeLater {
- AppManager.apply {
- setEvents(
- onAppStart = { println("onAppStart") },
- onAppExit = { println("onAppExit") },
- onWindowsEmpty = onCloseAppEvent
- )
- setMenu(
- MenuBar(
- Menu(
- "Shared actions",
- MenuItems.Exit
- )
- )
- )
- }
+fun main() = application {
+ val windowState = rememberWindowState(
+ size = WindowSize(800.dp, 600.dp)
+ )
- AppWindow(
- title = AppState.wndTitle.value,
- events = WindowEvents(
- onOpen = { println("onOpen") },
- onClose = { println("onClose") },
- onMinimize = { println("onMinimize") },
- onMaximize = { println("onMaximize") },
- onRestore = { println("onRestore") },
- onFocusGet = { println("onFocusGet") },
- onFocusLost = { println("onFocusLost") },
- onResize = { size ->
- AppState.wndSize.value = size
- },
- onRelocate = { location ->
- AppState.wndPos.value = location
+ val trayState = rememberTrayState()
+
+ if (AppState.isMainWindowOpen) {
+ Tray(
+ state = trayState,
+ icon = AppState.image().asPainter(),
+ menu = {
+ ActionItems(trayState)
}
- ),
- size = IntSize(800, 600),
- location = IntOffset(200, 200),
- icon = AppState.image(),
- menuBar = MenuBar(
- Menu(
- "Actions",
- MenuItems.Notify,
- MenuItems.Increment,
- MenuItems.Exit
- ),
- Menu(
- "About",
- MenuItems.IsFullscreen,
- MenuItems.About,
- MenuItems.Update
- )
)
- ).show {
- CompositionLocalProvider(
- LocalTest provides 42
+
+ Window(
+ onCloseRequest = AppState::closeMainWindow,
+ title = AppState.wndTitle.value,
+ state = windowState,
+ icon = AppState.image().asPainter(),
) {
- content()
+ MainMenuBar(windowState, trayState)
+
+ CompositionLocalProvider(
+ LocalTest provides 42
+ ) {
+ Content(windowState, trayState)
+ }
}
}
-}
-val onCloseAppEvent = {
- println("App exit.")
- System.exit(0)
-}
+ for (id in AppState.secondaryWindowIds) {
+ key(id) {
+ SecondaryWindow(
+ onCloseRequest = { AppState.closeSecondaryWindow(id) }
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/MenuItems.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/MenuItems.jvm.kt
index 6c667d3..7acba63 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/MenuItems.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/MenuItems.jvm.kt
@@ -13,61 +13,71 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package androidx.compose.desktop.examples.popupexample
-import androidx.compose.desktop.AppManager
+import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.window.Notifier
-import androidx.compose.ui.window.v1.KeyStroke
-import androidx.compose.ui.window.v1.MenuItem
+import androidx.compose.ui.input.key.KeyShortcut
+import androidx.compose.ui.window.FrameWindowScope
+import androidx.compose.ui.window.MenuBar
+import androidx.compose.ui.window.MenuScope
+import androidx.compose.ui.window.Notification
+import androidx.compose.ui.window.TrayState
+import androidx.compose.ui.window.WindowPlacement
+import androidx.compose.ui.window.WindowState
@OptIn(ExperimentalComposeUiApi::class)
-object MenuItems {
- val Exit = MenuItem(
- name = "Exit",
- onClick = { AppManager.exit() },
- shortcut = KeyStroke(Key.X)
- )
-
- val Notify = MenuItem(
- name = "Send tray notification",
- onClick = {
- Notifier().notify(
- title = "New Notification from JB",
- message = "JetBrains send you a message!"
- )
- },
- shortcut = KeyStroke(Key.N)
- )
-
- val Increment = MenuItem(
- name = "Increment amount",
- onClick = { AppState.amount.value++ },
- shortcut = KeyStroke(Key.A)
- )
-
- val About = MenuItem(
- name = "About app",
- onClick = {
+@Composable
+fun FrameWindowScope.MainMenuBar(
+ windowState: WindowState,
+ trayState: TrayState
+) = MenuBar {
+ Menu("Actions") {
+ ActionItems(trayState, withShortcuts = true)
+ }
+ Menu("About") {
+ CheckboxItem(
+ "Fullscreen",
+ windowState.placement == WindowPlacement.Fullscreen,
+ shortcut = KeyShortcut(Key.F, ctrl = true)
+ ) { checked ->
+ windowState.placement = if (checked) {
+ WindowPlacement.Fullscreen
+ } else {
+ WindowPlacement.Floating
+ }
+ }
+ Item("About", shortcut = KeyShortcut(Key.I, ctrl = true)) {
println("This is PopUpExampleApp")
- },
- shortcut = KeyStroke(Key.I)
- )
+ }
+ }
+}
- val Update = MenuItem(
- name = "Check updates",
- onClick = {
- println("Application is up to date.")
- },
- shortcut = KeyStroke(Key.U)
- )
-
- val IsFullscreen = MenuItem(
- name = "Is fullscreen mode",
- onClick = {
- println("Fullscreen mode: ${AppManager.focusedWindow?.isFullscreen}")
- },
- shortcut = KeyStroke(Key.F)
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun MenuScope.ActionItems(
+ trayState: TrayState,
+ withShortcuts: Boolean = false
+) {
+ Item(
+ "Send tray notification",
+ shortcut = KeyShortcut(Key.N, ctrl = true).takeIf { withShortcuts }
+ ) {
+ trayState.sendNotification(
+ Notification("New Notification from JB", "JetBrains send you a message!")
+ )
+ }
+ Item(
+ "Increment amount",
+ shortcut = KeyShortcut(Key.A, ctrl = true).takeIf { withShortcuts }
+ ) {
+ AppState.amount.value++
+ }
+ Item(
+ "Exit",
+ shortcut = KeyShortcut(Key.Escape).takeIf { withShortcuts },
+ onClick = AppState::closeAll
)
}
\ No newline at end of file
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/swingexample/Main.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/swingexample/Main.jvm.kt
index db7fed4..f202452 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/swingexample/Main.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/swingexample/Main.jvm.kt
@@ -13,13 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package androidx.compose.desktop.examples.swingexample
-import androidx.compose.desktop.AppManager
-import androidx.compose.desktop.LocalAppWindow
-import androidx.compose.desktop.ComposePanel
-import androidx.compose.desktop.SwingPanel
-import androidx.compose.desktop.Window
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -41,9 +37,18 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.ComposePanel
+import androidx.compose.ui.awt.SwingPanel
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.ApplicationScope
+import androidx.compose.ui.window.Window
+import androidx.compose.ui.window.WindowSize
+import androidx.compose.ui.window.launchApplication
+import androidx.compose.ui.window.rememberWindowState
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.GlobalScope
import java.awt.BorderLayout
import java.awt.Color as awtColor
import java.awt.Component
@@ -62,12 +67,6 @@
val eastClicks = mutableStateOf(0)
fun main() = SwingUtilities.invokeLater {
- // explicitly clear the application events
- AppManager.setEvents(
- onAppStart = null,
- onAppExit = null,
- onWindowsEmpty = null
- )
SwingComposeWindow()
}
@@ -155,10 +154,14 @@
Button(
modifier = Modifier.height(35.dp).padding(top = 3.dp),
onClick = {
- Window(
- size = IntSize(400, 250)
- ) {
- SecondWindowContent()
+ @OptIn(DelicateCoroutinesApi::class)
+ GlobalScope.launchApplication {
+ Window(
+ onCloseRequest = ::exitApplication,
+ state = rememberWindowState(size = WindowSize(400.dp, 250.dp))
+ ) {
+ SecondWindowContent()
+ }
}
}
) {
@@ -242,8 +245,7 @@
}
@Composable
-fun SecondWindowContent() {
- val window = LocalAppWindow.current
+fun ApplicationScope.SecondWindowContent() {
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
@@ -260,7 +262,7 @@
modifier = Modifier.height(30.dp).fillMaxWidth(),
contentAlignment = Alignment.Center
) {
- Button(onClick = { window.close() }) {
+ Button(onClick = { exitApplication() }) {
Text("Close", color = Color.White)
}
}
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/vsynctest/Main.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/vsynctest/Main.jvm.kt
index 7627f72..11f1317 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/vsynctest/Main.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/vsynctest/Main.jvm.kt
@@ -15,10 +15,9 @@
*/
package androidx.compose.desktop.examples.vsynctest
-import androidx.compose.desktop.LocalAppWindow
-import androidx.compose.desktop.Window
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -30,23 +29,31 @@
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.ApplicationScope
+import androidx.compose.ui.window.Window
+import androidx.compose.ui.window.WindowSize
+import androidx.compose.ui.window.application
+import androidx.compose.ui.window.rememberWindowState
-private val frameLogCount = 1000
-private val red = Color(255, 128, 128)
-private val cyan = Color(128, 255, 255)
+private val FrameLogCount = 1000
-fun main() {
- window()
- window()
+fun main() = application {
+ AppWindow()
+ AppWindow()
}
-fun window() {
- var t1 = Long.MAX_VALUE
- val frameDeltas = ArrayList<Long>(10000)
- var heuristicExpectedFrameTime = -1L
+@Composable
+private fun ApplicationScope.AppWindow() {
+ val state = remember {
+ object {
+ var t1 = Long.MAX_VALUE
+ val frameDeltas = ArrayList<Long>(10000)
+ var heuristicExpectedFrameTime = -1L
+ }
+ }
- fun logFrame() {
+ fun logFrame() = with(state) {
val t2 = System.nanoTime()
val dt = (t2 - t1).coerceAtLeast(0)
frameDeltas.add(dt)
@@ -58,7 +65,7 @@
println("Too long frame %.2f (expected %.2f)".format(dtMillis, expectedMillis))
}
- if (frameDeltas.size % frameLogCount == 0) {
+ if (frameDeltas.size % FrameLogCount == 0) {
val fps = 1E9 / frameDeltas.average()
// it is more precise than
@@ -74,11 +81,13 @@
}
}
- Window(size = IntSize(800, 200)) {
- val window = LocalAppWindow.current
- val width = (LocalDensity.current.density * window.window.width).toInt()
+ Window(
+ onCloseRequest = ::exitApplication,
+ state = rememberWindowState(size = WindowSize(800.dp, 200.dp))
+ ) {
+ val width = (LocalDensity.current.density * window.width).toInt()
val singleFrameMillis = remember {
- 1000 / window.window.graphicsConfiguration.device.displayMode.refreshRate
+ 1000 / window.graphicsConfiguration.device.displayMode.refreshRate
}
var position1 by remember { mutableStateOf(0L) }
var position2 by remember { mutableStateOf(0L) }
@@ -102,7 +111,7 @@
drawRect(Color.Red, Offset(position2.toFloat(), 50f), Size(32f, 32f))
// test similar to https://www.vsynctester.com/
- drawRect(if (isOddFrame) red else cyan, Offset(10f, 120f), Size(50f, 50f))
+ drawRect(if (isOddFrame) Color.Red else Color.Cyan, Offset(10f, 120f), Size(50f, 50f))
isOddFrame = !isOddFrame
logFrame()
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/windowapi/Examples.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/windowapi/Examples.jvm.kt
index 5b9486d..d7624ae 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/windowapi/Examples.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/windowapi/Examples.jvm.kt
@@ -17,7 +17,6 @@
package androidx.compose.desktop.examples.windowapi
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
@@ -34,6 +33,7 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.asPainter
import androidx.compose.ui.input.key.Key
@@ -49,7 +49,6 @@
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.MenuBar
import androidx.compose.ui.window.Notification
-import androidx.compose.ui.window.OwnerWindowScope
import androidx.compose.ui.window.Tray
import androidx.compose.ui.window.TrayState
import androidx.compose.ui.window.Window
@@ -311,7 +310,7 @@
}
@Composable
-private fun OwnerWindowScope.FileDialog(
+private fun FileDialog(
onDismissRequest: (result: String?) -> Unit
) = AwtWindow(
create = {
diff --git a/compose/desktop/desktop/src/jvmMain/kotlin/androidx/compose/ui/window/WindowDraggableArea.jvm.kt b/compose/desktop/desktop/src/jvmMain/kotlin/androidx/compose/ui/window/WindowDraggableArea.jvm.kt
index d39924f..5f36b41 100644
--- a/compose/desktop/desktop/src/jvmMain/kotlin/androidx/compose/ui/window/WindowDraggableArea.jvm.kt
+++ b/compose/desktop/desktop/src/jvmMain/kotlin/androidx/compose/ui/window/WindowDraggableArea.jvm.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.AppWindow
import androidx.compose.desktop.LocalAppWindow
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.drag
@@ -38,6 +37,15 @@
*
* @param modifier The modifier to be applied to the layout.
*/
+@Deprecated(
+ "Use another variant of WindowDraggableArea for the new Composable Window API (https://github" +
+ ".com/JetBrains/compose-jb/tree/master/tutorials/Window_API_new)",
+ replaceWith = ReplaceWith(
+ "WindowDraggableArea(modifier, content)",
+ "androidx.compose.foundation.window.WindowDraggableArea"
+ )
+)
+@Suppress("DEPRECATION")
@Composable
fun WindowDraggableArea(
modifier: Modifier = Modifier,
@@ -60,7 +68,8 @@
}
}
-private class DragHandler(private val window: AppWindow) {
+@Suppress("DEPRECATION")
+private class DragHandler(private val window: androidx.compose.desktop.AppWindow) {
private var location = window.window.location.toComposeOffset()
private var pointStart = MouseInfo.getPointerInfo().location.toComposeOffset()
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 0327af7..bbae904 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -722,6 +722,9 @@
public final class MultiWidgetSelectionDelegateKt {
}
+ public final class SelectionAdjustmentKt {
+ }
+
public final class SelectionContainerKt {
method @androidx.compose.runtime.Composable public static void DisableSelection(kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index 6bd264e..ed5baae9 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -760,6 +760,9 @@
public final class MultiWidgetSelectionDelegateKt {
}
+ public final class SelectionAdjustmentKt {
+ }
+
public final class SelectionContainerKt {
method @androidx.compose.runtime.Composable public static void DisableSelection(kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 0327af7..bbae904 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -722,6 +722,9 @@
public final class MultiWidgetSelectionDelegateKt {
}
+ public final class SelectionAdjustmentKt {
+ }
+
public final class SelectionContainerKt {
method @androidx.compose.runtime.Composable public static void DisableSelection(kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegateTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegateTest.kt
index c30fba8..2fc435c 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegateTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegateTest.kt
@@ -961,7 +961,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -1000,7 +1000,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -1041,7 +1041,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -1083,7 +1083,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -1124,7 +1124,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Drag downwards, after the drag the selection should remain the same.
@@ -1132,7 +1132,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end + Offset(0f, fontSizeInPx / 4)),
selectableId = 1,
- adjustment = SelectionAdjustment.WORD,
+ adjustment = SelectionAdjustment.Word,
previousSelection = textSelectionInfo1,
isStartHandle = false
)
@@ -1179,7 +1179,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
@@ -1227,7 +1227,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
@@ -1277,7 +1277,7 @@
textLayoutResult = textLayoutResult,
selectionCoordinates = Pair(start, end),
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
@@ -1316,7 +1316,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
assertThat(textSelectionInfo).isNotNull()
@@ -1362,7 +1362,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
assertThat(textSelectionInfo).isNotNull()
@@ -1410,7 +1410,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
assertThat(textSelectionInfo).isNotNull()
@@ -1465,7 +1465,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = false
)
@@ -1526,7 +1526,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = false
)
@@ -1581,7 +1581,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = true
)
@@ -1637,7 +1637,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = true
)
@@ -1693,13 +1693,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = true
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -1739,13 +1740,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = true
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -1791,13 +1793,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = true
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -1837,13 +1840,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = true
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -1882,7 +1886,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = false
)
@@ -1938,13 +1942,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = false
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -1984,13 +1989,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = false
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -2036,13 +2042,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = false
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -2088,13 +2095,14 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
previousSelection = previousSelection,
isStartHandle = false
)
// Assert.
- assertThat(textSelectionInfo).isEqualTo(previousSelection)
+ assertThat(textSelectionInfo?.start?.offset).isEqualTo(previousSelection.start.offset)
+ assertThat(textSelectionInfo?.end?.offset).isEqualTo(previousSelection.end.offset)
}
@Test
@@ -2117,7 +2125,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
assertThat(textSelectionInfo).isNotNull()
@@ -2157,7 +2165,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
assertThat(textSelectionInfo).isNotNull()
@@ -2196,7 +2204,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
assertThat(textSelectionInfo).isNotNull()
@@ -2236,7 +2244,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
assertThat(textSelectionInfo).isNotNull()
@@ -2271,7 +2279,7 @@
selectionCoordinates = Pair(start, end),
textLayoutResult = textLayoutResult,
selectableId = 1,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
assertThat(textSelectionInfo).isNull()
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegateTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegateTest.kt
index bf21e40..c7f06af 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegateTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegateTest.kt
@@ -68,7 +68,7 @@
rawEndOffset = 2,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -94,7 +94,7 @@
rawEndOffset = 5,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -123,7 +123,7 @@
rawEndOffset = rawEndOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -152,7 +152,7 @@
rawEndOffset = rawEndOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
@@ -182,7 +182,7 @@
rawEndOffset = endOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
// Assert.
@@ -212,7 +212,7 @@
rawEndOffset = endOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
// Assert.
@@ -244,7 +244,7 @@
rawEndOffset = endOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
// Assert.
@@ -274,7 +274,7 @@
rawEndOffset = endOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
// Assert.
@@ -304,7 +304,7 @@
rawEndOffset = endOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
// Assert.
@@ -336,7 +336,7 @@
rawEndOffset = endOffset,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.CHARACTER,
+ adjustment = SelectionAdjustment.Character,
)
// Assert.
@@ -362,7 +362,7 @@
rawEndOffset = 0,
previousSelection = null,
isStartHandle = true,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
// Assert.
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
index d526a14..500a875 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
@@ -100,7 +100,7 @@
* current value from [LocalIndication] to show theme default
* @param enabled whether or not this [toggleable] will handle input events and appear
* enabled for semantics purposes
- * * @param role the type of user interface element. Accessibility services might use this
+ * @param role the type of user interface element. Accessibility services might use this
* to describe the element or do customizations
* @param onValueChange callback to be invoked when toggleable is clicked,
* therefore the change of the state in requested.
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
index 6a2e918..c4d1d5c 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
@@ -386,7 +386,7 @@
selectionRegistrar?.notifySelectionUpdateStart(
layoutCoordinates = it,
startPosition = startPoint,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
}
@@ -415,7 +415,7 @@
selectionRegistrar?.notifySelectionUpdate(
layoutCoordinates = it,
endPosition = dragBeginPosition + dragTotalDistance,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
}
}
@@ -444,7 +444,7 @@
selectionRegistrar?.notifySelectionUpdate(
layoutCoordinates = it,
endPosition = downPosition,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
return selectionRegistrar.hasSelection(state.selectableId)
}
@@ -459,7 +459,7 @@
selectionRegistrar?.notifySelectionUpdate(
layoutCoordinates = it,
endPosition = dragPosition,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
}
return true
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/StringHelpers.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/StringHelpers.kt
index e2e12a0..97df541 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/StringHelpers.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/StringHelpers.kt
@@ -25,7 +25,7 @@
internal expect fun String.findFollowingBreak(index: Int): Int
-internal fun String.findParagraphStart(startIndex: Int): Int {
+internal fun CharSequence.findParagraphStart(startIndex: Int): Int {
for (index in startIndex - 1 downTo 1) {
if (this[index - 1] == '\n') {
return index
@@ -34,7 +34,7 @@
return 0
}
-internal fun String.findParagraphEnd(startIndex: Int): Int {
+internal fun CharSequence.findParagraphEnd(startIndex: Int): Int {
for (index in startIndex + 1 until this.length) {
if (this[index] == '\n') {
return index
@@ -48,6 +48,6 @@
*
* Paragraphs are separated by Line Feed character (\n).
*/
-internal fun String.getParagraphBoundary(index: Int): TextRange {
+internal fun CharSequence.getParagraphBoundary(index: Int): TextRange {
return TextRange(findParagraphStart(index), findParagraphEnd(index))
}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegate.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegate.kt
index 073ea619..4074dab 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegate.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/MultiWidgetSelectionDelegate.kt
@@ -38,6 +38,14 @@
previousSelection: Selection?,
isStartHandle: Boolean
): Selection? {
+ require(
+ previousSelection == null || (
+ selectableId == previousSelection.start.selectableId &&
+ selectableId == previousSelection.end.selectableId
+ )
+ ) {
+ "The given previousSelection doesn't belong to this selectable."
+ }
val layoutCoordinates = getLayoutCoordinates() ?: return null
val textLayoutResult = layoutResultCallback() ?: return null
@@ -59,10 +67,11 @@
override fun getSelectAllSelection(): Selection? {
val textLayoutResult = layoutResultCallback() ?: return null
+ val newSelectionRange = TextRange(0, textLayoutResult.layoutInput.text.length)
return getAssembledSelectionInfo(
- startOffset = 0,
- endOffset = textLayoutResult.layoutInput.text.length,
+ newSelectionRange = newSelectionRange,
+ newRawSelectionRange = newSelectionRange,
handlesCrossed = false,
selectableId = selectableId,
textLayoutResult = textLayoutResult
@@ -70,7 +79,7 @@
}
override fun getHandlePosition(selection: Selection, isStartHandle: Boolean): Offset {
- // Check if the selection handles's selectable is the current selectable.
+ // Check if the selection handle's selectable is the current selectable.
if (isStartHandle && selection.start.selectableId != this.selectableId ||
!isStartHandle && selection.end.selectableId != this.selectableId
) {
@@ -126,17 +135,22 @@
previousSelection: Selection? = null,
isStartHandle: Boolean = true
): Selection? {
- val textRange = getTextSelectionRange(textLayoutResult, selectionCoordinates) ?: return null
- val adjustedTextRange = adjustSelection(
+ val newRawSelectionRange =
+ getTextSelectionRange(textLayoutResult, selectionCoordinates) ?: return null
+ val previousRawSelection = previousSelection?.let {
+ TextRange(it.start.rawOffset, it.end.rawOffset)
+ }
+
+ val adjustedTextRange = adjustment.adjust(
textLayoutResult = textLayoutResult,
- textRange = textRange,
- isStartHandle = isStartHandle,
- previousHandlesCrossed = previousSelection?.handlesCrossed ?: false,
- adjustment = adjustment
+ newRawSelectionRange = newRawSelectionRange,
+ previousRawSelectionRange = previousRawSelection,
+ previousAdjustedSelection = previousSelection?.toTextRange(),
+ isStartHandle = isStartHandle
)
return getAssembledSelectionInfo(
- startOffset = adjustedTextRange.start,
- endOffset = adjustedTextRange.end,
+ newSelectionRange = adjustedTextRange,
+ newRawSelectionRange = newRawSelectionRange,
handlesCrossed = adjustedTextRange.reversed,
selectableId = selectableId,
textLayoutResult = textLayoutResult
@@ -241,8 +255,8 @@
* [Selection] contains a lot of parameters. It looks more clean to assemble an object of this
* class in a separate method.
*
- * @param startOffset the final start offset to be returned.
- * @param endOffset the final end offset to be returned.
+ * @param newSelectionRange the final new selection text range.
+ * @param newRawSelectionRange the new unadjusted selection text range.
* @param handlesCrossed true if the selection handles are crossed
* @param selectableId the id of the current [Selectable] for which the [Selection] is being
* calculated
@@ -251,21 +265,23 @@
* @return an assembled object of [Selection] using the offered selection info.
*/
private fun getAssembledSelectionInfo(
- startOffset: Int,
- endOffset: Int,
+ newSelectionRange: TextRange,
+ newRawSelectionRange: TextRange,
handlesCrossed: Boolean,
selectableId: Long,
textLayoutResult: TextLayoutResult
): Selection {
return Selection(
start = Selection.AnchorInfo(
- direction = textLayoutResult.getBidiRunDirection(startOffset),
- offset = startOffset,
+ direction = textLayoutResult.getBidiRunDirection(newSelectionRange.start),
+ offset = newSelectionRange.start,
+ rawOffset = newRawSelectionRange.start,
selectableId = selectableId
),
end = Selection.AnchorInfo(
- direction = textLayoutResult.getBidiRunDirection(max(endOffset - 1, 0)),
- offset = endOffset,
+ direction = textLayoutResult.getBidiRunDirection(max(newSelectionRange.end - 1, 0)),
+ offset = newSelectionRange.end,
+ rawOffset = newRawSelectionRange.end,
selectableId = selectableId
),
handlesCrossed = handlesCrossed
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selectable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selectable.kt
index ebad9c2..6e4da19 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selectable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selectable.kt
@@ -44,9 +44,12 @@
* @param endPosition graphical position of the end of the selection
* @param containerLayoutCoordinates [LayoutCoordinates] of the widget
* @param adjustment [Selection] range is adjusted according to this param
- * @param previousSelection previous selection result
- * @param isStartHandle true if the start handle is being dragged
+ * @param previousSelection previous selection result on this [Selectable]
*
+ * @throws IllegalStateException when the given [previousSelection] doesn't belong to this
+ * selectable. In other words, one of the [Selection.AnchorInfo] in the given
+ * [previousSelection] has a selectableId that doesn't match to the [selectableId] of this
+ * selectable.
* @return null if no selection will be applied for this composable, or [Selection] instance
* if selection is applied to this composable.
*/
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selection.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selection.kt
index 4ec4b4c..3a0f40c 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selection.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/Selection.kt
@@ -62,6 +62,14 @@
val offset: Int,
/**
+ * Character offset for the selection edge. This offset is computed based on the user
+ * input and might be adjusted to compute the final offset. This information is needed
+ * for [SelectionAdjustment].
+ * @see [SelectionAdjustment]
+ */
+ val rawOffset: Int = offset,
+
+ /**
* The id of the [Selectable] which contains this [Selection] Anchor.
*/
val selectableId: Long
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionAdjustment.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionAdjustment.kt
new file mode 100644
index 0000000..1d82a1c
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionAdjustment.kt
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text.selection
+
+import androidx.compose.foundation.text.getParagraphBoundary
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextRange
+
+/**
+ * Selection can be adjusted depends on context. For example, in touch mode dragging after a long
+ * press adjusts selection by word. But selection by dragging handles is character precise
+ * without adjustments. With a mouse, double-click selects by words and triple-clicks by paragraph.
+ * @see [SelectionRegistrar.notifySelectionUpdate]
+ */
+internal interface SelectionAdjustment {
+
+ /**
+ * The callback function that is called once a new selection arrives, the return value of
+ * this function will be the final selection range on the corresponding [Selectable].
+ *
+ * @param textLayoutResult the [TextLayoutResult] of the involved [Selectable].
+ * @param newRawSelectionRange the new selection range computed from the selection handle
+ * position on screen.
+ * @param previousRawSelectionRange the previous raw selection range.
+ * @param previousAdjustedSelection the previous adjusted selection range, or the selection
+ * range to be updated.
+ */
+ fun adjust(
+ textLayoutResult: TextLayoutResult,
+ newRawSelectionRange: TextRange,
+ previousRawSelectionRange: TextRange?,
+ previousAdjustedSelection: TextRange?,
+ isStartHandle: Boolean
+ ): TextRange
+
+ companion object {
+ /**
+ * The selection adjustment that does nothing and directly return the input raw
+ * selection range.
+ */
+ val None = object : SelectionAdjustment {
+ override fun adjust(
+ textLayoutResult: TextLayoutResult,
+ newRawSelectionRange: TextRange,
+ previousRawSelectionRange: TextRange?,
+ previousAdjustedSelection: TextRange?,
+ isStartHandle: Boolean
+ ): TextRange = newRawSelectionRange
+ }
+
+ /**
+ * The character based selection. It normally won't change the raw selection range except
+ * when the input raw selection range is collapsed. In this case, it will always make
+ * sure at least one character is selected.
+ * When the given raw selection range is collapsed:
+ * a) it will always try to adjust the changing selection boundary(base on the value of
+ * isStartHandle) and makes sure the other boundary remains the same after the adjustment
+ * b) if the previous selection range is reversed, it will try to make the adjusted
+ * selection range reversed as well, and vice versa.
+ */
+ val Character = object : SelectionAdjustment {
+ override fun adjust(
+ textLayoutResult: TextLayoutResult,
+ newRawSelectionRange: TextRange,
+ previousRawSelectionRange: TextRange?,
+ previousAdjustedSelection: TextRange?,
+ isStartHandle: Boolean
+ ): TextRange {
+ return if (newRawSelectionRange.collapsed) {
+ // If there isn't any selection before, we assume handles are not crossed.
+ val previousHandlesCrossed = previousAdjustedSelection?.reversed ?: false
+ ensureAtLeastOneChar(
+ offset = newRawSelectionRange.start,
+ lastOffset = textLayoutResult.layoutInput.text.lastIndex,
+ isStartHandle = isStartHandle,
+ previousHandlesCrossed = previousHandlesCrossed
+ )
+ } else {
+ newRawSelectionRange
+ }
+ }
+ }
+
+ /**
+ * The word based selection adjustment. It will adjust the raw input selection such that
+ * the selection boundary snap to the word boundary. It will always expand the raw input
+ * selection range to the closest word boundary. If the raw selection is reversed, it
+ * will always return a reversed selection, and vice versa.
+ */
+ val Word = object : SelectionAdjustment {
+ override fun adjust(
+ textLayoutResult: TextLayoutResult,
+ newRawSelectionRange: TextRange,
+ previousRawSelectionRange: TextRange?,
+ previousAdjustedSelection: TextRange?,
+ isStartHandle: Boolean
+ ): TextRange {
+ return adjustByBoundary(
+ textLayoutResult = textLayoutResult,
+ newRawSelection = newRawSelectionRange,
+ boundaryFun = textLayoutResult::getWordBoundary
+ )
+ }
+ }
+
+ /**
+ * The paragraph based selection adjustment. It will adjust the raw input selection such
+ * that the selection boundary snap to the paragraph boundary. It will always expand the
+ * raw input selection range to the closest paragraph boundary. If the raw selection is
+ * reversed, it will always return a reversed selection, and vice versa.
+ */
+ val Paragraph = object : SelectionAdjustment {
+ override fun adjust(
+ textLayoutResult: TextLayoutResult,
+ newRawSelectionRange: TextRange,
+ previousRawSelectionRange: TextRange?,
+ previousAdjustedSelection: TextRange?,
+ isStartHandle: Boolean
+ ): TextRange {
+ val boundaryFun = textLayoutResult.layoutInput.text::getParagraphBoundary
+ return adjustByBoundary(
+ textLayoutResult = textLayoutResult,
+ newRawSelection = newRawSelectionRange,
+ boundaryFun = boundaryFun
+ )
+ }
+ }
+
+ private fun adjustByBoundary(
+ textLayoutResult: TextLayoutResult,
+ newRawSelection: TextRange,
+ boundaryFun: (Int) -> TextRange
+ ): TextRange {
+ if (textLayoutResult.layoutInput.text.isEmpty()) {
+ return TextRange.Zero
+ }
+ val maxOffset = textLayoutResult.layoutInput.text.lastIndex
+ val startBoundary = boundaryFun(newRawSelection.start.coerceIn(0, maxOffset))
+ val endBoundary = boundaryFun(newRawSelection.end.coerceIn(0, maxOffset))
+
+ // If handles are not crossed, start should be snapped to the start of the word
+ // containing the start offset, and end should be snapped to the end of the word
+ // containing the end offset. If handles are crossed, start should be snapped to the
+ // end of the word containing the start offset, and end should be snapped to the start
+ // of the word containing the end offset.
+ val start = if (newRawSelection.reversed) startBoundary.end else startBoundary.start
+ val end = if (newRawSelection.reversed) endBoundary.start else endBoundary.end
+ return TextRange(start, end)
+ }
+
+ /**
+ * A special version of character based selection that accelerates the selection update
+ * with word based selection. In short, it expands by word and shrinks by character.
+ * Here is more details of the behavior:
+ * 1. When previous selection is null, it will use word based selection.
+ * 2. When the start/end offset has moved to a different line, it will use word
+ * based selection.
+ * 3. When the selection is shrinking, it behave same as the character based selection.
+ * Shrinking means that the start/end offset is moving in the direction that makes
+ * selected text shorter.
+ * 4. The selection boundary is expanding,
+ * a.if the previous start/end offset is not a word boundary, use character based
+ * selection.
+ * b.if the previous start/end offset is a word boundary, use word based selection.
+ *
+ * Notice that this selection adjustment assumes that when isStartHandle is ture, only
+ * start handle is moving(or unchanged), and vice versa.
+ */
+ val CharacterWithWordAccelerate = object : SelectionAdjustment {
+ override fun adjust(
+ textLayoutResult: TextLayoutResult,
+ newRawSelectionRange: TextRange,
+ previousRawSelectionRange: TextRange?,
+ previousAdjustedSelection: TextRange?,
+ isStartHandle: Boolean
+ ): TextRange {
+ // Previous selection is null. We start a word based selection.
+ if (
+ previousRawSelectionRange == null ||
+ previousAdjustedSelection == null
+ ) {
+ return Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = newRawSelectionRange,
+ previousRawSelectionRange = previousRawSelectionRange,
+ previousAdjustedSelection = previousAdjustedSelection,
+ isStartHandle = isStartHandle
+ )
+ }
+
+ // The new selection is collapsed, ensure at least one char is selected.
+ if (newRawSelectionRange.collapsed) {
+ return ensureAtLeastOneChar(
+ offset = newRawSelectionRange.start,
+ lastOffset = textLayoutResult.layoutInput.text.lastIndex,
+ isStartHandle = isStartHandle,
+ previousHandlesCrossed = previousAdjustedSelection.reversed
+ )
+ }
+
+ // Notice that we assume only one selection boundary is really updated. So we can
+ // directly pass previousAdjustedSelection.end as otherBoundOffset.
+ val start = updateSelectionBoundary(
+ textLayoutResult,
+ newRawSelectionRange.start,
+ previousRawSelectionRange.start,
+ previousAdjustedSelection.start,
+ previousAdjustedSelection.end,
+ true,
+ previousRawSelectionRange.reversed
+ )
+ val end = updateSelectionBoundary(
+ textLayoutResult,
+ newRawSelectionRange.end,
+ previousRawSelectionRange.end,
+ previousAdjustedSelection.end,
+ previousAdjustedSelection.start,
+ false,
+ previousRawSelectionRange.reversed
+ )
+ return TextRange(start, end)
+ }
+
+ /**
+ * Helper function that updates start or end offset of the selection. It implements the
+ * "expand by word and shrink by character behavior".
+ *
+ * @param textLayoutResult the text layout result
+ * @param newRawOffset the new raw offset of the selection boundary.
+ * @param previousRawOffset the previous raw offset of the selection boundary.
+ * @param previousAdjustedOffset the previous final/adjusted offset. It's the current
+ * @param otherBoundaryOffset the offset of the other selection boundary. It is used
+ * to avoid empty selection in word based selection mode.
+ * selection boundary.
+ * @param isStart whether it's updating the selection start or end boundary.
+ * @param isReversed whether the selection is reversed or not. We use
+ * this information to determine if the selection is expanding or shrinking.
+ */
+ private fun updateSelectionBoundary(
+ textLayoutResult: TextLayoutResult,
+ newRawOffset: Int,
+ previousRawOffset: Int,
+ previousAdjustedOffset: Int,
+ otherBoundaryOffset: Int,
+ isStart: Boolean,
+ isReversed: Boolean
+ ): Int {
+ // The raw offset didn't change, directly return the previous adjusted start offset.
+ if (newRawOffset == previousRawOffset) {
+ return previousAdjustedOffset
+ }
+
+ val currentLine = textLayoutResult.getLineForOffset(newRawOffset)
+ val previousLine = textLayoutResult.getLineForOffset(previousAdjustedOffset)
+
+ // The updating selection boundary has crossed a line, use word based selection.
+ if (currentLine != previousLine) {
+ return snapToWordBoundary(
+ textLayoutResult = textLayoutResult,
+ newRawOffset = newRawOffset,
+ currentLine = currentLine,
+ otherBoundaryOffset = otherBoundaryOffset,
+ isStart = isStart,
+ isReversed = isReversed
+ )
+ }
+
+ // Check if the start or end selection boundary is expanding. If it's shrinking,
+ // use character based selection.
+ val isExpanding =
+ isExpanding(newRawOffset, previousRawOffset, isStart, isReversed)
+ if (!isExpanding) {
+ return newRawOffset
+ }
+
+ // If the previous start/end offset is not at a word boundary, which is indicating
+ // that start/end offset is updating within a word. In this case, it still uses
+ // character based selection.
+ if (!textLayoutResult.isAtWordBoundary(previousAdjustedOffset)) {
+ return newRawOffset
+ }
+
+ // At this point we know, the updating start/end offset is still in the same line,
+ // it's expanding the selection, and it's not updating within a word. It should
+ // use word based selection.
+ return snapToWordBoundary(
+ textLayoutResult = textLayoutResult,
+ newRawOffset = newRawOffset,
+ currentLine = currentLine,
+ otherBoundaryOffset = otherBoundaryOffset,
+ isStart = isStart,
+ isReversed = isReversed
+ )
+ }
+
+ private fun snapToWordBoundary(
+ textLayoutResult: TextLayoutResult,
+ newRawOffset: Int,
+ currentLine: Int,
+ otherBoundaryOffset: Int,
+ isStart: Boolean,
+ isReversed: Boolean
+ ): Int {
+ val wordBoundary = textLayoutResult.getWordBoundary(newRawOffset)
+
+ // In the case where the target word crosses multiple lines due to hyphenation or
+ // being too long, we use the line start/end to keep the adjusted offset at the
+ // same line.
+ val wordStartLine = textLayoutResult.getLineForOffset(wordBoundary.start)
+ val start = if (wordStartLine == currentLine) {
+ wordBoundary.start
+ } else {
+ textLayoutResult.getLineStart(currentLine)
+ }
+
+ val wordEndLine = textLayoutResult.getLineForOffset(wordBoundary.end)
+ val end = if (wordEndLine == currentLine) {
+ wordBoundary.end
+ } else {
+ textLayoutResult.getLineEnd(currentLine)
+ }
+
+ // If one of the word boundary is exactly same as the otherBoundaryOffset, we
+ // can't snap to this word boundary since it will result in an empty selection
+ // range.
+ if (start == otherBoundaryOffset) {
+ return end
+ }
+ if (end == otherBoundaryOffset) {
+ return start
+ }
+
+ val threshold = (start + end) / 2
+ return if (isStart xor isReversed) {
+ // In this branch when:
+ // 1. selection is updating the start offset, and selection is not reversed.
+ // 2. selection is updating the end offset, and selection is reversed.
+ if (newRawOffset <= threshold) {
+ start
+ } else {
+ end
+ }
+ } else {
+ // In this branch when:
+ // 1. selection is updating the end offset, and selection is not reversed.
+ // 2. selection is updating the start offset, and selection is reversed.
+ if (newRawOffset >= threshold) {
+ end
+ } else {
+ start
+ }
+ }
+ }
+
+ private fun TextLayoutResult.isAtWordBoundary(offset: Int): Boolean {
+ val wordBoundary = getWordBoundary(offset)
+ return offset == wordBoundary.start || offset == wordBoundary.end
+ }
+
+ private fun isExpanding(
+ newRawOffset: Int,
+ previousRawOffset: Int,
+ isStart: Boolean,
+ previousReversed: Boolean
+ ): Boolean {
+ if (newRawOffset == previousRawOffset) {
+ return false
+ }
+ return if (isStart xor previousReversed) {
+ newRawOffset < previousRawOffset
+ } else {
+ newRawOffset > previousRawOffset
+ }
+ }
+ }
+ }
+}
+
+/**
+ * This method adjusts the raw start and end offset and bounds the selection to one character. The
+ * logic of bounding evaluates the last selection result, which handle is being dragged, and if
+ * selection reaches the boundary.
+ *
+ * @param offset unprocessed start and end offset calculated directly from input position, in
+ * this case start and offset equals to each other.
+ * @param lastOffset last offset of the text. It's actually the length of the text.
+ * @param isStartHandle true if the start handle is being dragged
+ * @param previousHandlesCrossed true if the selection handles are crossed in the previous
+ * selection. This function will try to maintain the handle cross state. This can help make
+ * selection stable.
+ *
+ * @return the adjusted [TextRange].
+ */
+internal fun ensureAtLeastOneChar(
+ offset: Int,
+ lastOffset: Int,
+ isStartHandle: Boolean,
+ previousHandlesCrossed: Boolean
+): TextRange {
+ // When lastOffset is 0, it can only return an empty TextRange.
+ // When previousSelection is null, it won't start a selection and return an empty TextRange.
+ if (lastOffset == 0) return TextRange(offset, offset)
+
+ // When offset is at the boundary, the handle that is not dragged should be at [offset]. Here
+ // the other handle's position is computed accordingly.
+ if (offset == 0) {
+ return if (isStartHandle) {
+ TextRange(1, 0)
+ } else {
+ TextRange(0, 1)
+ }
+ }
+
+ if (offset == lastOffset) {
+ return if (isStartHandle) {
+ TextRange(lastOffset - 1, lastOffset)
+ } else {
+ TextRange(lastOffset, lastOffset - 1)
+ }
+ }
+
+ // In other cases, this function will try to maintain the current cross handle states.
+ // Only in this way the selection can be stable.
+ return if (isStartHandle) {
+ if (!previousHandlesCrossed) {
+ // Handle is NOT crossed, and the start handle is dragged.
+ TextRange(offset - 1, offset)
+ } else {
+ // Handle is crossed, and the start handle is dragged.
+ TextRange(offset + 1, offset)
+ }
+ } else {
+ if (!previousHandlesCrossed) {
+ // Handle is NOT crossed, and the end handle is dragged.
+ TextRange(offset, offset + 1)
+ } else {
+ // Handle is crossed, and the end handle is dragged.
+ TextRange(offset, offset - 1)
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
index e669132..dd8f4ec 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
@@ -242,6 +242,7 @@
selectionRegistrar.onSelectionUpdateEndCallback = {
showSelectionToolbar()
+ finishSelectionUpdate()
}
selectionRegistrar.onSelectableChangeCallback = { selectableKey ->
@@ -353,27 +354,27 @@
internal fun mergeSelections(
startPosition: Offset,
endPosition: Offset,
- adjustment: SelectionAdjustment = SelectionAdjustment.NONE,
+ adjustment: SelectionAdjustment = SelectionAdjustment.None,
previousSelection: Selection? = null,
isStartHandle: Boolean = true
): Pair<Selection?, Map<Long, Selection>> {
val subselections = mutableMapOf<Long, Selection>()
val newSelection = selectionRegistrar.sort(requireContainerCoordinates())
.fastFold(null) { mergedSelection: Selection?, selectable: Selectable ->
+ val subselection =
+ selectionRegistrar.subselections[selectable.selectableId]
val selection = selectable.getSelection(
startPosition = startPosition,
endPosition = endPosition,
containerLayoutCoordinates = requireContainerCoordinates(),
- previousSelection = previousSelection,
+ adjustment = adjustment,
+ previousSelection = subselection,
isStartHandle = isStartHandle,
- adjustment = adjustment
)
selection?.let { subselections[selectable.selectableId] = it }
merge(mergedSelection, selection)
}
- if (previousSelection != newSelection) hapticFeedBack?.performHapticFeedback(
- HapticFeedbackType.TextHandleMove
- )
+ performHapticFeedbackIfNeeded(newSelection, previousSelection, hapticFeedBack)
return Pair(newSelection, subselections)
}
@@ -389,9 +390,7 @@
selection?.let { subselections[selectable.selectableId] = it }
merge(mergedSelection, selection)
}
- if (previousSelection != newSelection) hapticFeedBack?.performHapticFeedback(
- HapticFeedbackType.TextHandleMove
- )
+ performHapticFeedbackIfNeeded(previousSelection, newSelection, hapticFeedBack)
return Pair(newSelection, subselections)
}
@@ -617,13 +616,14 @@
startPosition = currentStart,
endPosition = currentEnd,
isStartHandle = isStartHandle,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.CharacterWithWordAccelerate
)
return
}
override fun onStop() {
showSelectionToolbar()
+ finishSelectionUpdate()
}
override fun onCancel() {
@@ -663,7 +663,7 @@
private fun updateSelection(
startPosition: Offset?,
endPosition: Offset?,
- adjustment: SelectionAdjustment = SelectionAdjustment.NONE,
+ adjustment: SelectionAdjustment = SelectionAdjustment.None,
isStartHandle: Boolean = true
) {
if (startPosition == null || endPosition == null) return
@@ -671,14 +671,25 @@
startPosition = startPosition,
endPosition = endPosition,
adjustment = adjustment,
- isStartHandle = isStartHandle,
previousSelection = selection,
+ isStartHandle = isStartHandle
)
if (newSelection != selection) {
selectionRegistrar.subselections = newSubselection
onSelectionChange(newSelection)
}
}
+
+ private fun finishSelectionUpdate() {
+ selection?.let {
+ val newSelection = Selection(
+ start = it.start.copy(rawOffset = it.start.offset),
+ end = it.end.copy(rawOffset = it.end.offset),
+ handlesCrossed = it.handlesCrossed
+ )
+ onSelectionChange(newSelection)
+ }
+ }
}
internal fun merge(lhs: Selection?, rhs: Selection?): Selection? {
@@ -744,3 +755,33 @@
internal fun Rect.containsInclusive(offset: Offset): Boolean =
offset.x in left..right && offset.y in top..bottom
+
+private fun performHapticFeedbackIfNeeded(
+ previousSelection: Selection?,
+ newSelection: Selection?,
+ hapticFeedback: HapticFeedback?,
+) {
+ if (hapticFeedback == null) {
+ return
+ }
+ if (previousSelection == null) {
+ if (newSelection != null) {
+ hapticFeedback.performHapticFeedback(HapticFeedbackType.TextHandleMove)
+ }
+ return
+ }
+ if (newSelection == null) {
+ // We know previousSelection is not null, so selection is updated.
+ hapticFeedback.performHapticFeedback(HapticFeedbackType.TextHandleMove)
+ return
+ }
+ // We don't care if rawOffset of Selection.AnchorInfo is different, so we only compare the
+ // other fields. If any of them changes, we need to perform hapticFeedback.
+ if (previousSelection.start.offset != newSelection.start.offset ||
+ previousSelection.start.selectableId != newSelection.start.selectableId ||
+ previousSelection.end.offset != newSelection.end.offset ||
+ previousSelection.end.selectableId != previousSelection.end.selectableId
+ ) {
+ hapticFeedback.performHapticFeedback(HapticFeedbackType.TextHandleMove)
+ }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionRegistrar.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionRegistrar.kt
index 554371a..ae3b611 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionRegistrar.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionRegistrar.kt
@@ -22,19 +22,6 @@
import androidx.compose.ui.layout.LayoutCoordinates
/**
- * Selection can be adjusted depends on context. For example, in touch mode dragging after a long
- * press adjusts selection by word. But selection by dragging handles is character precise
- * without adjustments. With a mouse, double-click selects by words and triple-clicks by paragraph.
- * @see [SelectionRegistrar.notifySelectionUpdate]
- */
-
-internal enum class SelectionAdjustment {
- NONE,
- CHARACTER,
- WORD,
- PARAGRAPH
-}
-/**
* An interface allowing a composable to subscribe and unsubscribe to selection changes.
*/
internal interface SelectionRegistrar {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegate.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegate.kt
index a83cbcc..a13efae 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegate.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionDelegate.kt
@@ -43,17 +43,17 @@
val textRange = TextRange(rawStartOffset, rawEndOffset)
// When the previous selection is null, it's allowed to have collapsed selection.
- // So we can ignore the SelectionAdjustment.CHARACTER.
- if (previousSelection == null && adjustment == SelectionAdjustment.CHARACTER) {
+ // So we can ignore the SelectionAdjustment.Character.
+ if (previousSelection == null && adjustment == SelectionAdjustment.Character) {
return textRange
}
- return adjustSelection(
+ return adjustment.adjust(
textLayoutResult = textLayoutResult,
- textRange = textRange,
- isStartHandle = isStartHandle,
- previousHandlesCrossed = previousSelection?.reversed ?: false,
- adjustment = adjustment
+ newRawSelectionRange = textRange,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
)
}
return TextRange(0, 0)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
index 6a7e10f..43d1029 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
@@ -176,7 +176,7 @@
transformedStartOffset = offset,
transformedEndOffset = offset,
isStartHandle = false,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
dragBeginOffsetInText = offset
}
@@ -203,7 +203,7 @@
transformedStartOffset = startOffset,
transformedEndOffset = endOffset,
isStartHandle = false,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
}
state?.showFloatingToolbar = false
@@ -228,7 +228,7 @@
transformedStartOffset = startOffset,
transformedEndOffset = clickOffset,
isStartHandle = false,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
return true
}
@@ -251,7 +251,7 @@
transformedStartOffset = startOffset,
transformedEndOffset = dragOffset,
isStartHandle = false,
- adjustment = SelectionAdjustment.NONE
+ adjustment = SelectionAdjustment.None
)
return true
}
@@ -338,7 +338,7 @@
transformedStartOffset = startOffset,
transformedEndOffset = endOffset,
isStartHandle = isStartHandle,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
}
state?.showFloatingToolbar = false
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionDelegate.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionDelegate.kt
index 63aaf64..e7f6517 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionDelegate.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionDelegate.kt
@@ -102,11 +102,11 @@
adjustment: SelectionAdjustment
): TextRange {
val textLength = textLayoutResult.layoutInput.text.text.length
- if (adjustment == SelectionAdjustment.NONE || textLength == 0) {
+ if (adjustment == SelectionAdjustment.None || textLength == 0) {
return textRange
}
- if (adjustment == SelectionAdjustment.CHARACTER) {
+ if (adjustment == SelectionAdjustment.Character) {
return if (!textRange.collapsed) {
textRange
} else {
@@ -119,7 +119,7 @@
}
}
- val boundaryFun = if (adjustment == SelectionAdjustment.WORD) {
+ val boundaryFun = if (adjustment == SelectionAdjustment.Word) {
textLayoutResult::getWordBoundary
} else {
textLayoutResult.layoutInput.text.text::getParagraphBoundary
@@ -140,70 +140,6 @@
}
/**
- * This method adjusts the raw start and end offset and bounds the selection to one character. The
- * logic of bounding evaluates the last selection result, which handle is being dragged, and if
- * selection reaches the boundary.
- *
- * @param offset unprocessed start and end offset calculated directly from input position, in
- * this case start and offset equals to each other.
- * @param lastOffset last offset of the text. It's actually the length of the text.
- * @param isStartHandle true if the start handle is being dragged
- * @param previousHandlesCrossed true if the selection handles are crossed in the previous
- * selection. This function will try to maintain the handle cross state. This can help make
- * selection stable.
- *
- * @return the adjusted [TextRange].
- */
-private fun ensureAtLeastOneChar(
- offset: Int,
- lastOffset: Int,
- isStartHandle: Boolean,
- previousHandlesCrossed: Boolean
-): TextRange {
- // When lastOffset is 0, it can only return an empty TextRange.
- // When previousSelection is null, it won't start a selection and return an empty TextRange.
- if (lastOffset == 0) return TextRange(offset, offset)
-
- // When offset is at the boundary, the handle that is not dragged should be at [offset]. Here
- // the other handle's position is computed accordingly.
- if (offset == 0) {
- return if (isStartHandle) {
- TextRange(1, 0)
- } else {
- TextRange(0, 1)
- }
- }
-
- if (offset == lastOffset) {
- return if (isStartHandle) {
- TextRange(lastOffset - 1, lastOffset)
- } else {
- TextRange(lastOffset, lastOffset - 1)
- }
- }
-
- // In other cases, this function will try to maintain the current cross handle states.
- // Only in this way the selection can be stable.
- return if (isStartHandle) {
- if (!previousHandlesCrossed) {
- // Handle is NOT crossed, and the start handle is dragged.
- TextRange(offset - 1, offset)
- } else {
- // Handle is crossed, and the start handle is dragged.
- TextRange(offset + 1, offset)
- }
- } else {
- if (!previousHandlesCrossed) {
- // Handle is NOT crossed, and the end handle is dragged.
- TextRange(offset, offset + 1)
- } else {
- // Handle is crossed, and the end handle is dragged.
- TextRange(offset, offset - 1)
- }
- }
-}
-
-/**
* This method returns the graphical position where the selection handle should be based on the
* offset and other information.
*
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionMouseDetector.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionMouseDetector.kt
index 91dc7f6..2f860e1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionMouseDetector.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextSelectionMouseDetector.kt
@@ -103,9 +103,9 @@
}
} else {
val selectionMode = when (clicksCounter.clicks) {
- 1 -> SelectionAdjustment.NONE
- 2 -> SelectionAdjustment.WORD
- else -> SelectionAdjustment.PARAGRAPH
+ 1 -> SelectionAdjustment.None
+ 2 -> SelectionAdjustment.Word
+ else -> SelectionAdjustment.Paragraph
}
val started = observer.onStart(downChange.position, selectionMode)
if (started) {
diff --git a/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt b/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
index c2b4e1e..a4577bf 100644
--- a/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
+++ b/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
@@ -123,13 +123,13 @@
@Test
fun TextFieldSelectionManager_mouseSelectionObserver_onStart() {
- manager.mouseSelectionObserver.onStart(dragBeginPosition, SelectionAdjustment.NONE)
+ manager.mouseSelectionObserver.onStart(dragBeginPosition, SelectionAdjustment.None)
assertThat(value.selection).isEqualTo(TextRange(0, 0))
manager.mouseSelectionObserver.onStart(
dragBeginPosition + dragDistance,
- SelectionAdjustment.NONE
+ SelectionAdjustment.None
)
assertThat(value.selection).isEqualTo(TextRange(8, 8))
}
@@ -147,8 +147,8 @@
@Test
fun TextFieldSelectionManager_mouseSelectionObserver_onDrag() {
val observer = manager.mouseSelectionObserver
- observer.onStart(dragBeginPosition, SelectionAdjustment.NONE)
- observer.onDrag(dragDistance, SelectionAdjustment.NONE)
+ observer.onStart(dragBeginPosition, SelectionAdjustment.None)
+ observer.onDrag(dragDistance, SelectionAdjustment.None)
assertThat(value.selection).isEqualTo(TextRange(0, 8))
}
@@ -156,8 +156,8 @@
@Test
fun TextFieldSelectionManager_mouseSelectionObserver_copy() {
val observer = manager.mouseSelectionObserver
- observer.onStart(dragBeginPosition, SelectionAdjustment.NONE)
- observer.onDrag(dragDistance, SelectionAdjustment.NONE)
+ observer.onStart(dragBeginPosition, SelectionAdjustment.None)
+ observer.onDrag(dragDistance, SelectionAdjustment.None)
manager.value = value
manager.copy(cancelSelection = false)
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextSelectionLongPressDragTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextSelectionLongPressDragTest.kt
index dae3c2e..1b046c1 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextSelectionLongPressDragTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextSelectionLongPressDragTest.kt
@@ -56,11 +56,13 @@
start = Selection.AnchorInfo(
direction = ResolvedTextDirection.Ltr,
offset = 0,
+ rawOffset = 0,
selectableId = selectableId
),
end = Selection.AnchorInfo(
direction = ResolvedTextDirection.Ltr,
offset = 5,
+ rawOffset = 5,
selectableId = selectableId
)
)
@@ -112,7 +114,7 @@
verify(selectionRegistrar, times(1)).notifySelectionUpdateStart(
layoutCoordinates = layoutCoordinates,
startPosition = position,
- adjustment = SelectionAdjustment.WORD
+ adjustment = SelectionAdjustment.Word
)
}
@@ -161,7 +163,7 @@
.notifySelectionUpdate(
layoutCoordinates = layoutCoordinates,
endPosition = beginPosition2 + dragDistance2,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
}
@@ -181,7 +183,7 @@
.notifySelectionUpdate(
layoutCoordinates = layoutCoordinates,
endPosition = beginPosition + dragDistance,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
}
@@ -201,7 +203,7 @@
.notifySelectionUpdate(
layoutCoordinates = layoutCoordinates,
endPosition = beginPosition + dragDistance,
- adjustment = SelectionAdjustment.CHARACTER
+ adjustment = SelectionAdjustment.Character
)
}
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionAdjustmentTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionAdjustmentTest.kt
new file mode 100644
index 0000000..7d158af
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionAdjustmentTest.kt
@@ -0,0 +1,1434 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text.selection
+
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.MultiParagraph
+import androidx.compose.ui.text.TextLayoutInput
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.util.packInts
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
+import com.nhaarman.mockitokotlin2.mock
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class SelectionAdjustmentTest {
+ @Test
+ fun adjustment_None_noAdjustment() {
+ val textLayoutResult = mockTextLayoutResult(text = "hello world")
+ val rawSelection = TextRange(0, 5)
+ val adjustedSelection = SelectionAdjustment.None.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = true
+ )
+
+ assertThat(adjustedSelection).isEqualTo(rawSelection)
+ }
+
+ @Test
+ fun adjustment_Character_notCollapsed_noAdjustment() {
+ val textLayoutResult = mockTextLayoutResult(text = "hello world")
+ val rawSelection = TextRange(0, 3)
+ val adjustedSelection = SelectionAdjustment.Character.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = true
+ )
+
+ assertThat(adjustedSelection).isEqualTo(rawSelection)
+ }
+
+ @Test
+ fun adjustment_Character_collapsedNotReversed_returnOneCharSelectionNotReversed() {
+ val textLayoutResult = mockTextLayoutResult(text = "hello")
+ // The end offset is moving towards the start offset, which makes the new raw text range
+ // collapsed.
+ // After the adjustment, at least one character should be selected.
+ // Since the previousTextRange is not reversed, the adjusted TextRange should
+ // also be not reversed.
+ // Based the above rules, adjusted text range should be [1, 2)
+ val rawSelection = TextRange(1, 1)
+ val previousSelection = TextRange(1, 2)
+ val isStartHandle = false
+
+ val adjustedSelection = SelectionAdjustment.Character.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedSelection).isEqualTo(TextRange(1, 2))
+ }
+
+ @Test
+ fun adjustment_Character_collapsedReversed_returnOneCharSelectionReversed() {
+ val textLayoutResult = mockTextLayoutResult(text = "hello")
+ val rawSelection = TextRange(2, 2)
+ val previousTextRange = TextRange(2, 1)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Character.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousTextRange,
+ previousAdjustedSelection = previousTextRange,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(2, 1))
+ }
+
+ @Test
+ fun adjustment_Word_collapsed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world",
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ val rawSelection = TextRange(1, 1)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun adjustment_Word_collapsed_onStartBoundary() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world",
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ val rawSelection = TextRange(6, 6)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 11))
+ }
+
+ @Test
+ fun adjustment_Word_collapsed_onEndBoundary() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world",
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ val rawSelection = TextRange(5, 5)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun adjustment_Word_collapsed_zero() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world",
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ val rawSelection = TextRange(0, 0)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun adjustment_Word_collapsed_lastIndex() {
+ val text = "hello world"
+ val textLayoutResult = mockTextLayoutResult(
+ text = text,
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ val rawSelection = TextRange(text.lastIndex, text.lastIndex)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 11))
+ }
+
+ @Test
+ fun adjustment_Word_collapsed_textLength() {
+ val text = "hello world"
+ val textLayoutResult = mockTextLayoutResult(
+ text = text,
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ val rawSelection = TextRange(text.length, text.length)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 11))
+ }
+
+ @Test
+ fun adjustment_Word_collapsed_emptyString() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "",
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ val rawSelection = TextRange(0, 0)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 0))
+ }
+
+ @Test
+ fun adjustment_Word_notReversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world",
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ // The adjusted selection should cover the word "hello" and is not reversed.
+ val rawSelection = TextRange(1, 2)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ // The raw selection
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun adjustment_Word_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world",
+ wordBoundaries = listOf(TextRange(0, 5), TextRange(6, 11))
+ )
+ // The raw selection is reversed, so the adjusted selection should cover the word "hello"
+ // and is also reversed.
+ val rawSelection = TextRange(2, 1)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(5, 0))
+ }
+
+ @Test
+ fun adjustment_Word_crossWords() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(4, 7)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 11))
+ }
+
+ @Test
+ fun adjustment_Word_crossWords_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(7, 4)
+
+ val adjustedTextRange = SelectionAdjustment.Word.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = false
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(11, 0))
+ }
+
+ @Test
+ fun adjustment_Paragraph_collapsed() {
+ val textLayoutResult = mockTextLayoutResult(text = "hello world\nhello world")
+
+ val rawSelection = TextRange(14, 14)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(12, 23))
+ }
+
+ @Test
+ fun adjustment_Paragraph_collapsed_zero() {
+
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world\nhello world\nhello world\nhello world"
+ )
+ val rawSelection = TextRange(0, 0)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 11))
+ }
+
+ @Test
+ fun adjustment_Paragraph_collapsed_lastIndex() {
+ val text = "hello world\nhello world"
+ val textLayoutResult = mockTextLayoutResult(text = text)
+ val rawSelection = TextRange(text.lastIndex, text.lastIndex)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(12, 23))
+ }
+
+ @Test
+ fun adjustment_Paragraph_collapsed_textLength() {
+ val text = "hello world\nhello world"
+ val textLayoutResult = mockTextLayoutResult(text = text)
+ val rawSelection = TextRange(text.length, text.length)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(12, 23))
+ }
+
+ @Test
+ fun adjustment_Paragraph_emptyString() {
+ val textLayoutResult = mockTextLayoutResult(text = "")
+ val rawSelection = TextRange(0, 0)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 0))
+ }
+
+ @Test
+ fun adjustment_Paragraph_notReversed() {
+ val textLayoutResult = mockTextLayoutResult(text = "hello world\nhello world")
+ // The raw selection is not reversed, so the adjusted selection should cover the word
+ // "hello" and is not reversed either.
+ val rawSelection = TextRange(1, 2)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 11))
+ }
+
+ @Test
+ fun adjustment_Paragraph_reversed() {
+ val textLayoutResult = mockTextLayoutResult(text = "hello world\nhello world")
+ // The raw selection is reversed, so the adjusted selection should cover the word "hello"
+ // and is also reversed.
+ val rawSelection = TextRange(2, 1)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(11, 0))
+ }
+
+ @Test
+ fun adjustment_Paragraph_crossParagraph() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world\nhello world\nhello world\nhello world"
+ )
+ val rawSelection = TextRange(13, 26)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.Paragraph.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(12, 35))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_initialSelection() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world\nhello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The and previous selection is null, it should use word based
+ // selection in this case.
+ val rawSelection = TextRange(3, 3)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = null,
+ previousAdjustedSelection = null,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndWithinWord() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world\nhello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [6, 7) and new selection expand the end to 8. This is
+ // considered in-word selection. And it will use character-wise selection
+ val rawSelection = TextRange(6, 8)
+ val previousSelection = TextRange(6, 7)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 8))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartWithinWord_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world\nhello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(8, 6)
+ val previousSelection = TextRange(7, 6)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(8, 6))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartWithinWord() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world\nhello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [7, 11) and new selection expand the start to 8. This is
+ // considered in-word selection. And it will use character-wise selection
+ val rawSelection = TextRange(8, 11)
+ val previousSelection = TextRange(7, 11)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(8, 11))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndWithinWord_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world\nhello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(11, 8)
+ val previousSelection = TextRange(11, 7)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(11, 8))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndOutOfWord_notExceedThreshold() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [6, 11) and the new selection expand the end to 13.
+ // Because the previous selection end is at word boundary, it will use word selection mode.
+ // However, the end is didn't exceed the middle of the next word(offset = 14), the adjusted
+ // selection end will be 12, which is the start of the next word.
+ val rawSelection = TextRange(6, 13)
+ val previousSelection = TextRange(6, 11)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 12))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartOutOfWord_notExceedThreshold_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(13, 6)
+ val previousSelection = TextRange(11, 6)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(12, 6))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartOutOfWord_notExceedThreshold() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [6, 11) and the new selection expand the start to 5.
+ // Because the previous selection start is at word boundary, it will use word selection
+ // mode.
+ // However, the start is didn't exceed the middle of the previous word(offset = 2), the
+ // adjusted selection end will be 5, which is the end of the previous word.
+ val rawSelection = TextRange(5, 11)
+ val previousSelection = TextRange(6, 11)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(5, 11))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndOutOfWord_notExceedThreshold_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(11, 5)
+ val previousSelection = TextRange(11, 6)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(11, 5))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndOutOfWord_exceedThreshold() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [6, 11) and the new selection expand the end to 15.
+ // Because the previous selection end is at word boundary, it will use word based selection
+ // strategy.
+ // Since the 15 exceed the middle of the next word(offset: 14), the adjusted selection end
+ // will be 17.
+ val rawSelection = TextRange(6, 15)
+ val previousSelection = TextRange(6, 11)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 17))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartOutOfWord_exceedThreshold_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(15, 6)
+ val previousSelection = TextRange(11, 6)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(17, 6))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartOutOfWord_exceedThreshold() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [6, 11) and the new selection expand the end to 2.
+ // Because the previous selection end is at word boundary, it will use word based selection
+ // strategy.
+ // Since the 2 exceed the middle of the previous word(offset: 2), the adjusted selection
+ // start will be 0.
+ val rawSelection = TextRange(2, 11)
+ val previousSelection = TextRange(6, 11)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 11))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndOutOfWord_exceedThreshold_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(11, 2)
+ val previousSelection = TextRange(11, 6)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(11, 0))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndToNextLine() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+ // The text line break is as shown(underscore for space):
+ // hello_
+ // world_
+ // hello_
+ // world_
+ // The previous selection is [3, 4) and new selection expand the end to 8. Because offset
+ // 8 is at the next line, it will use word based selection strategy. And since 8 exceeds
+ // the middle of the next word(offset: 8), the end will be adjusted to word end: 11.
+ val rawSelection = TextRange(3, 8)
+ val previousSelection = TextRange(3, 4)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(3, 11))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartToNextLine_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+
+ val rawSelection = TextRange(8, 3)
+ val previousSelection = TextRange(4, 3)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(11, 3))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartToNextLine() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+ // The text line break is as shown(underscore for space):
+ // hello_
+ // world_
+ // hello_
+ // world_
+ // The previous selection is [6, 8) and new selection expand the start to 3. Because offset
+ // 3 is at the previous line, it will use word based selection strategy. And because 3
+ // doesn't exceed the middle of the previous word(offset: 2), the end will be adjusted to
+ // word end: 5.
+ val rawSelection = TextRange(3, 8)
+ val previousSelection = TextRange(7, 8)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(5, 8))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndToNextLine_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+
+ val rawSelection = TextRange(8, 3)
+ val previousSelection = TextRange(8, 7)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(8, 5))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndToNextLine_withinWord() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 8
+ )
+ // The text line break is as shown:
+ // hello wo
+ // rld hell
+ // o world
+ // The previous selection is [3, 7) and the end is expanded to 9, which is the next line.
+ // Because end offset is moving between lines, it will use word based selection. In this
+ // case the word "world" crosses 2 lines, so the candidate values for the adjusted end
+ // offset are 8(first character of the line) and 11(word end). Since 9 is closer to
+ // 11(word end), the end offset will be adjusted to 11.
+ val rawSelection = TextRange(3, 9)
+ val previousSelection = TextRange(3, 7)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(3, 11))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartToNextLine_withinWord_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 8
+ )
+
+ val rawSelection = TextRange(9, 3)
+ val previousSelection = TextRange(7, 3)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(11, 3))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandStartToNextLine_withinWord() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 8
+ )
+ // The text line break is as shown:
+ // hello wo
+ // rld hell
+ // o world
+ // The previous selection is [16, 17) and the start is expanded to 15, which is at the
+ // previous line.
+ // Because start offset is moving between lines, it will use word based selection. In this
+ // case the word "hello" crosses 2 lines, so the candidate values for the adjusted start
+ // offset are 12(word start) and 16(last character of the line). Since 15 is closer to
+ // 16(word end), the end offset will be adjusted to 16.
+ val rawSelection = TextRange(15, 17)
+ val previousSelection = TextRange(16, 17)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(16, 17))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_expandEndToNextLine_withinWord_reverse() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 8
+ )
+
+ val rawSelection = TextRange(17, 15)
+ val previousSelection = TextRange(17, 16)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(17, 16))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkEnd() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [0, 11) and new selection shrink the end to 8. In this case
+ // it will use character based selection strategy.
+ val rawSelection = TextRange(0, 8)
+ val previousSelection = TextRange(0, 11)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(0, 8))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkStart_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(8, 0)
+ val previousSelection = TextRange(11, 0)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(8, 0))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkStart() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+ // The previous selection is [0, 8) and new selection shrink the start to 2. In this case
+ // it will use character based selection strategy.
+ val rawSelection = TextRange(2, 8)
+ val previousSelection = TextRange(0, 8)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(2, 8))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkEnd_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ )
+ )
+
+ val rawSelection = TextRange(8, 2)
+ val previousSelection = TextRange(8, 0)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(8, 2))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkEndToPrevLine() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+ // The text line break is as shown(underscore for space):
+ // hello_
+ // world_
+ // hello_
+ // world_
+ // The previous selection is [2, 8) and new selection shrink the end to 4. Because offset
+ // 4 is at the previous line, it will use word based selection strategy. And the end will
+ // be snap to 5.
+ val rawSelection = TextRange(2, 4)
+ val previousSelection = TextRange(2, 8)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(2, 5))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkStartToPrevLine_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+
+ val rawSelection = TextRange(4, 2)
+ val previousSelection = TextRange(8, 2)
+ val isStartHandle = true
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(5, 2))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkStartToNextLine() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+ // The text line break is as shown(underscore for space):
+ // hello_
+ // world_
+ // hello_
+ // world_
+ // The previous selection is [2, 8) and new selection shrink the end to 7. Because offset
+ // 7 is at the next line, it will use word based selection strategy. And the start will
+ // be snap to 6.
+ val rawSelection = TextRange(7, 8)
+ val previousSelection = TextRange(2, 8)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 8))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_shrinkEndToNextLine_reversed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+
+ val rawSelection = TextRange(8, 7)
+ val previousSelection = TextRange(8, 2)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(8, 6))
+ }
+
+ @Test
+ fun adjustment_characterWithWordAccelerate_crossLineSelection_notCollapsed() {
+ val textLayoutResult = mockTextLayoutResult(
+ text = "hello world hello world",
+ wordBoundaries = listOf(
+ TextRange(0, 5),
+ TextRange(6, 11),
+ TextRange(12, 17),
+ TextRange(18, 23)
+ ),
+ lineLength = 6
+ )
+ // The text line break is as shown(underscore for space):
+ // hello_
+ // world_
+ // hello_
+ // world_
+ // The previous selection is [6, 15) and new selection move the end to 7. Because offset
+ // 7 is at the previous line, it will use word based selection strategy.
+ // Normally, the new end will snap to the closest word boundary,
+ // which is 6(the word "world"'s boundaries are 6 and 11).
+ // However, in this specific case the selection start offset is already 6,
+ // adjusting the end to 6 will result in a collapsed selection [6, 6). So, it should
+ // move the end offset to the other word boundary which is 11 instead.
+ val rawSelection = TextRange(6, 7)
+ val previousSelection = TextRange(6, 15)
+ val isStartHandle = false
+
+ val adjustedTextRange = SelectionAdjustment.CharacterWithWordAccelerate.adjust(
+ textLayoutResult = textLayoutResult,
+ newRawSelectionRange = rawSelection,
+ previousRawSelectionRange = previousSelection,
+ previousAdjustedSelection = previousSelection,
+ isStartHandle = isStartHandle
+ )
+
+ assertThat(adjustedTextRange).isEqualTo(TextRange(6, 11))
+ }
+
+ private fun mockTextLayoutResult(
+ text: String,
+ wordBoundaries: List<TextRange> = listOf(),
+ lineLength: Int = text.length
+ ): TextLayoutResult {
+ val multiParagraph = mock<MultiParagraph> {
+ on { getWordBoundary(any()) }.thenAnswer { invocation ->
+ val offset = invocation.arguments[0] as Int
+ val wordBoundary = wordBoundaries.find { offset in it.start..it.end }
+ // Workaround: Mockito doesn't work with inline class now. The packed Long is
+ // equal to TextRange(start, end).
+ packInts(wordBoundary!!.start, wordBoundary.end)
+ }
+
+ on { getLineForOffset(any()) }.thenAnswer { invocation ->
+ val offset = invocation.arguments[0] as Int
+ offset / lineLength
+ }
+
+ on { getLineStart(any()) }.thenAnswer { invocation ->
+ val offset = invocation.arguments[0] as Int
+ offset * lineLength
+ }
+
+ on { getLineEnd(any(), any()) }.thenAnswer { invocation ->
+ val offset = invocation.arguments[0] as Int
+ (offset + 1) * lineLength
+ }
+ }
+
+ return TextLayoutResult(
+ layoutInput = TextLayoutInput(
+ text = AnnotatedString(text = text),
+ style = TextStyle.Default,
+ placeholders = emptyList(),
+ maxLines = Int.MAX_VALUE,
+ softWrap = true,
+ overflow = TextOverflow.Clip,
+ density = Density(1f, 1f),
+ layoutDirection = LayoutDirection.Ltr,
+ resourceLoader = mock(),
+ constraints = mock()
+ ),
+ multiParagraph = multiParagraph,
+ size = IntSize.Zero
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerDragTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerDragTest.kt
index 7df0c90..f19af4f 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerDragTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerDragTest.kt
@@ -67,6 +67,18 @@
private val endSelectableKey = 3L
private val startLayoutCoordinates = mock<LayoutCoordinates>()
private val endLayoutCoordinates = mock<LayoutCoordinates>()
+ private val fakeSubselection: Selection = Selection(
+ start = Selection.AnchorInfo(
+ direction = ResolvedTextDirection.Ltr,
+ offset = 0,
+ selectableId = selectableKey
+ ),
+ end = Selection.AnchorInfo(
+ direction = ResolvedTextDirection.Ltr,
+ offset = 5,
+ selectableId = selectableKey
+ )
+ )
private val fakeInitialSelection: Selection = Selection(
start = Selection.AnchorInfo(
direction = ResolvedTextDirection.Ltr,
@@ -105,7 +117,11 @@
selectionRegistrar.subscribe(selectable)
selectionRegistrar.subscribe(startSelectable)
selectionRegistrar.subscribe(endSelectable)
+ selectionRegistrar.subselections = mapOf(
+ selectableKey to fakeSubselection
+ )
+ selectable.clear()
selectable.selectionToReturn = fakeResultSelection
selectionManager.containerLayoutCoordinates = containerLayoutCoordinates
@@ -157,9 +173,10 @@
assertThat(selectable.lastEndPosition).isEqualTo(childToLocalOffset)
assertThat(selectable.lastContainerLayoutCoordinates)
.isEqualTo(selectionManager.requireContainerCoordinates())
- assertThat(selectable.lastAdjustment).isEqualTo(SelectionAdjustment.CHARACTER)
+ assertThat(selectable.lastAdjustment)
+ .isEqualTo(SelectionAdjustment.CharacterWithWordAccelerate)
assertThat(selectable.lastIsStartHandle).isEqualTo(true)
- assertThat(selectable.lastPreviousSelection).isEqualTo(fakeInitialSelection)
+ assertThat(selectable.lastPreviousSelection).isEqualTo(fakeSubselection)
assertThat(selection).isEqualTo(fakeResultSelection)
verify(spyLambda, times(1)).invoke(fakeResultSelection)
@@ -184,9 +201,10 @@
assertThat(selectable.lastEndPosition).isEqualTo(childToLocalOffset + dragDistance)
assertThat(selectable.lastContainerLayoutCoordinates)
.isEqualTo(selectionManager.requireContainerCoordinates())
- assertThat(selectable.lastAdjustment).isEqualTo(SelectionAdjustment.CHARACTER)
+ assertThat(selectable.lastAdjustment)
+ .isEqualTo(SelectionAdjustment.CharacterWithWordAccelerate)
assertThat(selectable.lastIsStartHandle).isEqualTo(false)
- assertThat(selectable.lastPreviousSelection).isEqualTo(fakeInitialSelection)
+ assertThat(selectable.lastPreviousSelection).isEqualTo(fakeSubselection)
assertThat(selection).isEqualTo(fakeResultSelection)
verify(spyLambda, times(1)).invoke(fakeResultSelection)
@@ -215,11 +233,13 @@
start = Selection.AnchorInfo(
direction = ResolvedTextDirection.Ltr,
offset = 0,
+ rawOffset = 0,
selectableId = selectableKey
),
end = Selection.AnchorInfo(
direction = ResolvedTextDirection.Ltr,
offset = 10,
+ rawOffset = 10,
selectableId = selectableKey
)
)
@@ -260,4 +280,17 @@
override fun getBoundingBox(offset: Int): Rect {
TODO("Not yet implemented")
}
+
+ fun clear() {
+ lastStartPosition = null
+ lastEndPosition = null
+ lastContainerLayoutCoordinates = null
+ lastAdjustment = null
+ lastPreviousSelection = null
+ lastIsStartHandle = null
+ getSelectionCalledTimes = 0
+ getTextCalledTimes = 0
+ selectionToReturn = null
+ textToReturn = null
+ }
}
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerTest.kt
index 59736b1..2f38c09 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/SelectionManagerTest.kt
@@ -95,8 +95,10 @@
@Before
fun setup() {
+ selectable.clear()
selectable.selectableId = selectableId
selectionRegistrar.subscribe(selectable)
+ selectionRegistrar.subselections = mapOf(selectableId to fakeSelection)
selectionManager.containerLayoutCoordinates = containerLayoutCoordinates
selectionManager.hapticFeedBack = hapticFeedback
selectionManager.clipboardManager = clipboardManager
@@ -115,9 +117,13 @@
@Test
fun mergeSelections_single_selectable_calls_getSelection_once() {
- val fakeNewSelection = mock<Selection>()
+ val newSelection = fakeSelection.copy(
+ start = fakeSelection.start.copy(
+ offset = fakeSelection.start.offset + 1
+ )
+ )
- selectable.selectionToReturn = fakeNewSelection
+ selectable.selectionToReturn = newSelection
selectionManager.mergeSelections(
startPosition = startCoordinates,
@@ -130,7 +136,7 @@
assertThat(selectable.lastEndPosition).isEqualTo(endCoordinates)
assertThat(selectable.lastContainerLayoutCoordinates)
.isEqualTo(selectionManager.requireContainerCoordinates())
- assertThat(selectable.lastAdjustment).isEqualTo(SelectionAdjustment.NONE)
+ assertThat(selectable.lastAdjustment).isEqualTo(SelectionAdjustment.None)
assertThat(selectable.lastPreviousSelection).isEqualTo(fakeSelection)
verify(
@@ -146,6 +152,10 @@
whenever(selectableAnother.selectableId).thenReturn(anotherSelectableId)
selectionRegistrar.subscribe(selectableAnother)
+ selectionRegistrar.subselections = mapOf(
+ anotherSelectableId to fakeSelection,
+ selectableId to fakeSelection
+ )
selectionManager.mergeSelections(
startPosition = startCoordinates,
@@ -158,7 +168,7 @@
assertThat(selectable.lastEndPosition).isEqualTo(endCoordinates)
assertThat(selectable.lastContainerLayoutCoordinates)
.isEqualTo(selectionManager.requireContainerCoordinates())
- assertThat(selectable.lastAdjustment).isEqualTo(SelectionAdjustment.NONE)
+ assertThat(selectable.lastAdjustment).isEqualTo(SelectionAdjustment.None)
assertThat(selectable.lastPreviousSelection).isEqualTo(fakeSelection)
verify(selectableAnother, times(1))
@@ -166,7 +176,7 @@
startPosition = startCoordinates,
endPosition = endCoordinates,
containerLayoutCoordinates = selectionManager.requireContainerCoordinates(),
- adjustment = SelectionAdjustment.NONE,
+ adjustment = SelectionAdjustment.None,
previousSelection = fakeSelection
)
verify(
@@ -177,13 +187,13 @@
@Test
fun mergeSelections_selection_does_not_change_hapticFeedBack_Not_triggered() {
- val selection: Selection = mock()
+ val selection: Selection = fakeSelection
selectable.selectionToReturn = selection
selectionManager.mergeSelections(
startPosition = startCoordinates,
endPosition = endCoordinates,
- previousSelection = selection
+ previousSelection = fakeSelection
)
verify(
diff --git a/compose/integration-tests/demos/common/build.gradle b/compose/integration-tests/demos/common/build.gradle
index 393d58f..dc41c9f 100644
--- a/compose/integration-tests/demos/common/build.gradle
+++ b/compose/integration-tests/demos/common/build.gradle
@@ -26,5 +26,6 @@
implementation(libs.kotlinStdlib)
api("androidx.activity:activity:1.2.0")
+ api("androidx.fragment:fragment-ktx:1.3.6")
implementation(projectOrArtifact(":compose:runtime:runtime"))
}
diff --git a/compose/integration-tests/demos/common/src/main/java/androidx/compose/integration/demos/common/Demo.kt b/compose/integration-tests/demos/common/src/main/java/androidx/compose/integration/demos/common/Demo.kt
index 15ee91f..2c1d864 100644
--- a/compose/integration-tests/demos/common/src/main/java/androidx/compose/integration/demos/common/Demo.kt
+++ b/compose/integration-tests/demos/common/src/main/java/androidx/compose/integration/demos/common/Demo.kt
@@ -19,6 +19,7 @@
import android.app.Activity
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
+import androidx.fragment.app.Fragment
import kotlin.reflect.KClass
/**
@@ -39,6 +40,8 @@
*/
class ActivityDemo<T : ComponentActivity>(title: String, val activityClass: KClass<T>) : Demo(title)
+class FragmentDemo<T : Fragment>(title: String, val fragmentClass: KClass<T>) : Demo(title)
+
/**
* Demo that displays [Composable] [content] when selected.
*/
diff --git a/compose/integration-tests/demos/src/main/AndroidManifest.xml b/compose/integration-tests/demos/src/main/AndroidManifest.xml
index 12e95e6..1d86efa 100644
--- a/compose/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/compose/integration-tests/demos/src/main/AndroidManifest.xml
@@ -26,6 +26,7 @@
<activity
android:name=".DemoActivity"
android:configChanges="uiMode"
+ android:exported="true"
android:theme="@android:style/Theme.Material.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -37,6 +38,7 @@
<activity
android:name=".DemoSettingsActivity"
android:label="Demo Theme Settings"
+ android:exported="false"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar" />
</application>
</manifest>
diff --git a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt
index 8f59333..b438f13 100644
--- a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt
+++ b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt
@@ -23,7 +23,6 @@
import android.os.Bundle
import android.view.View
import android.view.Window
-import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.activity.OnBackPressedDispatcher
import androidx.compose.integration.demos.common.ActivityDemo
@@ -48,6 +47,7 @@
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalView
+import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.preference.PreferenceManager
@@ -55,7 +55,7 @@
/**
* Main [Activity] containing all Compose related demos.
*/
-class DemoActivity : ComponentActivity() {
+class DemoActivity : FragmentActivity() {
lateinit var hostView: View
lateinit var focusManager: FocusManager
diff --git a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoApp.kt b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoApp.kt
index fdfbc3e..a878e475 100644
--- a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoApp.kt
+++ b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoApp.kt
@@ -20,8 +20,8 @@
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@@ -29,6 +29,7 @@
import androidx.compose.integration.demos.common.ComposableDemo
import androidx.compose.integration.demos.common.Demo
import androidx.compose.integration.demos.common.DemoCategory
+import androidx.compose.integration.demos.common.FragmentDemo
import androidx.compose.integration.demos.common.allLaunchableDemos
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
@@ -45,6 +46,7 @@
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
@@ -55,6 +57,9 @@
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.fragment.app.FragmentActivity
+import androidx.fragment.app.FragmentContainerView
@Composable
fun DemoApp(
@@ -122,6 +127,30 @@
}
is ComposableDemo -> demo.content()
is DemoCategory -> DisplayDemoCategory(demo, onNavigate)
+ is FragmentDemo<*> -> {
+ lateinit var view: FragmentContainerView
+ AndroidView(
+ modifier = Modifier.fillMaxSize(),
+ factory = { context ->
+ view = FragmentContainerView(context).also {
+ it.id = R.id.fragment_container
+ }
+ view
+ }
+ )
+ DisposableEffect(demo) {
+ // TODO: This code could be cleaner using FragmentContainerView.getFragment().
+ // Update this code once it appears in a released artifact.
+ val fm = (view.context as FragmentActivity).supportFragmentManager
+ fm.beginTransaction()
+ .add(R.id.fragment_container, demo.fragmentClass.java, null, null)
+ .commit()
+ onDispose {
+ fm.beginTransaction().remove(fm.findFragmentById(R.id.fragment_container)!!)
+ .commit()
+ }
+ }
+ }
}
}
diff --git a/compose/integration-tests/demos/src/main/res/values/ids.xml b/compose/integration-tests/demos/src/main/res/values/ids.xml
new file mode 100644
index 0000000..285c404
--- /dev/null
+++ b/compose/integration-tests/demos/src/main/res/values/ids.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <item name="fragment_container" type="id" />
+</resources>
\ No newline at end of file
diff --git a/compose/integration-tests/docs-snippets/build.gradle b/compose/integration-tests/docs-snippets/build.gradle
index dd7311c..d8381ae 100644
--- a/compose/integration-tests/docs-snippets/build.gradle
+++ b/compose/integration-tests/docs-snippets/build.gradle
@@ -46,6 +46,7 @@
implementation(libs.kotlinStdlib)
implementation(libs.kotlinReflect)
+ implementation(libs.testCore)
implementation(libs.testRules)
implementation(libs.espressoCore)
implementation(libs.junit)
diff --git a/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt b/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt
index 2169a8f..518d4a5 100644
--- a/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt
+++ b/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt
@@ -21,7 +21,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest.compiled
import com.android.tools.lint.checks.infrastructure.LintDetectorTest.kotlin
import com.android.tools.lint.checks.infrastructure.TestFile
-import com.android.tools.lint.checks.infrastructure.TestFiles.bytecode
import org.intellij.lang.annotations.Language
import java.util.Locale
@@ -32,6 +31,7 @@
val Color: TestFile = compiledStub(
filename = "Color.kt",
filepath = "androidx/compose/ui/graphics",
+ checksum = 0x2a148ced,
source = """
package androidx.compose.ui.graphics
@@ -75,27 +75,10 @@
): Color = Color.Black
""",
"""
- androidx/compose/ui/graphics/ColorKt.class:
- H4sIAAAAAAAAAJVUz28bRRT+Zn/a2026ae202dSpk7hglyR2UkgAN6EhUiSn
- LpUo6SUHNF4v7ibrXWt3XZULREj8EVy5c+GALA4oKjdO/EWUN5uVnaZCLSvN
- vB8z73vfmzezf/3z+x8APsQuQ4UH3Sj0ui/qTtgfhLFbH3r1XsQHzzwnru+F
- fhg9THQwBuuYP+d1nwe9+uPOseuQV2ZQ0y0MSvWgdsBgnoSJ7wX1w3YY9HTo
- FOaEQZxEQycJo1WvP/BN5KEZyMFQiQRe0cew9HYaOqYNXIVBOZ3znOxA5G2J
- vKzFoFf36RNWfo9AeOCFAcNa++3QlfH+polZ3MhTnpsMK/8nUodNxfbc5HOf
- Oyerje7W1w+PDxnkau3AxC2UDMxjgezI7RLffSqjF7kuMVQ6/tAlk/uDZ5xh
- 6hy4637Dh37CYKdltdqXj78pcFUUDUh4X1Tfok9Ub6fafwbURMAHDDPtrFeP
- 3IR3ecKbDFL/uUw9YWJSieWJUCTyv/CE1iCtu87w99npgnF2akg3pVRYuiHl
- VJI5khLJPLnthkWT1GAbmiWRlEkqmVRTmctJlia0P0fs7PTlzxoB2bOTqBzJ
- /GTNuIyYzxDzGWJ+jHgh6splRHOyNvXyB0khynOirg16DO9wV+iUwJBL9bUT
- 6o+yF3apfVfbXuB+Mex33Ogr3vHJc60dOtx/yiNP2Jlz6klC1+MRH2S28SQc
- Ro677wlj7sthkHh996kXe7S6GwRhwhO6XDHWqWmKeC/QMEdd1IhEk6wOeXWS
- Kwu78qZSHuHKbgHmliJvauVZ5XthW+VNMtVyUfmWzBGsX0RTcZ/maynmLAwa
- No0qjW3ymIROmJihHUjzXc/ytSFDvFvbvi9vz/9IgA+s8g6lvl16A30a4tLY
- hG6n+BNkm5ALGXIxQ36cVaj/irnfcHsCo6UhS2n43fMtKGMxPQyd/Ivpuo5l
- 0qRUq5AmW3ncwXsZeJPiNFFwUbFy3/0E1dxfWq7cGaF6nmeHZhnMuMC7RL+o
- ReJeSlnW3o1l7RLLwphlYcyyMGZZyFjezcC3M5aFjKU+g1c79vyt0ggrr/E0
- L/CsEM8qnWuFlj9LN32KByQPCXSVmK8dQW6h3kKDZqy3sIF7Lfr5f3QEFmMT
- W0eYjqHG+DhGOcYnMZZiLMeoxCjGmEk912PUUkX7F4jgH2k8BgAA
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcolmZiXUpSfmVKhl5yfW5BfnKqX
+ m1iSWpSZmCPE4Zyfk19U7F3Cpc4li1OZXlp+vhBbSGpxCVihDIbC0ky99KLE
+ gozM5GIhdrCR3iVKDFoMAMec7K6RAAAA
""",
"""
androidx/compose/ui/graphics/Color$Companion.class:
@@ -127,61 +110,79 @@
""",
"""
androidx/compose/ui/graphics/Color.class:
- H4sIAAAAAAAAAI1X+1Mb1xX+7koCsSwgsIwBE2LH1BYYLCBumtqOjYHGkSxw
- YmxcQtJ0ERuxsNqVd1fYbtOWpp2GJtPpdJq2k3Q6bdJH+rDbOE6AxjMd6vzW
- 8Z/QP6VT99y7F0mGnToes+fcc7/zuOdxL/zrv5/+A8Bx/J3hCd1ecB1z4Xo6
- 7xRLjmeky2a64OqlRTPvpccdy3HrwRgSS/qKnrZ0u5C+ML9k5P16REhaMPwZ
- 3Sobg97gzPmp85cZIqm+LINatued64NmsWRpqEedCgVxhqi/aHoMvblHez3J
- 0OQ7075r2gVhh2FvKtuXq8YR7BFu307ZWNm0FgwKvJmh7pRpm/5pEdiMhgRa
- VbSgjUETblIrPPxn4kgSVC+VDHuBYTC1281uz9LLSQ3t2MeNdpDRZce3TDt9
- OefYhXp0adDQpGI/undYDZL4CKs93OrjDN2p8f8PPMiBTzDEtzPGkEyF5EpD
- L77AsYepFrpbGGJgWV4bCq9pUfcWx50FQ2Y7StnOaDiKAR7/IBnfBohcZrga
- SRuNq2Xd8qRSeyobcsgXGWKOv2i4DG27tynxgQ1e4TBtDSN4krt7OohqRkWU
- VzAmaqfhFPoaaPcZ6se8Y3u+W877jltzDGrI+HY7MhzhbfQ5GpA3ywnudpyy
- tEK1rTkpJS6Wymb5yZTSMP+M0Nn0fN7wvF4aijFLzy/35ksEE6yG80GQOTpk
- FTahu8vnXP2GQMa3VxouBODnGVqr4AowGoCmA9AlynoVlDMLi1VkQ2Wp4UoA
- /+pDcV5ZNH0jiFOwGuYC2EuUzCrsorEgQBFiNLwSQL7+kKVzrmHYgSXBasgH
- sIWHDjFGFQsOMSZqVwhAiwx7qqBZw7KcawJWF/AalgOg9ZC18Rt64DPKOQ1O
- ACJBsgqa1AuG7esCVy8XGrwA6jN0VKGXXN32SrpLEAFvrBFouBaoXKdSncpb
- 8loZeHQn9Y7Tjm6bjl2PbzIMp3LyllhaKaZN2zdcW7fSE8aretnyx6sdPEn9
- QAMeXFvfUvEavk0lrRhjOPY52rjqnBp6Fd/lJ3g9Rtc/HtAP3cWPNnGeLvsf
- UF3FQsMaRlW8gR8GRiYmJgJmbW0tYO7fvx8w9E8ygPT4YJvB9lZFUgU/4FOb
- 6ctyV7/mrn7DcCjnuIX0kuHPu7ppe2ndth1f9+lYXnrK8afKlkUXSXttZrMr
- xYxNC4M2Wrc3Jg1fX9B9nWRKcSXCU8A/MRrxZRJdN/mKpltZoKn+99Zqv6p0
- KKqS2FpV6b/g43W0biQaJRonGiHazGn83hujHVurB9pHlCF2grWPtbXVJZQu
- ZSjy2SbbWr33fl00Hk3Esl2JBhKqI/FEY1e0gw2x5z77eUTsaommbCLRTLst
- JGNClki0kqyNZHsqsmRi78XuGtP0YfSj0KbKo+qKxusS9ffWmBJ4fl1poQA7
- 1Vj83ns9Q4z4g/yMdGlRCzTnal8tykxcVPrYMg3H/otl2zeLRsZeMT1z3jLO
- VhPPx048By05yvJUuThvuJd0wvBr3snr1ozumnwthU3TPl2Fk3pJrrWMbRvu
- uKV7nkHG1Gmn7OaNZ02+1yn9zuzyimHq4ChVqRmdvKHpALdpVUf0faJt/Dkg
- 2sVvXEEvSDot6RVJ5yR9RdK8pAVJlyV1JPUkvSZoJ1qpc7nXj2iVppgY76P+
- dTTcIkbBHRkUKNiP6asFAKhoJNrAfzGQyicQITzQfRctsxvY07Z3HZ09m3hs
- HQcSfes4tI4jH4phrdrpRkqEwfiLLu0clkHEeRCb6N+pE6/4pkdd6hwiHe47
- Rv6O3dyhEKs4SWMo3MnwTp2qE3q0pc7zlAI+3PsH/gnlXcQiNwe2oJD+WM/B
- t9/h6+hNkbNP6FsPpeE/aAmS1i6C2y/j4NxxfFFE8BS+JK0Py/Q18IiObuLL
- 1ZAC9QYZEue4Okso/GmX6qdJnQ+92r+Bk/2Pf4LTt0PrF9hSK7ZU0Wh0IeMM
- RqWtAzKbSs+tHWlRgrZMdOIsxiT6CFkW8d2FMtuzgYmdBWvAV4RSK/8VuqZg
- Qad9jNM7vWx3VyeexTmpcIa88HHReg68/S7qox8gGqlmOwZFHa1NlobnZK41
- ZIhTKORsxXu3wFBKPsJk4LwmTYScCkO+EIa8GIa8HIacCUPOhiFfDEO+HIb8
- WhhSD0POhyGNMOSrYUgzDLkUhiyGIe0w5NUwpBuGLIchV8KQN3YhaZK/QXdc
- gPxUjAiwchevzbINfOcOvpfE9zfx5h1MJvGWYF5I4keCuZzEjwUzm8RPBPNy
- Ej8VjJ7EzwRjJPELwZhJvCOYYhK/FMzVJH4lmHJkE+/dwY3bldhGqCsbKcIk
- TcRjFOFhmpE0Nf3TJD1Le1m6VKfpZXiJ/sYxaMhtOkEE62JcGf0CpdCL0YkN
- 0f4fYpOoT9xvif6ORuH3c4hk8IcMPqAv/sg/f8rgz/jLHJiHm7g1h30eGj38
- 1cMpD3/zcMbDqIeYhzp6HTw8JbaOexjx8KSHtFge9TDgoVfwmocmD6v/AwBZ
- QjGCDwAA
+ H4sIAAAAAAAAAI1X+1Mb1xX+7kpCYllAYBkDJsQPagsMFhA3TW3HxkDjSBY4
+ MTYuIWm6iI1YWHbl3ZVst2lL005D2+l0Ok3bSTqdNukjfdhtHCdA45kOdX7r
+ +E/on9Kpe+7di4Rhp47H7Dn33O887nncC//67yf/AHACf2c4pNvzrmPO38gU
+ nOWS4xmZspkpunppwSx4mTHHctw4GENyUa/oGUu3i5mLc4tGwY8jQtKi4U/r
+ VtkY8AamL0xeuMIQSffmGNSyPefcGDCXS5aGOOpUKEgwRP0F02PoyT/e6ymG
+ Rt+Z8l3TLgo7DHvTud58LY5gj3D7dspGy6Y1b1DgTQx1p03b9M+IwKY1JNGi
+ ohmtDJpwk67w8J9NIEVQvVQy7HmGgfRuN7s9Sy+nNLRhHzfaTkaXHN8y7cyV
+ vGMX4+jUoKFRxX507bAaJPExVru51ScZutJj/x94kAMPMSS2MsaQSofkSkMP
+ PsexR6gWulscZGA5XhsKr3FB9xbGnHlDZjtK2c5qOIZ+Hv8AGd8CiFxmuRpJ
+ G4xrZd3ypFJbOhdyyJcYYo6/YLgMrbu3KfGBDV7hMG0Nw3iKu3smiGpaRZRX
+ MCZqp+E0eutp91nqx4Jje75bLviOu+0Y1JCJrXZkOMrb6DM0IG+Wk9ztGGWp
+ QrXddlJKXCydy/GTKaUh/hmms+mFguF5PTQUo5ZeWOoplAgmWA0XgiDzdMga
+ bFx3l867+k2BTGytNFwMwC8wtNTAVWA0AE0FoMuU9RoobxYXasj66lLD1QD+
+ 5UfivLpg+kYQp2A1zAawlymZNdglY16AIsRoeDWAfPURS+ddw7ADS4LVUAhg
+ 848cYpQqFhxiVNSuGIAWGPbUQDOGZTnXBawu4DUsBUDrEWtjN/XAZ5RzGpwA
+ RIJUDTShFw3b1wUuLhcavADqM7TXoJdd3fZKuksQAW/YJtBwPVC5QaU6XbDk
+ tdL/+E7qGaMd3TYdO46vMwyl8/KWWKwsZ0zbN1xbtzLjxmt62fLHah08Qf1A
+ Ax5cW99Q8Tq+SSWtGmM4/hnauOacGnoF3+YneCNG1z8e0g/dxY83cYEu++9R
+ XcVCwypGVLyJ7wdGxsfHA2Z1dTVgHjx4EDD0TzKA9Phwi8HWVlVSAz/kU5vt
+ zXFXv+aufsNwOO+4xcyi4c+5uml7Gd22HV/36VheZtLxJ8uWRRdJ2/bM5irL
+ WZsWBm20bG1MGL4+r/s6yZTlSoSngH9iNOJLJLph8hVNtzJPU/3vzZU+VWlX
+ VCW5uaLSf8En6mjdQDRKNEE0QrSJ08T9N0faN1cOtA0rg+wkaxttba1LKp3K
+ YOTTDba5cv+9umgimozlOpP1JFSHE8mGzmg7G2TPf/rziNjVko25ZLKJdptJ
+ xoQsmWwhWSvJ9lRlqeTeS13bTNOH0Y9CmyqPqjOaqEvG768yJfD8htJMAXao
+ scT9d7sHGfEH+Rnp0qIWaMpvf7UoMwlR6eNLNBz7L5Vt31w2snbF9Mw5yzhX
+ SzwfO/EcNOcpy5Pl5TnDvawThl/zTkG3pnXX5GspbJzy6Sqc0EtyrWVt23DH
+ LN3zDDKmTjllt2A8Z/K9Dul3epdXDFEHR6lKTejgDU0HuEOrOqLvEW3lzwHR
+ Tn7jCnpR0ilJr0o6K+mrkhYkLUq6JKkjqSfpdUE70EKdy71+SKsMxcR4H/Wt
+ of42MQruyqBAwX5EXy0AQEUD0Xr+i4FUPokI4YGue2ieWcee1r1r6OjewBNr
+ OJDsXcPhNRz9QAxrzU4X0iIMxl90aeeIDCLBg9hA306dRNU3PepS5zDpcN8x
+ 8nf81g6FWNVJBoPhToZ26tSc0KMtdV6gFPDh3t//TyjvIBa51b8JhfRHuw++
+ 9TZfR2+JnH1M3ziU+v+gOUhamwhuv4yDcyfweRHB0/iCtD4k01fPIzq2gS/W
+ QgrU62VInOPqLKnwp12qnyF1PvRq3zpO9T35Mc7cCa1fYEut2lJFo9GFjLMY
+ kbYOydaMdp87cHtHYqJBYyY7cA6jEn+UpCLCe1BmutcxvrNk9fiSUGrhv0Rv
+ K1nQax/hzE4vW/3VgedwXiqcJS88Kq37wFvvIB59H9FILd8xKOrI9nRpeF5m
+ W0OWOIVCzlW9dwkMHedDTATOtyWKkJNhyBfDkJfCkFfCkNNhyJkw5EthyFfC
+ kF8JQ+phyLkwpBGGfC0MaYYhF8OQy2FIOwx5LQzphiHLYchKGPLmLiTN8tfo
+ lguQn4ghASr38PoMW8e37uI7KXx3Az+4i4kUfiiYF1P4kWCupPBjwcyk8BPB
+ vJLCTwWjp/AzwRgp/EIwZgpvC2Y5hV8K5loKvxJMObKBd+/i5p1qbMPUlQ0U
+ YYom4gmK8AjNSIaa/hmSnqO9HF2rU/Q2vEx/5Rg05jadIII1MbCMfoVS6M3o
+ wLpo/w+wQdQn7rdEf0ej8PtZRLL4Qxbv0xd/5J8/ZfFn/GUWzMMt3J7FPg8N
+ Hv7q4bSHv3k462HEQ8xDHb0PHp4WWyc8DHt4ykNGLI956PfQI3jNQ6OHlf8B
+ UC9ZO4QPAAA=
""",
"""
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcolmZiXUpSfmVKhl5yfW5BfnKqX
- m1iSWpSZmCPE4Zyfk19U7F3Cpc4li1OZXlp+vhBbSGpxCVihDIbC0ky99KLE
- gozM5GIhdrCR3iVKDFoMAMec7K6RAAAA
+ androidx/compose/ui/graphics/ColorKt.class:
+ H4sIAAAAAAAAAJVUz28bRRT+Zn/a2026ae202dSpk7hglyR2UkgAN6EhUiSn
+ LpUo6SUHNF4v7ibrXWt3XZULREj8EVy5c+GALA4oKjdO/EWUN5uVnaZCLSvN
+ vB8z73vfmzezf/3z+x8APsQuQ4UH3Sj0ui/qTtgfhLFbH3r1XsQHzzwnru+F
+ fhg9THQwBuuYP+d1nwe9+uPOseuQV2ZQ0y0MSvWgdsBgnoSJ7wX1w3YY9HTo
+ FOaEQZxEQycJo1WvP/BN5KEZyMFQiQRe0cew9HYaOqYNXIVBOZ3znOxA5G2J
+ vKzFoFf36RNWfo9AeOCFAcNa++3QlfH+polZ3MhTnpsMK/8nUodNxfbc5HOf
+ Oyerje7W1w+PDxnkau3AxC2UDMxjgezI7RLffSqjF7kuMVQ6/tAlk/uDZ5xh
+ 6hy4637Dh37CYKdltdqXj78pcFUUDUh4X1Tfok9Ub6fafwbURMAHDDPtrFeP
+ 3IR3ecKbDFL/uUw9YWJSieWJUCTyv/CE1iCtu87w99npgnF2akg3pVRYuiHl
+ VJI5khLJPLnthkWT1GAbmiWRlEkqmVRTmctJlia0P0fs7PTlzxoB2bOTqBzJ
+ /GTNuIyYzxDzGWJ+jHgh6splRHOyNvXyB0khynOirg16DO9wV+iUwJBL9bUT
+ 6o+yF3apfVfbXuB+Mex33Ogr3vHJc60dOtx/yiNP2Jlz6klC1+MRH2S28SQc
+ Ro677wlj7sthkHh996kXe7S6GwRhwhO6XDHWqWmKeC/QMEdd1IhEk6wOeXWS
+ Kwu78qZSHuHKbgHmliJvauVZ5XthW+VNMtVyUfmWzBGsX0RTcZ/maynmLAwa
+ No0qjW3ymIROmJihHUjzXc/ytSFDvFvbvi9vz/9IgA+s8g6lvl16A30a4tLY
+ hG6n+BNkm5ALGXIxQ36cVaj/irnfcHsCo6UhS2n43fMtKGMxPQyd/Ivpuo5l
+ 0qRUq5AmW3ncwXsZeJPiNFFwUbFy3/0E1dxfWq7cGaF6nmeHZhnMuMC7RL+o
+ ReJeSlnW3o1l7RLLwphlYcyyMGZZyFjezcC3M5aFjKU+g1c79vyt0ggrr/E0
+ L/CsEM8qnWuFlj9LN32KByQPCXSVmK8dQW6h3kKDZqy3sIF7Lfr5f3QEFmMT
+ W0eYjqHG+DhGOcYnMZZiLMeoxCjGmEk912PUUkX7F4jgH2k8BgAA
"""
)
val Composable: TestFile = compiledStub(
filename = "Composable.kt",
filepath = "androidx/compose/runtime",
+ checksum = 0x12c49724,
source = """
package androidx.compose.runtime
@@ -191,35 +192,37 @@
AnnotationTarget.FUNCTION,
AnnotationTarget.TYPE,
AnnotationTarget.TYPE_PARAMETER,
- AnnotationTarget.PROPERTY
+ AnnotationTarget.PROPERTY_GETTER
)
annotation class Composable
""",
"""
- androidx/compose/runtime/Composable.class:
- H4sIAAAAAAAAAI1STW/TQBB96yRNCFASykfSUvqdFg64VNw4OWkqIuVLjotU
- 5YC29qpy49hVvA7tLQck/hMHFHHkRyFmExEHyRLY0tvZmTc7O2/n569v3wG8
- w2uGPe47o8B1bnU7GN4EodBHkS/dodBrsz2/9EQWjKFwzcdc97h/pXcur4Ut
- s0gxbMVe7vuB5NINfN1YmFlkGPabg0B6rr9MaUWhrIrTwI6GwpfCec+wmUAz
- haQwWRTPjLkXCYbDBF5ccTljpdpoG+YFw3pCisVHV0ISa5V7XvBZOHNHmHzf
- uMAiL3d23q5ZjU6bIW1ddOt0klo+dQ3TaNWtukmUrtnp1k2LrrDTTJTqLwW2
- kznLLVX+QekGnmvfKbVqTaPXU6omJiy62E2O1z2hrmXd3QglJPXzoXNKDc06
- PO9Rs8U/KrWE5A6XnHjacJyiyWIK6OHZgFy3rtodk+W8ZShPJ7m8VtLyWmEj
- 9+OrVppOTrRjVp1OFOGE4aD5HxNJpcDwMHa8GUiGfC+IRrY4cz2akrI5z/ro
- hi4R4vcLK1QJacpfgfo0HM3wEK9o/YIs/UCO4vcE8riPB6pUH2mBVTxSUFBQ
- VPAYa8R9Muc+xTM8V2YfKYESygqKCtaxgQxekL+BzQZeEmJLwXYDO9jtg4XY
- w34fWoiDEJXfIrDY76EDAAA=
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlkZiXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbKsQVlJqbmpuUWuRdwqXJJYyhrjRTSMgZwk7xzU/JTMsEK+XjYilJ
+ LS4RYgsBkt4lSgxaDACMRj6sewAAAA==
""",
"""
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3AJcbFUpJaXCLEFlxSmuQNpEOAPO8S
- JQYtBgBDd0xtMAAAAA==
+ androidx/compose/runtime/Composable.class:
+ H4sIAAAAAAAAAI1STW/aQBB9ayBQ2ibQT0ia5pu0PdRp1FtPQJwWiS8ZJxLi
+ EG3sVeRg7AivaXLjUKn/qYcK9dgfVXUWVKCSpdaW3s7OvNnZeTs/f337DuA9
+ 3jDscd8ZBq5zq9vB4CYIhT6MfOkOhF6d7vmlJ9JgDLlrPuK6x/0rvXV5LWyZ
+ RoJha+Hlvh9ILt3A18tzM40Uw369H0jP9ZcpjSiUFXES2NFA+FI4Hxg2Y2im
+ kBQmi+KpEfciwXAYw1tUXM5YqdSaZbPLsB6TYvHhlZDEWuWeF3wWzswRxt93
+ UWCelzk9a1atWqvJkLS6bYNOUstFu2yWG4ZlmAxrbbPVNkyre/HRsKaenXqs
+ Yn8JsR3PWe6s9A9KO/Bc+06JVq2XOx0lbmzCvJnd+LjhCXUt6+5GKD2prU+t
+ E2p92uhZh3rO/xGrISR3uOTE0wajBA0YU0Dvz/rkunXV7ogs5x1DcTLOZLWC
+ ltVyG5kfX7XCZHysHbHKZKwIxwwH9f8YTCoFhocLx9u+ZMh2gmhoi1PXo2Ep
+ mrOsczd0ibB4xrBElZCk/BWoT8OrKR7iNa1fkKYfyFD8nkAW9/FAleohKbCK
+ NQU5BXkFj/CYuE9m3Kd4hufK7CEhUEBRQV7BOjaQwgvy17BZw0tCbCnYrmEH
+ uz2wEHvY70ELcRCi9BuuoX9IqAMAAA==
"""
)
val Modifier: TestFile = compiledStub(
filename = "Modifier.kt",
filepath = "androidx/compose/ui",
+ checksum = 0xe49bcfc1,
source = """
package androidx.compose.ui
@@ -241,6 +244,12 @@
) : Modifier
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlkZiXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbKsQVlJqbmpuUWuRdwqXJJYyhrjRTSMgZwk7xzU/JTMsEK+XjYilJ
+ LS4RYgsBkt4lSgxaDACMRj6sewAAAA==
+ """,
+ """
androidx/compose/ui/CombinedModifier.class:
H4sIAAAAAAAAAKVTWU8TURT+7nRlKFJGyw6iVOmCDCAusQajGJMmBQ0QYoIv
t+0FbjudITPThkfiT/EX6AOR+GAIj/4o47ltKVpIeTBNz/Lds58zv37/+Alg
@@ -260,66 +269,6 @@
eTzaBfOwAHMXIQ9THkY86B4MD9E/kXas0GMFAAA=
""",
"""
- androidx/compose/ui/Modifier$Element.class:
- H4sIAAAAAAAAAI1QTU8CMRB9s6ssXyogKqjxRDy6QLx5Mn4km0BMNPHCqbDF
- VHZbst0lHPldHgxnf5RxNtHEE6HJvL5586ad9uv74xPANc4IHaHDxKhw6U9M
- PDdW+pnyhyZUUyWTzkMkY6lTD0SovYuF8COh3/yn8bucsOoSzjf1e9gl1Acz
- k0ZK+0OZilCk4obgxAuXJ6Ac2EIzlpYqz7rMwh6huV4Vy07LyaM4ba1XfadL
- ea1PuBxsMzRfc7HRyIbeNgd17uVUZFEaxPPIejgkVP8rBO/XSKj89V7NOKsG
- WsvkLhLWSraVX0yWTOSjiiSh/ZzpVMXyVVk1juSt1iYVqTLaFviV2AGhgHy5
- aDE2WGtyHKHNWMBxocQMzE9wynuP/fzbKI7gBigFKDOikkM1wB72RyCLA9RG
- cCzqFo0fJIqRGAUCAAA=
- """,
- """
- androidx/compose/ui/Modifier$Element$DefaultImpls.class:
- H4sIAAAAAAAAAKVSS2/TQBD+Ni8nqUvTlBRKS3k0tHlATSVuOaECkiU3IIpy
- gcvG2aab2LuVvYn6szhWHBBnfhRinBpoixQiYcmz8/hmZveb+f7jy1cAL/Cc
- 4YCrQaTl4NzxdXimY+FMpHOkB/JEiqj+OhChUKb+SpzwSWDc8CyILTCGyohP
- uRNwNXTe9kfCNxayDDlzKhTDoOEtUrUzF9Vpzg8z7Hg6GjojYfoRlyp2uFLa
- cCM16V1tupMg6MzuJOMiigzbY20CqZzRNHSkMiJSPHBcZSJKlj69q8xQ80+F
- P06z3/GIh4KADHsN7+aLO1c8x0mRYafZs2FjuYwl3GLIa6IjKqLCsDXvKRaq
- DM25jF3n/zbDp/kU/x+1NvJYL6OGOwy7i42S2P3XuFa9lP8jYfiAG06+TDjN
- 0iayROQZ2DhRaJEy5zLRaD/ri7S3sMNgXyWJwUpjDEu/4PtjsnKHeiAYVjyp
- RHcS9kX0gfcD8lQ97fOgxyOZ2Klz8/1EGRkKV01lLMn18s+S0eVuRn9vzDWY
- 7SolosOAx7Egs3ysJ5Ev3sikwUZaovdXeRwggxySj6FEIykgiwZZLvkzdNZa
- 1dIFVtrVVZKtb1hrX+DuZwpk0CRZoDSbElukr18moIiNWcEaKrhH8XaKs+h8
- Sv9yJjUuZRbPSFZn/ep4Qsl1rGG3UML+rM0eHDq3Cb1J2K2PyLq472KbJB64
- eIhHLh7/BG04LjBuBAAA
- """,
- """
- androidx/compose/ui/Modifier$DefaultImpls.class:
- H4sIAAAAAAAAAKVSXU8TQRQ9swW2LUVKEbCCoFKlLcqi8a1GYzAmG9tqrGli
- 9GW6HWDa3RmyO9vwi/TV+KLRxPjsjzLehRUQTX1wk71zz/04M/fj+4/PXwHc
- w12GGlf9UMv+oePp4EBHwoml09J9uStFWHksdnnsGzc48CMbjKE44CPu+Fzt
- Oc96A+EZGxmGCbMvFMObanMcW2O8tzbezbDe1OGeMxCmF3KpIocrpQ03UpPe
- 1qYd+37j6C0yyiLLsDrUxpfKGYwCRyojQsV9x1UmpGTpUT15hgVvX3jDNPs5
- D3kgKJBho9o8X2njjKWTkOw1at0CCpjJYxoXGCY1tSHMosiwMq4UGyWG3A45
- uKLHM4xvW+UkslHARSzkMI9Fhsrfcii0J5Xon151iWHqvlTSPGB4+H/zoWIv
- YzmPMlaouf+a1lwzbX9LGN7nhpPNCkYZWjyWiEkGNkwU2h/rUCbaNkPh7MYx
- TP8i3BoaGu2O7guGmY7h3rDFD17ynk94tkklt+OgJ8LUUmpqj/tdHsoEp8bl
- F7EyMhCuGslIkunR6f5QO897T5bht7CCq5QId3weRYJgvqPj0BNPZHJBOaXo
- /kGPO7AwgeSjyWMSU8igRkiQ1aKzUi/lPmF2szSXyA9Yegu7/g6zX1B+Vd/8
- iCvfMP8+6RXqJG1YS09tWoNNAlNEWSDTLdIXj8mQxerRZRUUSWO4ncbZdG7R
- P2Ol4Fhm4JDME7KIdIMGvE3YQpXejSOCNYq5+hoZF9dcXCeJdZfYb7i4+RNB
- PoFzTQQAAA==
- """,
- """
- androidx/compose/ui/Modifier.class:
- H4sIAAAAAAAAAIVSS2/TQBD+ZuPESRogoTzSB6XQUBJeLhVcKFSqQhFGbUAU
- 9dLTNtmUbZ115d1EPeZX8D+AGwcUceRHIcZVoRSkYMvzzXwzOzOe2e8/vnwF
- 8Aj3CbPSdJJYd46Cdtw7jK0K+jrYjDu6q1XigwjlfTmQQSTNXvB6d1+1nY8M
- wXPvlSGs1jfGJVhpjHcTFjbiZC/YV243kdrYQBoTO+l0zHordq1+FHFU/mk7
- 0ka7VUKm3tgmLI5LW2syJw3n8FEkFGu1sLX1bq3VXCeM7/f05EoJJZwrYALn
- CYXfdAnllBWoECobB7HjtoJN5WRHOsmNit4gw6OlVGQJdMDUkU6tJdY6DwmP
- R8NSUVRFUZRHw6LIe/ludTSc95bFEj0RXvZVpSymxdJouJwrZ46Vl98+eOnh
- ZcLc/8YJQjbm1SQEfz1SPWUcoTb2l0/CfNwgNMZGPldd2Y9c2DuMrI8FQulP
- hjDxK/LBAVededs3TvdUaAba6t1IrZ2ulnv62/tGJrKnnErOhHnNuKO4UGiM
- SpqRtFYxW9yK+0lbvdAR+6ZOMm3/UyXHU4OXrgNT6d4Yb7OVY/QZBU81y5Y4
- w9b58+nEyPNbYL3B+iRj+vifcOEzLn48NjK4w3Ka8Sbnmc+lF0ZwrSnUGG8x
- 3k0rYRH3GJ9xikmueWkHmRCXQ1xhiaupqIYcO70DspjB7A5yFtcs5iyyFtct
- yhbzPwFNAZX3twMAAA==
- """,
- """
androidx/compose/ui/Modifier$Companion.class:
H4sIAAAAAAAAAI1SXU8TQRQ9s1u6y1JkQYHyIX5QoYCyQHwwlpBgo7GmVCOE
xPA03Y4w7XbW7G4bHnnyJ/gD/AUSHzCaGMKjP8p4p1QUTMCHuTP3zDn33rl3
@@ -338,15 +287,71 @@
V5vpEnK4twMWYwazO+iJkYmRjWHH6I/h/gJ6Cp4UWgQAAA==
""",
"""
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcklnpiXUpSfmVKhl5yfW5BfnKpX
- mqmXlp8vxBeSWlzim5+SmZaZWuRdosSgxQAATlErVEMAAAA=
+ androidx/compose/ui/Modifier$DefaultImpls.class:
+ H4sIAAAAAAAAAKVSXU8TQRQ9swW2LUVKEbCCoFKlLcqi8a1GYzAmG9tqrGli
+ 9GW6HWDa3RmyO9vwi/TV+KLRxPjsjzLehRUQTX1wk71zz/04M/fj+4/PXwHc
+ w12GGlf9UMv+oePp4EBHwoml09J9uStFWHksdnnsGzc48CMbjKE44CPu+Fzt
+ Oc96A+EZGxmGCbMvFMObanMcW2O8tzbezbDe1OGeMxCmF3KpIocrpQ03UpPe
+ 1qYd+37j6C0yyiLLsDrUxpfKGYwCRyojQsV9x1UmpGTpUT15hgVvX3jDNPs5
+ D3kgKJBho9o8X2njjKWTkOw1at0CCpjJYxoXGCY1tSHMosiwMq4UGyWG3A45
+ uKLHM4xvW+UkslHARSzkMI9Fhsrfcii0J5Xon151iWHqvlTSPGB4+H/zoWIv
+ YzmPMlaouf+a1lwzbX9LGN7nhpPNCkYZWjyWiEkGNkwU2h/rUCbaNkPh7MYx
+ TP8i3BoaGu2O7guGmY7h3rDFD17ynk94tkklt+OgJ8LUUmpqj/tdHsoEp8bl
+ F7EyMhCuGslIkunR6f5QO897T5bht7CCq5QId3weRYJgvqPj0BNPZHJBOaXo
+ /kGPO7AwgeSjyWMSU8igRkiQ1aKzUi/lPmF2szSXyA9Yegu7/g6zX1B+Vd/8
+ iCvfMP8+6RXqJG1YS09tWoNNAlNEWSDTLdIXj8mQxerRZRUUSWO4ncbZdG7R
+ P2Ol4Fhm4JDME7KIdIMGvE3YQpXejSOCNYq5+hoZF9dcXCeJdZfYb7i4+RNB
+ PoFzTQQAAA==
+ """,
+ """
+ androidx/compose/ui/Modifier$Element$DefaultImpls.class:
+ H4sIAAAAAAAAAKVSS2/TQBD+Ni8nqUvTlBRKS3k0tHlATSVuOaECkiU3IIpy
+ gcvG2aab2LuVvYn6szhWHBBnfhRinBpoixQiYcmz8/hmZveb+f7jy1cAL/Cc
+ 4YCrQaTl4NzxdXimY+FMpHOkB/JEiqj+OhChUKb+SpzwSWDc8CyILTCGyohP
+ uRNwNXTe9kfCNxayDDlzKhTDoOEtUrUzF9Vpzg8z7Hg6GjojYfoRlyp2uFLa
+ cCM16V1tupMg6MzuJOMiigzbY20CqZzRNHSkMiJSPHBcZSJKlj69q8xQ80+F
+ P06z3/GIh4KADHsN7+aLO1c8x0mRYafZs2FjuYwl3GLIa6IjKqLCsDXvKRaq
+ DM25jF3n/zbDp/kU/x+1NvJYL6OGOwy7i42S2P3XuFa9lP8jYfiAG06+TDjN
+ 0iayROQZ2DhRaJEy5zLRaD/ri7S3sMNgXyWJwUpjDEu/4PtjsnKHeiAYVjyp
+ RHcS9kX0gfcD8lQ97fOgxyOZ2Klz8/1EGRkKV01lLMn18s+S0eVuRn9vzDWY
+ 7SolosOAx7Egs3ysJ5Ev3sikwUZaovdXeRwggxySj6FEIykgiwZZLvkzdNZa
+ 1dIFVtrVVZKtb1hrX+DuZwpk0CRZoDSbElukr18moIiNWcEaKrhH8XaKs+h8
+ Sv9yJjUuZRbPSFZn/ep4Qsl1rGG3UML+rM0eHDq3Cb1J2K2PyLq472KbJB64
+ eIhHLh7/BG04LjBuBAAA
+ """,
+ """
+ androidx/compose/ui/Modifier$Element.class:
+ H4sIAAAAAAAAAI1QTU8CMRB9s6ssXyogKqjxRDy6QLx5Mn4km0BMNPHCqbDF
+ VHZbst0lHPldHgxnf5RxNtHEE6HJvL5586ad9uv74xPANc4IHaHDxKhw6U9M
+ PDdW+pnyhyZUUyWTzkMkY6lTD0SovYuF8COh3/yn8bucsOoSzjf1e9gl1Acz
+ k0ZK+0OZilCk4obgxAuXJ6Ac2EIzlpYqz7rMwh6huV4Vy07LyaM4ba1XfadL
+ ea1PuBxsMzRfc7HRyIbeNgd17uVUZFEaxPPIejgkVP8rBO/XSKj89V7NOKsG
+ WsvkLhLWSraVX0yWTOSjiiSh/ZzpVMXyVVk1juSt1iYVqTLaFviV2AGhgHy5
+ aDE2WGtyHKHNWMBxocQMzE9wynuP/fzbKI7gBigFKDOikkM1wB72RyCLA9RG
+ cCzqFo0fJIqRGAUCAAA=
+ """,
+ """
+ androidx/compose/ui/Modifier.class:
+ H4sIAAAAAAAAAIVSS2/TQBD+ZuPESRogoTzSB6XQUBJeLhVcKFSqQhFGbUAU
+ 9dLTNtmUbZ115d1EPeZX8D+AGwcUceRHIcZVoRSkYMvzzXwzOzOe2e8/vnwF
+ 8Aj3CbPSdJJYd46Cdtw7jK0K+jrYjDu6q1XigwjlfTmQQSTNXvB6d1+1nY8M
+ wXPvlSGs1jfGJVhpjHcTFjbiZC/YV243kdrYQBoTO+l0zHordq1+FHFU/mk7
+ 0ka7VUKm3tgmLI5LW2syJw3n8FEkFGu1sLX1bq3VXCeM7/f05EoJJZwrYALn
+ CYXfdAnllBWoECobB7HjtoJN5WRHOsmNit4gw6OlVGQJdMDUkU6tJdY6DwmP
+ R8NSUVRFUZRHw6LIe/ludTSc95bFEj0RXvZVpSymxdJouJwrZ46Vl98+eOnh
+ ZcLc/8YJQjbm1SQEfz1SPWUcoTb2l0/CfNwgNMZGPldd2Y9c2DuMrI8FQulP
+ hjDxK/LBAVededs3TvdUaAba6t1IrZ2ulnv62/tGJrKnnErOhHnNuKO4UGiM
+ SpqRtFYxW9yK+0lbvdAR+6ZOMm3/UyXHU4OXrgNT6d4Yb7OVY/QZBU81y5Y4
+ w9b58+nEyPNbYL3B+iRj+vifcOEzLn48NjK4w3Ka8Sbnmc+lF0ZwrSnUGG8x
+ 3k0rYRH3GJ9xikmueWkHmRCXQ1xhiaupqIYcO70DspjB7A5yFtcs5iyyFtct
+ yhbzPwFNAZX3twMAAA==
"""
)
val Remember: TestFile = compiledStub(
filename = "Remember.kt",
filepath = "androidx/compose/runtime",
+ checksum = 0xc78323f1,
source = """
package androidx.compose.runtime
@@ -383,6 +388,12 @@
): V = calculation()
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlkZiXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbKsQVlJqbmpuUWuRdwqXJJYyhrjRTSMgZwk7xzU/JTMsEK+XjYilJ
+ LS4RYgsBkt4lSgxaDACMRj6sewAAAA==
+ """,
+ """
androidx/compose/runtime/RememberKt.class:
H4sIAAAAAAAAAK1WXVPbRhQ9K38J29jCfJSYJiFgyndkG5q2MZBSWhpPCekE
j9opT8JWqMCWMlrZk0emL33pH+hrf0Ef0z50GPrWH9XpXVlgg4UJTTzW3qvr
@@ -409,18 +420,13 @@
4EcvNemjXh2Sr6A9SrQdxbiGL8nWKLpAyhb3ESpjqYxlGvGwDBX5Mm3o4j4Y
xwpW9zHMEeH4mCPO8YgjyvEJx12OCY5POR5w3Of4jCPHMcXxmGOWo+R9Z/4D
oSNh5zILAAA=
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlkZiXUpSfmVKhl5yfW5BfnKpX
- VJpXkpmbKsQVlJqbmpuUWuRdwqXFJYNLnV5afr4Ql1t+fnBJYkmqd4kSgxYD
- AK/uqdJsAAAA
"""
)
val MutableState: TestFile = compiledStub(
filename = "MutableState.kt",
filepath = "androidx/compose/runtime",
+ checksum = 0xbd322309,
source = """
package androidx.compose.runtime
@@ -435,6 +441,12 @@
class SnapshotStateMap<K, V>
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcUlkZiXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbKsTnW1qSmJSTGlySWJLqXcJlzqWIS61ecWJZKkitkFBQam5qblJq
+ UTBUBKiRl4ulJLW4RIjVLT/fu0SJQYsBAFB+NmSMAAAA
+ """,
+ """
androidx/compose/runtime/MutableState.class:
H4sIAAAAAAAAAI1QTUsbQRh+ZjbZ6Jrq+tXG2tpT8ePgqghCK0JbKATWFpqQ
S06T7KBjkhnZmRWP+1v8B54ED7L06I8qfSd6KO2lc3je93nm4f16/HX/AOAQ
@@ -491,12 +503,6 @@
qfyofGH7y69lU2UVKd9pbegJZbTFATj9lD80hv84wseUxXVOu+59x8o3Cjie
ELZqsounNdYChFglH+BZrQrwvPbb2CF/RJouae6NEQywNsA6ISIPGwNsYmsM
ZnEfD8ZoWqxaPLR4ZNGzaN8Bn285EWQCAAA=
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3AZcYlkZiXUpSfmVKhl5yfW5BfnKpX
- VJpXkpmbKsTnW1qSmJSTGlySWJLqXSLEFZSam5qblFrkXcKlzCWDS59eWn6+
- EHO8d4kSgxYDAFRZLFp1AAAA
"""
)
}
@@ -520,23 +526,17 @@
fun kotlinAndCompiledStub(
filename: String,
filepath: String,
+ checksum: Long,
@Language("kotlin") source: String,
vararg bytecode: String
): KotlinAndCompiledStub {
val filenameWithoutExtension = filename.substringBefore(".").lowercase(Locale.ROOT)
val kotlin = kotlin(source).to("$filepath/$filename")
- @Suppress("DEPRECATION") // b/193244821
val compiled = compiled(
"libs/$filenameWithoutExtension.jar",
kotlin,
- // Hacky hack - duplicate kotlin_module files will cause errors, so instead let's just
- // rename them and hope that nothing breaks (!?)
- *bytecode.map {
- it.replace(
- "main.kotlin_module",
- "$filenameWithoutExtension.kotlin_module"
- )
- }.toTypedArray()
+ checksum,
+ *bytecode
)
return KotlinAndCompiledStub(kotlin, compiled)
}
@@ -563,6 +563,7 @@
fun compiledStub(
filename: String,
filepath: String,
+ checksum: Long,
@Language("kotlin") source: String,
vararg bytecode: String
-): TestFile = kotlinAndCompiledStub(filename, filepath, source, *bytecode).compiled
+): TestFile = kotlinAndCompiledStub(filename, filepath, checksum, source, *bytecode).compiled
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/ModifierInspectorInfoDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/ModifierInspectorInfoDetectorTest.kt
index 3485e15..640e020 100644
--- a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/ModifierInspectorInfoDetectorTest.kt
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/ModifierInspectorInfoDetectorTest.kt
@@ -22,7 +22,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -565,7 +564,6 @@
.expectClean()
}
- @Ignore // b/193270279
@Test
fun rememberModifierInfo() {
lint().files(
@@ -577,7 +575,7 @@
"""
package androidx.compose.ui
- import androidx.compose.runtime.remember
+ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.platform.InspectorValueInfo
@@ -604,18 +602,18 @@
.expectClean()
}
- @Ignore // b/193270279
@Test
fun emptyModifier() {
lint().files(
Stubs.Modifier,
Stubs.Remember,
composedStub,
+ inspectableInfoStub,
kotlin(
"""
package androidx.compose.ui
- import androidx.compose.runtime.remember
+ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
internal actual fun Modifier.width1(width: Int): Modifier = this
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
index 1332499..cdafef1 100644
--- a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
@@ -28,7 +28,6 @@
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.intellij.lang.annotations.Language
-import org.junit.Ignore
import org.junit.runners.Parameterized
/* ktlint-disable max-line-length */
@@ -42,6 +41,7 @@
private val stub = kotlinAndCompiledStub(
filename = "Stub.kt",
filepath = "test",
+ checksum = 0xdbff73f0,
source = """
package test
@@ -65,30 +65,30 @@
}
""",
"""
- test/StubKt.class:
- H4sIAAAAAAAAAJVUW08TQRT+ZnvZpRRYKigtCohVCl621NsDxMSYEBsrGqr4
- wNN0u+DQdtbsThsfiS/+Bp9M/Ae+oQ+G4Js/ynhmS7kjuknPmT3n+8535uxM
- f/3+/gPAPTxk6FdeqJyqateeKROMwd7kHe40udxwXtQ2PZeiMQZrvS1dJXzJ
- ECvMrjJknvitd37Ia01vaT91rVBp+KoppLPZaTk9Suj0EMUFTS2dh1rs5V9L
- oRYeRaTrFS7rgS/q7x03UvacoC2VaHnOQScL1ELFDzacTU/VAi6oKJfSV7wr
- sOyr5XazSSjT9aXypLKQZpg41I2gcCB50ylLFRBfuKGJQYZR963nNvYKvOQB
- b3kEZJgpVI7Pa+FQpKqLbNAG0rAxnMIQMkf1Ttm9iRGGpJAdv+ExjBRmTyqk
- cRGX+jGKMYap80bOMFaWBPBO+2JX8iK/nj87z8oM2RVPrAuvflp+IuL/BTDc
- a++5p3idK079GK1OjM4f0yZBGg29MCj+XuhVkVb1eYbPO1sjqZ2tlGEbkRsz
- uj8rnhu3d7ZyRpGVhm0jN5CJZ2hdjO1+SVLyqZmbtBNnZnc/Wj+3GdFn7KQG
- TSetnS3bHDsHnbQtjd79YJiphLX7qVRkus0So30g09vk4amzV3TO9MW601AM
- 8Sd+nT7nUIUGvdxu1bzglR6U5voub67yQOj3vWBfVWxIrtoBrcdXuue8LDsi
- FJR+fHCkGfLHs/uH8wgsVfXbgestCV09u8dZPVEP8zAQh37iyCKBJO3Oobcs
- ug/7qg2KZHVK2yxMWATXsEWi6+jgXGZgGxfmviHL8EZzjIiTIp8kO4B+kgLS
- XTT5HPlShOvD3b3qqehPCjBpmETQXYzvSz0lqEHe7krFFk8Vs+jKDdHd02IX
- o3cLl3ElkrX/UdbOYoJoxn/JjpDs6BHZyWOyh+UM3I/sHTwgv0TRKRr+1TXE
- ypgu4xpZ5Mu4jhtlzKCwBhZiFnNr6AthhrgZIh3iVohUiPEQEyFuh0j8ATwh
- ftTnBQAA
- """,
- """
META-INF/main.kotlin_module:
H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3AJcbFUpJaXCLEFlxSmuQNpEOAPO8S
JQYtBgBDd0xtMAAAAA==
+ """,
+ """
+ test/StubKt.class:
+ H4sIAAAAAAAAAJ1UW08TQRT+ZnvZpRRZKigtCqhVCl621GuEmBgTQmNFI4gP
+ PE23Cw5tZ83utOGR+OJv8MnEf+Cb+mAIvvmjjGe2FLlUUZvsnJlzvu9858yl
+ 3398+QrgFu4x9CsvVM6yalUfKxOMwd7kbe40uNxwnlY3PZe8MQZrvSVdJXzJ
+ ECtMrzJkHvnN137Iqw1vYT90qVCp+6ohpLPZbjpdSuh0EcU5TS2dhJrvxl9I
+ oeYeRKTLFS5rgS9qW44bKXtO0JJKND3nVyVzVELFDzacTU9VAy4oKZfSV7wj
+ sOSrpVajQSjT9aXypLKQZhg/UI0gdyB5wylLFRBfuKGJUwwj7ivPre8leMYD
+ 3vQIyDBVqBzdr7kDnmWdZIMaSMPGUAqDyBzW69G9iWGGpJBtv+4xDBemjyuk
+ cQZn+zGCUYbJk7acYbQsCeD1OrHzeZFfz/8+zsoM2eeeWBderVd8cX7l/vH6
+ HvzPCY9HpfxBa6hLeuIpXuOKU2tGsx2jq8z0kKBy63pikH9L6FmRZrVZhvc7
+ 28Opne2UYRuRGTU6nxXPjdk72zmjyEpDtpEbyMQzNC/Gdj8kKbho5ibsxG+j
+ u2+tb58Y0afspAZdTFo727Y5egI6aVsavfvGMFMJa/ddqch0mSVGfSDTbfLg
+ AbIVurL6jd6oK4b4I79GN2OwQme21GpWvWBFb5Tm+i5vrPJA6PWes29ZbEiu
+ WgHNx553nkxZtkUoKPzw1+tgyB+N7t/zQ7DUst8KXG9B6OzZPc7qsXyYhYE4
+ 9C+OLBJIUndFWmXR+bGPeiAYopAeszBhEVzD5omuvadmMgOfcHrmM7IMLzXH
+ iDgpskkaB9CPEq3THTTZHNmbEa6P/uM62VNkb9Nn0mYSQVcxti+1SFCDrN2R
+ is33FLPo9Q7SM9ZiZ6K1hXM4H8nafylrZzFOtNg/yQ6T7Mgh2cmeshOHZA3c
+ iUYHd8kukPcCHcLFNcTKuFRGnkZcLuMKpsooYHoNLMQMrq6hL4QZ4lqIdIjr
+ IVIhxkKMh7gRIvETuPI3KzoGAAA=
"""
)
@@ -111,7 +111,6 @@
.run()
}
- @Ignore // b/193270279
@Test
fun warnsForSingleExpressions() {
check(
diff --git a/compose/material/material-lint/src/test/java/androidx/compose/material/lint/ColorsDetectorTest.kt b/compose/material/material-lint/src/test/java/androidx/compose/material/lint/ColorsDetectorTest.kt
index 909289a..832a570 100644
--- a/compose/material/material-lint/src/test/java/androidx/compose/material/lint/ColorsDetectorTest.kt
+++ b/compose/material/material-lint/src/test/java/androidx/compose/material/lint/ColorsDetectorTest.kt
@@ -23,7 +23,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -48,10 +47,11 @@
private val ColorsStub = kotlinAndCompiledStub(
filename = "Colors.kt",
filepath = "androidx/compose/material",
+ checksum = 0x2f84988c,
"""
package androidx.compose.material
- import androidx.compose.ui.graphics.Color
+ import androidx.compose.ui.graphics.*
class Colors(
primary: Color,
@@ -127,6 +127,12 @@
false
)
""",
+"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcolmZiXUpSfmVKhl5yfW5BfnKqX
+ m1iSWpSZmCPE4Zyfk19U7F3Cpc4li1OZXlp+vhBbSGpxCVihDIbC0ky99KLE
+ gozM5GIhdrCR3iVKDFoMAMec7K6RAAAA
+ """,
"""
androidx/compose/material/Colors.class:
H4sIAAAAAAAAAJVUTW8TSRB9Pf6YeGzHdownNmGWrwBJgExA3LJCgrArBZnd
@@ -182,12 +188,6 @@
nCcn71K+iVN4l/IDnMbHlJ+TZV9SfsvIHyl9eMWpf4OVgAI7fon8yU6gKovB
LIa4IpclSUayrHFlAsLES7g6gR0mRk1cMxEzcd3kH0vUm4ibtj1hImlCNrHT
RMpEg4lGE70mgibGTAT+BZIgXWjiCwAA
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcolmZiXUpSfmVKhl5yfW5BfnKqX
- m1iSWpSZmCPE4Zyfk19U7F3Cpc4li1OZXlp+vhBbSGpxCVihDIbC0ky99KLE
- gozM5GIhdrCR3iVKDFoMAMec7K6RAAAA
"""
)
@@ -257,7 +257,6 @@
Stubs.Color,
ColorsStub.kotlin
)
- .allowCompilationErrors(true) // b/195443860
.run()
.expect(
"""
@@ -333,7 +332,6 @@
Stubs.Color,
ColorsStub.kotlin
)
- .allowCompilationErrors(true) // b/195443860
.run()
.expect(
"""
@@ -383,7 +381,6 @@
Stubs.Color,
ColorsStub.kotlin
)
- .allowCompilationErrors(true) // b/195443860
.run()
.expect(
"""
@@ -445,7 +442,6 @@
Stubs.Color,
ColorsStub.kotlin
)
- .allowCompilationErrors(true) // b/195443860
.run()
.expectClean()
}
@@ -519,7 +515,6 @@
Stubs.Color,
ColorsStub.kotlin
)
- .allowCompilationErrors(true) // b/195443860
.run()
.expectClean()
}
@@ -596,7 +591,6 @@
.expectClean()
}
- @Ignore // b/193270279
@Test
fun lightColorsErrors_compiled() {
lint().files(
@@ -636,7 +630,6 @@
)
}
- @Ignore // b/193270279
@Test
fun darkColorsErrors_compiled() {
lint().files(
diff --git a/compose/material/material/icons/generator/api/icons.txt b/compose/material/material/icons/generator/api/icons.txt
index 4d0aa35..06f3cb5 100644
--- a/compose/material/material/icons/generator/api/icons.txt
+++ b/compose/material/material/icons/generator/api/icons.txt
@@ -41,6 +41,7 @@
Filled.Addchart
Filled.Adjust
Filled.AdminPanelSettings
+Filled.AdsClick
Filled.Agriculture
Filled.Air
Filled.AirlineSeatFlat
@@ -51,6 +52,8 @@
Filled.AirlineSeatLegroomReduced
Filled.AirlineSeatReclineExtra
Filled.AirlineSeatReclineNormal
+Filled.AirlineStops
+Filled.Airlines
Filled.AirplaneTicket
Filled.AirplanemodeActive
Filled.AirplanemodeInactive
@@ -86,8 +89,10 @@
Filled.AppSettingsAlt
Filled.Approval
Filled.Apps
+Filled.AppsOutage
Filled.Architecture
Filled.Archive
+Filled.AreaChart
Filled.ArrowBack
Filled.ArrowBackIos
Filled.ArrowBackIosNew
@@ -137,6 +142,7 @@
Filled.Autorenew
Filled.AvTimer
Filled.BabyChangingStation
+Filled.BackHand
Filled.Backpack
Filled.Backspace
Filled.Backup
@@ -214,6 +220,7 @@
Filled.BrightnessMedium
Filled.BrokenImage
Filled.BrowserNotSupported
+Filled.BrowserUpdated
Filled.BrunchDining
Filled.Brush
Filled.BubbleChart
@@ -287,6 +294,8 @@
Filled.CheckBoxOutlineBlank
Filled.CheckCircle
Filled.CheckCircleOutline
+Filled.Checklist
+Filled.ChecklistRtl
Filled.Checkroom
Filled.ChevronLeft
Filled.ChevronRight
@@ -312,6 +321,7 @@
Filled.CloudOff
Filled.CloudQueue
Filled.CloudUpload
+Filled.Co2
Filled.Code
Filled.CodeOff
Filled.Coffee
@@ -322,15 +332,18 @@
Filled.Colorize
Filled.Comment
Filled.CommentBank
+Filled.CommentsDisabled
Filled.Commute
Filled.Compare
Filled.CompareArrows
Filled.CompassCalibration
+Filled.Compost
Filled.Compress
Filled.Computer
Filled.ConfirmationNumber
Filled.ConnectWithoutContact
Filled.ConnectedTv
+Filled.ConnectingAirports
Filled.Construction
Filled.ContactMail
Filled.ContactPage
@@ -369,10 +382,12 @@
Filled.CropPortrait
Filled.CropRotate
Filled.CropSquare
+Filled.CrueltyFree
Filled.Dangerous
Filled.DarkMode
Filled.Dashboard
Filled.DashboardCustomize
+Filled.DataExploration
Filled.DataSaverOff
Filled.DataSaverOn
Filled.DataUsage
@@ -422,6 +437,7 @@
Filled.DirectionsWalk
Filled.DirtyLens
Filled.DisabledByDefault
+Filled.DisabledVisible
Filled.DiscFull
Filled.Dns
Filled.DoDisturb
@@ -436,6 +452,7 @@
Filled.DoNotStep
Filled.DoNotTouch
Filled.Dock
+Filled.DocumentScanner
Filled.Domain
Filled.DomainDisabled
Filled.DomainVerification
@@ -457,8 +474,10 @@
Filled.Drafts
Filled.DragHandle
Filled.DragIndicator
+Filled.Draw
Filled.DriveEta
Filled.DriveFileMove
+Filled.DriveFileMoveRtl
Filled.DriveFileRenameOutline
Filled.DriveFolderUpload
Filled.Dry
@@ -476,8 +495,10 @@
Filled.EdgesensorLow
Filled.Edit
Filled.EditAttributes
+Filled.EditCalendar
Filled.EditLocation
Filled.EditLocationAlt
+Filled.EditNote
Filled.EditNotifications
Filled.EditOff
Filled.EditRoad
@@ -491,6 +512,7 @@
Filled.ElectricalServices
Filled.Elevator
Filled.Email
+Filled.Emergency
Filled.EmojiEmotions
Filled.EmojiEvents
Filled.EmojiFlags
@@ -517,6 +539,7 @@
Filled.EventSeat
Filled.ExitToApp
Filled.Expand
+Filled.ExpandCircleDown
Filled.ExpandLess
Filled.ExpandMore
Filled.Explicit
@@ -587,6 +610,7 @@
Filled.Fireplace
Filled.FirstPage
Filled.FitScreen
+Filled.Fitbit
Filled.FitnessCenter
Filled.Flag
Filled.Flaky
@@ -598,6 +622,7 @@
Filled.FlashlightOn
Filled.Flatware
Filled.Flight
+Filled.FlightClass
Filled.FlightLand
Filled.FlightTakeoff
Filled.Flip
@@ -649,6 +674,8 @@
Filled.ForwardToInbox
Filled.Foundation
Filled.FreeBreakfast
+Filled.FreeCancellation
+Filled.FrontHand
Filled.Fullscreen
Filled.FullscreenExit
Filled.Functions
@@ -658,9 +685,11 @@
Filled.Games
Filled.Garage
Filled.Gavel
+Filled.GeneratingTokens
Filled.Gesture
Filled.GetApp
Filled.Gif
+Filled.GifBox
Filled.Gite
Filled.GolfCourse
Filled.GppBad
@@ -683,6 +712,8 @@
Filled.GridView
Filled.Group
Filled.GroupAdd
+Filled.GroupOff
+Filled.GroupRemove
Filled.GroupWork
Filled.Groups
Filled.HMobiledata
@@ -736,6 +767,7 @@
Filled.HorizontalSplit
Filled.HotTub
Filled.Hotel
+Filled.HotelClass
Filled.HourglassBottom
Filled.HourglassDisabled
Filled.HourglassEmpty
@@ -748,6 +780,7 @@
Filled.HowToVote
Filled.Http
Filled.Https
+Filled.Hub
Filled.Hvac
Filled.IceSkating
Filled.Icecream
@@ -760,6 +793,7 @@
Filled.ImportExport
Filled.ImportantDevices
Filled.Inbox
+Filled.IncompleteCircle
Filled.IndeterminateCheckBox
Filled.Info
Filled.Input
@@ -773,6 +807,8 @@
Filled.InsertPhoto
Filled.Insights
Filled.IntegrationInstructions
+Filled.Interests
+Filled.InterpreterMode
Filled.Inventory
Filled.Inventory2
Filled.InvertColors
@@ -781,6 +817,7 @@
Filled.Iron
Filled.Iso
Filled.Kayaking
+Filled.KebabDining
Filled.Keyboard
Filled.KeyboardAlt
Filled.KeyboardArrowDown
@@ -941,6 +978,7 @@
Filled.ModeEdit
Filled.ModeEditOutline
Filled.ModeNight
+Filled.ModeOfTravel
Filled.ModeStandby
Filled.ModelTraining
Filled.MonetizationOn
@@ -991,6 +1029,7 @@
Filled.NetworkCheck
Filled.NetworkLocked
Filled.NetworkWifi
+Filled.NewLabel
Filled.NewReleases
Filled.NextPlan
Filled.NextWeek
@@ -1106,6 +1145,7 @@
Filled.PersonRemove
Filled.PersonRemoveAlt1
Filled.PersonSearch
+Filled.PersonalInjury
Filled.PersonalVideo
Filled.PestControl
Filled.PestControlRodent
@@ -1147,6 +1187,8 @@
Filled.PieChartOutline
Filled.Pin
Filled.PinDrop
+Filled.PinEnd
+Filled.PinInvoke
Filled.PivotTableChart
Filled.Place
Filled.Plagiarism
@@ -1159,6 +1201,8 @@
Filled.PlayLesson
Filled.PlaylistAdd
Filled.PlaylistAddCheck
+Filled.PlaylistAddCheckCircle
+Filled.PlaylistAddCircle
Filled.PlaylistPlay
Filled.Plumbing
Filled.PlusOne
@@ -1185,6 +1229,7 @@
Filled.PrintDisabled
Filled.PriorityHigh
Filled.PrivacyTip
+Filled.PrivateConnectivity
Filled.ProductionQuantityLimits
Filled.Psychology
Filled.Public
@@ -1214,11 +1259,13 @@
Filled.RawOff
Filled.RawOn
Filled.ReadMore
+Filled.RealEstateAgent
Filled.Receipt
Filled.ReceiptLong
Filled.RecentActors
Filled.Recommend
Filled.RecordVoiceOver
+Filled.Recycling
Filled.Redeem
Filled.Redo
Filled.ReduceCapacity
@@ -1413,12 +1460,15 @@
Filled.SocialDistance
Filled.Sort
Filled.SortByAlpha
+Filled.SoupKitchen
Filled.Source
Filled.South
+Filled.SouthAmerica
Filled.SouthEast
Filled.SouthWest
Filled.Spa
Filled.SpaceBar
+Filled.SpaceDashboard
Filled.Speaker
Filled.SpeakerGroup
Filled.SpeakerNotes
@@ -1427,6 +1477,7 @@
Filled.Speed
Filled.Spellcheck
Filled.Splitscreen
+Filled.Spoke
Filled.Sports
Filled.SportsBar
Filled.SportsBaseball
@@ -1498,6 +1549,8 @@
Filled.SwapVert
Filled.SwapVerticalCircle
Filled.Swipe
+Filled.SwitchAccessShortcut
+Filled.SwitchAccessShortcutAdd
Filled.SwitchAccount
Filled.SwitchCamera
Filled.SwitchLeft
@@ -1560,11 +1613,13 @@
Filled.Timer3
Filled.Timer3Select
Filled.TimerOff
+Filled.TipsAndUpdates
Filled.Title
Filled.Toc
Filled.Today
Filled.ToggleOff
Filled.ToggleOn
+Filled.Token
Filled.Toll
Filled.Tonality
Filled.Topic
@@ -1609,6 +1664,7 @@
Filled.UploadFile
Filled.Usb
Filled.UsbOff
+Filled.Vaccines
Filled.Verified
Filled.VerifiedUser
Filled.VerticalAlignBottom
@@ -1666,8 +1722,10 @@
Filled.WatchLater
Filled.Water
Filled.WaterDamage
+Filled.WaterDrop
Filled.WaterfallChart
Filled.Waves
+Filled.WavingHand
Filled.WbAuto
Filled.WbCloudy
Filled.WbIncandescent
@@ -1699,6 +1757,7 @@
Filled.Work
Filled.WorkOff
Filled.WorkOutline
+Filled.WorkspacePremium
Filled.Workspaces
Filled.WrapText
Filled.WrongLocation
@@ -1806,6 +1865,7 @@
Outlined.Addchart
Outlined.Adjust
Outlined.AdminPanelSettings
+Outlined.AdsClick
Outlined.Agriculture
Outlined.Air
Outlined.AirlineSeatFlat
@@ -1816,6 +1876,8 @@
Outlined.AirlineSeatLegroomReduced
Outlined.AirlineSeatReclineExtra
Outlined.AirlineSeatReclineNormal
+Outlined.AirlineStops
+Outlined.Airlines
Outlined.AirplaneTicket
Outlined.AirplanemodeActive
Outlined.AirplanemodeInactive
@@ -1851,8 +1913,10 @@
Outlined.AppSettingsAlt
Outlined.Approval
Outlined.Apps
+Outlined.AppsOutage
Outlined.Architecture
Outlined.Archive
+Outlined.AreaChart
Outlined.ArrowBack
Outlined.ArrowBackIos
Outlined.ArrowBackIosNew
@@ -1902,6 +1966,7 @@
Outlined.Autorenew
Outlined.AvTimer
Outlined.BabyChangingStation
+Outlined.BackHand
Outlined.Backpack
Outlined.Backspace
Outlined.Backup
@@ -1979,6 +2044,7 @@
Outlined.BrightnessMedium
Outlined.BrokenImage
Outlined.BrowserNotSupported
+Outlined.BrowserUpdated
Outlined.BrunchDining
Outlined.Brush
Outlined.BubbleChart
@@ -2052,6 +2118,8 @@
Outlined.CheckBoxOutlineBlank
Outlined.CheckCircle
Outlined.CheckCircleOutline
+Outlined.Checklist
+Outlined.ChecklistRtl
Outlined.Checkroom
Outlined.ChevronLeft
Outlined.ChevronRight
@@ -2077,6 +2145,7 @@
Outlined.CloudOff
Outlined.CloudQueue
Outlined.CloudUpload
+Outlined.Co2
Outlined.Code
Outlined.CodeOff
Outlined.Coffee
@@ -2087,15 +2156,18 @@
Outlined.Colorize
Outlined.Comment
Outlined.CommentBank
+Outlined.CommentsDisabled
Outlined.Commute
Outlined.Compare
Outlined.CompareArrows
Outlined.CompassCalibration
+Outlined.Compost
Outlined.Compress
Outlined.Computer
Outlined.ConfirmationNumber
Outlined.ConnectWithoutContact
Outlined.ConnectedTv
+Outlined.ConnectingAirports
Outlined.Construction
Outlined.ContactMail
Outlined.ContactPage
@@ -2134,10 +2206,12 @@
Outlined.CropPortrait
Outlined.CropRotate
Outlined.CropSquare
+Outlined.CrueltyFree
Outlined.Dangerous
Outlined.DarkMode
Outlined.Dashboard
Outlined.DashboardCustomize
+Outlined.DataExploration
Outlined.DataSaverOff
Outlined.DataSaverOn
Outlined.DataUsage
@@ -2187,6 +2261,7 @@
Outlined.DirectionsWalk
Outlined.DirtyLens
Outlined.DisabledByDefault
+Outlined.DisabledVisible
Outlined.DiscFull
Outlined.Dns
Outlined.DoDisturb
@@ -2201,6 +2276,7 @@
Outlined.DoNotStep
Outlined.DoNotTouch
Outlined.Dock
+Outlined.DocumentScanner
Outlined.Domain
Outlined.DomainDisabled
Outlined.DomainVerification
@@ -2222,8 +2298,10 @@
Outlined.Drafts
Outlined.DragHandle
Outlined.DragIndicator
+Outlined.Draw
Outlined.DriveEta
Outlined.DriveFileMove
+Outlined.DriveFileMoveRtl
Outlined.DriveFileRenameOutline
Outlined.DriveFolderUpload
Outlined.Dry
@@ -2241,8 +2319,10 @@
Outlined.EdgesensorLow
Outlined.Edit
Outlined.EditAttributes
+Outlined.EditCalendar
Outlined.EditLocation
Outlined.EditLocationAlt
+Outlined.EditNote
Outlined.EditNotifications
Outlined.EditOff
Outlined.EditRoad
@@ -2256,6 +2336,7 @@
Outlined.ElectricalServices
Outlined.Elevator
Outlined.Email
+Outlined.Emergency
Outlined.EmojiEmotions
Outlined.EmojiEvents
Outlined.EmojiFlags
@@ -2282,6 +2363,7 @@
Outlined.EventSeat
Outlined.ExitToApp
Outlined.Expand
+Outlined.ExpandCircleDown
Outlined.ExpandLess
Outlined.ExpandMore
Outlined.Explicit
@@ -2352,6 +2434,7 @@
Outlined.Fireplace
Outlined.FirstPage
Outlined.FitScreen
+Outlined.Fitbit
Outlined.FitnessCenter
Outlined.Flag
Outlined.Flaky
@@ -2363,6 +2446,7 @@
Outlined.FlashlightOn
Outlined.Flatware
Outlined.Flight
+Outlined.FlightClass
Outlined.FlightLand
Outlined.FlightTakeoff
Outlined.Flip
@@ -2414,6 +2498,8 @@
Outlined.ForwardToInbox
Outlined.Foundation
Outlined.FreeBreakfast
+Outlined.FreeCancellation
+Outlined.FrontHand
Outlined.Fullscreen
Outlined.FullscreenExit
Outlined.Functions
@@ -2423,9 +2509,11 @@
Outlined.Games
Outlined.Garage
Outlined.Gavel
+Outlined.GeneratingTokens
Outlined.Gesture
Outlined.GetApp
Outlined.Gif
+Outlined.GifBox
Outlined.Gite
Outlined.GolfCourse
Outlined.GppBad
@@ -2448,6 +2536,8 @@
Outlined.GridView
Outlined.Group
Outlined.GroupAdd
+Outlined.GroupOff
+Outlined.GroupRemove
Outlined.GroupWork
Outlined.Groups
Outlined.HMobiledata
@@ -2501,6 +2591,7 @@
Outlined.HorizontalSplit
Outlined.HotTub
Outlined.Hotel
+Outlined.HotelClass
Outlined.HourglassBottom
Outlined.HourglassDisabled
Outlined.HourglassEmpty
@@ -2513,6 +2604,7 @@
Outlined.HowToVote
Outlined.Http
Outlined.Https
+Outlined.Hub
Outlined.Hvac
Outlined.IceSkating
Outlined.Icecream
@@ -2525,6 +2617,7 @@
Outlined.ImportExport
Outlined.ImportantDevices
Outlined.Inbox
+Outlined.IncompleteCircle
Outlined.IndeterminateCheckBox
Outlined.Info
Outlined.Input
@@ -2538,6 +2631,8 @@
Outlined.InsertPhoto
Outlined.Insights
Outlined.IntegrationInstructions
+Outlined.Interests
+Outlined.InterpreterMode
Outlined.Inventory
Outlined.Inventory2
Outlined.InvertColors
@@ -2546,6 +2641,7 @@
Outlined.Iron
Outlined.Iso
Outlined.Kayaking
+Outlined.KebabDining
Outlined.Keyboard
Outlined.KeyboardAlt
Outlined.KeyboardArrowDown
@@ -2706,6 +2802,7 @@
Outlined.ModeEdit
Outlined.ModeEditOutline
Outlined.ModeNight
+Outlined.ModeOfTravel
Outlined.ModeStandby
Outlined.ModelTraining
Outlined.MonetizationOn
@@ -2756,6 +2853,7 @@
Outlined.NetworkCheck
Outlined.NetworkLocked
Outlined.NetworkWifi
+Outlined.NewLabel
Outlined.NewReleases
Outlined.NextPlan
Outlined.NextWeek
@@ -2871,6 +2969,7 @@
Outlined.PersonRemove
Outlined.PersonRemoveAlt1
Outlined.PersonSearch
+Outlined.PersonalInjury
Outlined.PersonalVideo
Outlined.PestControl
Outlined.PestControlRodent
@@ -2912,6 +3011,8 @@
Outlined.PieChartOutline
Outlined.Pin
Outlined.PinDrop
+Outlined.PinEnd
+Outlined.PinInvoke
Outlined.PivotTableChart
Outlined.Place
Outlined.Plagiarism
@@ -2924,6 +3025,8 @@
Outlined.PlayLesson
Outlined.PlaylistAdd
Outlined.PlaylistAddCheck
+Outlined.PlaylistAddCheckCircle
+Outlined.PlaylistAddCircle
Outlined.PlaylistPlay
Outlined.Plumbing
Outlined.PlusOne
@@ -2950,6 +3053,7 @@
Outlined.PrintDisabled
Outlined.PriorityHigh
Outlined.PrivacyTip
+Outlined.PrivateConnectivity
Outlined.ProductionQuantityLimits
Outlined.Psychology
Outlined.Public
@@ -2979,11 +3083,13 @@
Outlined.RawOff
Outlined.RawOn
Outlined.ReadMore
+Outlined.RealEstateAgent
Outlined.Receipt
Outlined.ReceiptLong
Outlined.RecentActors
Outlined.Recommend
Outlined.RecordVoiceOver
+Outlined.Recycling
Outlined.Redeem
Outlined.Redo
Outlined.ReduceCapacity
@@ -3178,12 +3284,15 @@
Outlined.SocialDistance
Outlined.Sort
Outlined.SortByAlpha
+Outlined.SoupKitchen
Outlined.Source
Outlined.South
+Outlined.SouthAmerica
Outlined.SouthEast
Outlined.SouthWest
Outlined.Spa
Outlined.SpaceBar
+Outlined.SpaceDashboard
Outlined.Speaker
Outlined.SpeakerGroup
Outlined.SpeakerNotes
@@ -3192,6 +3301,7 @@
Outlined.Speed
Outlined.Spellcheck
Outlined.Splitscreen
+Outlined.Spoke
Outlined.Sports
Outlined.SportsBar
Outlined.SportsBaseball
@@ -3263,6 +3373,8 @@
Outlined.SwapVert
Outlined.SwapVerticalCircle
Outlined.Swipe
+Outlined.SwitchAccessShortcut
+Outlined.SwitchAccessShortcutAdd
Outlined.SwitchAccount
Outlined.SwitchCamera
Outlined.SwitchLeft
@@ -3325,11 +3437,13 @@
Outlined.Timer3
Outlined.Timer3Select
Outlined.TimerOff
+Outlined.TipsAndUpdates
Outlined.Title
Outlined.Toc
Outlined.Today
Outlined.ToggleOff
Outlined.ToggleOn
+Outlined.Token
Outlined.Toll
Outlined.Tonality
Outlined.Topic
@@ -3374,6 +3488,7 @@
Outlined.UploadFile
Outlined.Usb
Outlined.UsbOff
+Outlined.Vaccines
Outlined.Verified
Outlined.VerifiedUser
Outlined.VerticalAlignBottom
@@ -3431,8 +3546,10 @@
Outlined.WatchLater
Outlined.Water
Outlined.WaterDamage
+Outlined.WaterDrop
Outlined.WaterfallChart
Outlined.Waves
+Outlined.WavingHand
Outlined.WbAuto
Outlined.WbCloudy
Outlined.WbIncandescent
@@ -3464,6 +3581,7 @@
Outlined.Work
Outlined.WorkOff
Outlined.WorkOutline
+Outlined.WorkspacePremium
Outlined.Workspaces
Outlined.WrapText
Outlined.WrongLocation
@@ -3571,6 +3689,7 @@
Rounded.Addchart
Rounded.Adjust
Rounded.AdminPanelSettings
+Rounded.AdsClick
Rounded.Agriculture
Rounded.Air
Rounded.AirlineSeatFlat
@@ -3581,6 +3700,8 @@
Rounded.AirlineSeatLegroomReduced
Rounded.AirlineSeatReclineExtra
Rounded.AirlineSeatReclineNormal
+Rounded.AirlineStops
+Rounded.Airlines
Rounded.AirplaneTicket
Rounded.AirplanemodeActive
Rounded.AirplanemodeInactive
@@ -3616,8 +3737,10 @@
Rounded.AppSettingsAlt
Rounded.Approval
Rounded.Apps
+Rounded.AppsOutage
Rounded.Architecture
Rounded.Archive
+Rounded.AreaChart
Rounded.ArrowBack
Rounded.ArrowBackIos
Rounded.ArrowBackIosNew
@@ -3667,6 +3790,7 @@
Rounded.Autorenew
Rounded.AvTimer
Rounded.BabyChangingStation
+Rounded.BackHand
Rounded.Backpack
Rounded.Backspace
Rounded.Backup
@@ -3744,6 +3868,7 @@
Rounded.BrightnessMedium
Rounded.BrokenImage
Rounded.BrowserNotSupported
+Rounded.BrowserUpdated
Rounded.BrunchDining
Rounded.Brush
Rounded.BubbleChart
@@ -3817,6 +3942,8 @@
Rounded.CheckBoxOutlineBlank
Rounded.CheckCircle
Rounded.CheckCircleOutline
+Rounded.Checklist
+Rounded.ChecklistRtl
Rounded.Checkroom
Rounded.ChevronLeft
Rounded.ChevronRight
@@ -3842,6 +3969,7 @@
Rounded.CloudOff
Rounded.CloudQueue
Rounded.CloudUpload
+Rounded.Co2
Rounded.Code
Rounded.CodeOff
Rounded.Coffee
@@ -3852,15 +3980,18 @@
Rounded.Colorize
Rounded.Comment
Rounded.CommentBank
+Rounded.CommentsDisabled
Rounded.Commute
Rounded.Compare
Rounded.CompareArrows
Rounded.CompassCalibration
+Rounded.Compost
Rounded.Compress
Rounded.Computer
Rounded.ConfirmationNumber
Rounded.ConnectWithoutContact
Rounded.ConnectedTv
+Rounded.ConnectingAirports
Rounded.Construction
Rounded.ContactMail
Rounded.ContactPage
@@ -3899,10 +4030,12 @@
Rounded.CropPortrait
Rounded.CropRotate
Rounded.CropSquare
+Rounded.CrueltyFree
Rounded.Dangerous
Rounded.DarkMode
Rounded.Dashboard
Rounded.DashboardCustomize
+Rounded.DataExploration
Rounded.DataSaverOff
Rounded.DataSaverOn
Rounded.DataUsage
@@ -3952,6 +4085,7 @@
Rounded.DirectionsWalk
Rounded.DirtyLens
Rounded.DisabledByDefault
+Rounded.DisabledVisible
Rounded.DiscFull
Rounded.Dns
Rounded.DoDisturb
@@ -3966,6 +4100,7 @@
Rounded.DoNotStep
Rounded.DoNotTouch
Rounded.Dock
+Rounded.DocumentScanner
Rounded.Domain
Rounded.DomainDisabled
Rounded.DomainVerification
@@ -3987,8 +4122,10 @@
Rounded.Drafts
Rounded.DragHandle
Rounded.DragIndicator
+Rounded.Draw
Rounded.DriveEta
Rounded.DriveFileMove
+Rounded.DriveFileMoveRtl
Rounded.DriveFileRenameOutline
Rounded.DriveFolderUpload
Rounded.Dry
@@ -4006,8 +4143,10 @@
Rounded.EdgesensorLow
Rounded.Edit
Rounded.EditAttributes
+Rounded.EditCalendar
Rounded.EditLocation
Rounded.EditLocationAlt
+Rounded.EditNote
Rounded.EditNotifications
Rounded.EditOff
Rounded.EditRoad
@@ -4021,6 +4160,7 @@
Rounded.ElectricalServices
Rounded.Elevator
Rounded.Email
+Rounded.Emergency
Rounded.EmojiEmotions
Rounded.EmojiEvents
Rounded.EmojiFlags
@@ -4047,6 +4187,7 @@
Rounded.EventSeat
Rounded.ExitToApp
Rounded.Expand
+Rounded.ExpandCircleDown
Rounded.ExpandLess
Rounded.ExpandMore
Rounded.Explicit
@@ -4117,6 +4258,7 @@
Rounded.Fireplace
Rounded.FirstPage
Rounded.FitScreen
+Rounded.Fitbit
Rounded.FitnessCenter
Rounded.Flag
Rounded.Flaky
@@ -4128,6 +4270,7 @@
Rounded.FlashlightOn
Rounded.Flatware
Rounded.Flight
+Rounded.FlightClass
Rounded.FlightLand
Rounded.FlightTakeoff
Rounded.Flip
@@ -4179,6 +4322,8 @@
Rounded.ForwardToInbox
Rounded.Foundation
Rounded.FreeBreakfast
+Rounded.FreeCancellation
+Rounded.FrontHand
Rounded.Fullscreen
Rounded.FullscreenExit
Rounded.Functions
@@ -4188,9 +4333,11 @@
Rounded.Games
Rounded.Garage
Rounded.Gavel
+Rounded.GeneratingTokens
Rounded.Gesture
Rounded.GetApp
Rounded.Gif
+Rounded.GifBox
Rounded.Gite
Rounded.GolfCourse
Rounded.GppBad
@@ -4213,6 +4360,8 @@
Rounded.GridView
Rounded.Group
Rounded.GroupAdd
+Rounded.GroupOff
+Rounded.GroupRemove
Rounded.GroupWork
Rounded.Groups
Rounded.HMobiledata
@@ -4266,6 +4415,7 @@
Rounded.HorizontalSplit
Rounded.HotTub
Rounded.Hotel
+Rounded.HotelClass
Rounded.HourglassBottom
Rounded.HourglassDisabled
Rounded.HourglassEmpty
@@ -4278,6 +4428,7 @@
Rounded.HowToVote
Rounded.Http
Rounded.Https
+Rounded.Hub
Rounded.Hvac
Rounded.IceSkating
Rounded.Icecream
@@ -4290,6 +4441,7 @@
Rounded.ImportExport
Rounded.ImportantDevices
Rounded.Inbox
+Rounded.IncompleteCircle
Rounded.IndeterminateCheckBox
Rounded.Info
Rounded.Input
@@ -4303,6 +4455,8 @@
Rounded.InsertPhoto
Rounded.Insights
Rounded.IntegrationInstructions
+Rounded.Interests
+Rounded.InterpreterMode
Rounded.Inventory
Rounded.Inventory2
Rounded.InvertColors
@@ -4311,6 +4465,7 @@
Rounded.Iron
Rounded.Iso
Rounded.Kayaking
+Rounded.KebabDining
Rounded.Keyboard
Rounded.KeyboardAlt
Rounded.KeyboardArrowDown
@@ -4471,6 +4626,7 @@
Rounded.ModeEdit
Rounded.ModeEditOutline
Rounded.ModeNight
+Rounded.ModeOfTravel
Rounded.ModeStandby
Rounded.ModelTraining
Rounded.MonetizationOn
@@ -4521,6 +4677,7 @@
Rounded.NetworkCheck
Rounded.NetworkLocked
Rounded.NetworkWifi
+Rounded.NewLabel
Rounded.NewReleases
Rounded.NextPlan
Rounded.NextWeek
@@ -4636,6 +4793,7 @@
Rounded.PersonRemove
Rounded.PersonRemoveAlt1
Rounded.PersonSearch
+Rounded.PersonalInjury
Rounded.PersonalVideo
Rounded.PestControl
Rounded.PestControlRodent
@@ -4677,6 +4835,8 @@
Rounded.PieChartOutline
Rounded.Pin
Rounded.PinDrop
+Rounded.PinEnd
+Rounded.PinInvoke
Rounded.PivotTableChart
Rounded.Place
Rounded.Plagiarism
@@ -4689,6 +4849,8 @@
Rounded.PlayLesson
Rounded.PlaylistAdd
Rounded.PlaylistAddCheck
+Rounded.PlaylistAddCheckCircle
+Rounded.PlaylistAddCircle
Rounded.PlaylistPlay
Rounded.Plumbing
Rounded.PlusOne
@@ -4715,6 +4877,7 @@
Rounded.PrintDisabled
Rounded.PriorityHigh
Rounded.PrivacyTip
+Rounded.PrivateConnectivity
Rounded.ProductionQuantityLimits
Rounded.Psychology
Rounded.Public
@@ -4744,11 +4907,13 @@
Rounded.RawOff
Rounded.RawOn
Rounded.ReadMore
+Rounded.RealEstateAgent
Rounded.Receipt
Rounded.ReceiptLong
Rounded.RecentActors
Rounded.Recommend
Rounded.RecordVoiceOver
+Rounded.Recycling
Rounded.Redeem
Rounded.Redo
Rounded.ReduceCapacity
@@ -4943,12 +5108,15 @@
Rounded.SocialDistance
Rounded.Sort
Rounded.SortByAlpha
+Rounded.SoupKitchen
Rounded.Source
Rounded.South
+Rounded.SouthAmerica
Rounded.SouthEast
Rounded.SouthWest
Rounded.Spa
Rounded.SpaceBar
+Rounded.SpaceDashboard
Rounded.Speaker
Rounded.SpeakerGroup
Rounded.SpeakerNotes
@@ -4957,6 +5125,7 @@
Rounded.Speed
Rounded.Spellcheck
Rounded.Splitscreen
+Rounded.Spoke
Rounded.Sports
Rounded.SportsBar
Rounded.SportsBaseball
@@ -5028,6 +5197,8 @@
Rounded.SwapVert
Rounded.SwapVerticalCircle
Rounded.Swipe
+Rounded.SwitchAccessShortcut
+Rounded.SwitchAccessShortcutAdd
Rounded.SwitchAccount
Rounded.SwitchCamera
Rounded.SwitchLeft
@@ -5090,11 +5261,13 @@
Rounded.Timer3
Rounded.Timer3Select
Rounded.TimerOff
+Rounded.TipsAndUpdates
Rounded.Title
Rounded.Toc
Rounded.Today
Rounded.ToggleOff
Rounded.ToggleOn
+Rounded.Token
Rounded.Toll
Rounded.Tonality
Rounded.Topic
@@ -5139,6 +5312,7 @@
Rounded.UploadFile
Rounded.Usb
Rounded.UsbOff
+Rounded.Vaccines
Rounded.Verified
Rounded.VerifiedUser
Rounded.VerticalAlignBottom
@@ -5196,8 +5370,10 @@
Rounded.WatchLater
Rounded.Water
Rounded.WaterDamage
+Rounded.WaterDrop
Rounded.WaterfallChart
Rounded.Waves
+Rounded.WavingHand
Rounded.WbAuto
Rounded.WbCloudy
Rounded.WbIncandescent
@@ -5229,6 +5405,7 @@
Rounded.Work
Rounded.WorkOff
Rounded.WorkOutline
+Rounded.WorkspacePremium
Rounded.Workspaces
Rounded.WrapText
Rounded.WrongLocation
@@ -5336,6 +5513,7 @@
Sharp.Addchart
Sharp.Adjust
Sharp.AdminPanelSettings
+Sharp.AdsClick
Sharp.Agriculture
Sharp.Air
Sharp.AirlineSeatFlat
@@ -5346,6 +5524,8 @@
Sharp.AirlineSeatLegroomReduced
Sharp.AirlineSeatReclineExtra
Sharp.AirlineSeatReclineNormal
+Sharp.AirlineStops
+Sharp.Airlines
Sharp.AirplaneTicket
Sharp.AirplanemodeActive
Sharp.AirplanemodeInactive
@@ -5381,8 +5561,10 @@
Sharp.AppSettingsAlt
Sharp.Approval
Sharp.Apps
+Sharp.AppsOutage
Sharp.Architecture
Sharp.Archive
+Sharp.AreaChart
Sharp.ArrowBack
Sharp.ArrowBackIos
Sharp.ArrowBackIosNew
@@ -5432,6 +5614,7 @@
Sharp.Autorenew
Sharp.AvTimer
Sharp.BabyChangingStation
+Sharp.BackHand
Sharp.Backpack
Sharp.Backspace
Sharp.Backup
@@ -5509,6 +5692,7 @@
Sharp.BrightnessMedium
Sharp.BrokenImage
Sharp.BrowserNotSupported
+Sharp.BrowserUpdated
Sharp.BrunchDining
Sharp.Brush
Sharp.BubbleChart
@@ -5582,6 +5766,8 @@
Sharp.CheckBoxOutlineBlank
Sharp.CheckCircle
Sharp.CheckCircleOutline
+Sharp.Checklist
+Sharp.ChecklistRtl
Sharp.Checkroom
Sharp.ChevronLeft
Sharp.ChevronRight
@@ -5607,6 +5793,7 @@
Sharp.CloudOff
Sharp.CloudQueue
Sharp.CloudUpload
+Sharp.Co2
Sharp.Code
Sharp.CodeOff
Sharp.Coffee
@@ -5617,15 +5804,18 @@
Sharp.Colorize
Sharp.Comment
Sharp.CommentBank
+Sharp.CommentsDisabled
Sharp.Commute
Sharp.Compare
Sharp.CompareArrows
Sharp.CompassCalibration
+Sharp.Compost
Sharp.Compress
Sharp.Computer
Sharp.ConfirmationNumber
Sharp.ConnectWithoutContact
Sharp.ConnectedTv
+Sharp.ConnectingAirports
Sharp.Construction
Sharp.ContactMail
Sharp.ContactPage
@@ -5664,10 +5854,12 @@
Sharp.CropPortrait
Sharp.CropRotate
Sharp.CropSquare
+Sharp.CrueltyFree
Sharp.Dangerous
Sharp.DarkMode
Sharp.Dashboard
Sharp.DashboardCustomize
+Sharp.DataExploration
Sharp.DataSaverOff
Sharp.DataSaverOn
Sharp.DataUsage
@@ -5717,6 +5909,7 @@
Sharp.DirectionsWalk
Sharp.DirtyLens
Sharp.DisabledByDefault
+Sharp.DisabledVisible
Sharp.DiscFull
Sharp.Dns
Sharp.DoDisturb
@@ -5731,6 +5924,7 @@
Sharp.DoNotStep
Sharp.DoNotTouch
Sharp.Dock
+Sharp.DocumentScanner
Sharp.Domain
Sharp.DomainDisabled
Sharp.DomainVerification
@@ -5752,8 +5946,10 @@
Sharp.Drafts
Sharp.DragHandle
Sharp.DragIndicator
+Sharp.Draw
Sharp.DriveEta
Sharp.DriveFileMove
+Sharp.DriveFileMoveRtl
Sharp.DriveFileRenameOutline
Sharp.DriveFolderUpload
Sharp.Dry
@@ -5771,8 +5967,10 @@
Sharp.EdgesensorLow
Sharp.Edit
Sharp.EditAttributes
+Sharp.EditCalendar
Sharp.EditLocation
Sharp.EditLocationAlt
+Sharp.EditNote
Sharp.EditNotifications
Sharp.EditOff
Sharp.EditRoad
@@ -5786,6 +5984,7 @@
Sharp.ElectricalServices
Sharp.Elevator
Sharp.Email
+Sharp.Emergency
Sharp.EmojiEmotions
Sharp.EmojiEvents
Sharp.EmojiFlags
@@ -5812,6 +6011,7 @@
Sharp.EventSeat
Sharp.ExitToApp
Sharp.Expand
+Sharp.ExpandCircleDown
Sharp.ExpandLess
Sharp.ExpandMore
Sharp.Explicit
@@ -5882,6 +6082,7 @@
Sharp.Fireplace
Sharp.FirstPage
Sharp.FitScreen
+Sharp.Fitbit
Sharp.FitnessCenter
Sharp.Flag
Sharp.Flaky
@@ -5893,6 +6094,7 @@
Sharp.FlashlightOn
Sharp.Flatware
Sharp.Flight
+Sharp.FlightClass
Sharp.FlightLand
Sharp.FlightTakeoff
Sharp.Flip
@@ -5944,6 +6146,8 @@
Sharp.ForwardToInbox
Sharp.Foundation
Sharp.FreeBreakfast
+Sharp.FreeCancellation
+Sharp.FrontHand
Sharp.Fullscreen
Sharp.FullscreenExit
Sharp.Functions
@@ -5953,9 +6157,11 @@
Sharp.Games
Sharp.Garage
Sharp.Gavel
+Sharp.GeneratingTokens
Sharp.Gesture
Sharp.GetApp
Sharp.Gif
+Sharp.GifBox
Sharp.Gite
Sharp.GolfCourse
Sharp.GppBad
@@ -5978,6 +6184,8 @@
Sharp.GridView
Sharp.Group
Sharp.GroupAdd
+Sharp.GroupOff
+Sharp.GroupRemove
Sharp.GroupWork
Sharp.Groups
Sharp.HMobiledata
@@ -6031,6 +6239,7 @@
Sharp.HorizontalSplit
Sharp.HotTub
Sharp.Hotel
+Sharp.HotelClass
Sharp.HourglassBottom
Sharp.HourglassDisabled
Sharp.HourglassEmpty
@@ -6043,6 +6252,7 @@
Sharp.HowToVote
Sharp.Http
Sharp.Https
+Sharp.Hub
Sharp.Hvac
Sharp.IceSkating
Sharp.Icecream
@@ -6055,6 +6265,7 @@
Sharp.ImportExport
Sharp.ImportantDevices
Sharp.Inbox
+Sharp.IncompleteCircle
Sharp.IndeterminateCheckBox
Sharp.Info
Sharp.Input
@@ -6068,6 +6279,8 @@
Sharp.InsertPhoto
Sharp.Insights
Sharp.IntegrationInstructions
+Sharp.Interests
+Sharp.InterpreterMode
Sharp.Inventory
Sharp.Inventory2
Sharp.InvertColors
@@ -6076,6 +6289,7 @@
Sharp.Iron
Sharp.Iso
Sharp.Kayaking
+Sharp.KebabDining
Sharp.Keyboard
Sharp.KeyboardAlt
Sharp.KeyboardArrowDown
@@ -6236,6 +6450,7 @@
Sharp.ModeEdit
Sharp.ModeEditOutline
Sharp.ModeNight
+Sharp.ModeOfTravel
Sharp.ModeStandby
Sharp.ModelTraining
Sharp.MonetizationOn
@@ -6286,6 +6501,7 @@
Sharp.NetworkCheck
Sharp.NetworkLocked
Sharp.NetworkWifi
+Sharp.NewLabel
Sharp.NewReleases
Sharp.NextPlan
Sharp.NextWeek
@@ -6401,6 +6617,7 @@
Sharp.PersonRemove
Sharp.PersonRemoveAlt1
Sharp.PersonSearch
+Sharp.PersonalInjury
Sharp.PersonalVideo
Sharp.PestControl
Sharp.PestControlRodent
@@ -6442,6 +6659,8 @@
Sharp.PieChartOutline
Sharp.Pin
Sharp.PinDrop
+Sharp.PinEnd
+Sharp.PinInvoke
Sharp.PivotTableChart
Sharp.Place
Sharp.Plagiarism
@@ -6454,6 +6673,8 @@
Sharp.PlayLesson
Sharp.PlaylistAdd
Sharp.PlaylistAddCheck
+Sharp.PlaylistAddCheckCircle
+Sharp.PlaylistAddCircle
Sharp.PlaylistPlay
Sharp.Plumbing
Sharp.PlusOne
@@ -6480,6 +6701,7 @@
Sharp.PrintDisabled
Sharp.PriorityHigh
Sharp.PrivacyTip
+Sharp.PrivateConnectivity
Sharp.ProductionQuantityLimits
Sharp.Psychology
Sharp.Public
@@ -6509,11 +6731,13 @@
Sharp.RawOff
Sharp.RawOn
Sharp.ReadMore
+Sharp.RealEstateAgent
Sharp.Receipt
Sharp.ReceiptLong
Sharp.RecentActors
Sharp.Recommend
Sharp.RecordVoiceOver
+Sharp.Recycling
Sharp.Redeem
Sharp.Redo
Sharp.ReduceCapacity
@@ -6708,12 +6932,15 @@
Sharp.SocialDistance
Sharp.Sort
Sharp.SortByAlpha
+Sharp.SoupKitchen
Sharp.Source
Sharp.South
+Sharp.SouthAmerica
Sharp.SouthEast
Sharp.SouthWest
Sharp.Spa
Sharp.SpaceBar
+Sharp.SpaceDashboard
Sharp.Speaker
Sharp.SpeakerGroup
Sharp.SpeakerNotes
@@ -6722,6 +6949,7 @@
Sharp.Speed
Sharp.Spellcheck
Sharp.Splitscreen
+Sharp.Spoke
Sharp.Sports
Sharp.SportsBar
Sharp.SportsBaseball
@@ -6793,6 +7021,8 @@
Sharp.SwapVert
Sharp.SwapVerticalCircle
Sharp.Swipe
+Sharp.SwitchAccessShortcut
+Sharp.SwitchAccessShortcutAdd
Sharp.SwitchAccount
Sharp.SwitchCamera
Sharp.SwitchLeft
@@ -6855,11 +7085,13 @@
Sharp.Timer3
Sharp.Timer3Select
Sharp.TimerOff
+Sharp.TipsAndUpdates
Sharp.Title
Sharp.Toc
Sharp.Today
Sharp.ToggleOff
Sharp.ToggleOn
+Sharp.Token
Sharp.Toll
Sharp.Tonality
Sharp.Topic
@@ -6904,6 +7136,7 @@
Sharp.UploadFile
Sharp.Usb
Sharp.UsbOff
+Sharp.Vaccines
Sharp.Verified
Sharp.VerifiedUser
Sharp.VerticalAlignBottom
@@ -6961,8 +7194,10 @@
Sharp.WatchLater
Sharp.Water
Sharp.WaterDamage
+Sharp.WaterDrop
Sharp.WaterfallChart
Sharp.Waves
+Sharp.WavingHand
Sharp.WbAuto
Sharp.WbCloudy
Sharp.WbIncandescent
@@ -6994,6 +7229,7 @@
Sharp.Work
Sharp.WorkOff
Sharp.WorkOutline
+Sharp.WorkspacePremium
Sharp.Workspaces
Sharp.WrapText
Sharp.WrongLocation
@@ -7101,6 +7337,7 @@
TwoTone.Addchart
TwoTone.Adjust
TwoTone.AdminPanelSettings
+TwoTone.AdsClick
TwoTone.Agriculture
TwoTone.Air
TwoTone.AirlineSeatFlat
@@ -7111,6 +7348,8 @@
TwoTone.AirlineSeatLegroomReduced
TwoTone.AirlineSeatReclineExtra
TwoTone.AirlineSeatReclineNormal
+TwoTone.AirlineStops
+TwoTone.Airlines
TwoTone.AirplaneTicket
TwoTone.AirplanemodeActive
TwoTone.AirplanemodeInactive
@@ -7146,8 +7385,10 @@
TwoTone.AppSettingsAlt
TwoTone.Approval
TwoTone.Apps
+TwoTone.AppsOutage
TwoTone.Architecture
TwoTone.Archive
+TwoTone.AreaChart
TwoTone.ArrowBack
TwoTone.ArrowBackIos
TwoTone.ArrowBackIosNew
@@ -7197,6 +7438,7 @@
TwoTone.Autorenew
TwoTone.AvTimer
TwoTone.BabyChangingStation
+TwoTone.BackHand
TwoTone.Backpack
TwoTone.Backspace
TwoTone.Backup
@@ -7274,6 +7516,7 @@
TwoTone.BrightnessMedium
TwoTone.BrokenImage
TwoTone.BrowserNotSupported
+TwoTone.BrowserUpdated
TwoTone.BrunchDining
TwoTone.Brush
TwoTone.BubbleChart
@@ -7347,6 +7590,8 @@
TwoTone.CheckBoxOutlineBlank
TwoTone.CheckCircle
TwoTone.CheckCircleOutline
+TwoTone.Checklist
+TwoTone.ChecklistRtl
TwoTone.Checkroom
TwoTone.ChevronLeft
TwoTone.ChevronRight
@@ -7372,6 +7617,7 @@
TwoTone.CloudOff
TwoTone.CloudQueue
TwoTone.CloudUpload
+TwoTone.Co2
TwoTone.Code
TwoTone.CodeOff
TwoTone.Coffee
@@ -7382,15 +7628,18 @@
TwoTone.Colorize
TwoTone.Comment
TwoTone.CommentBank
+TwoTone.CommentsDisabled
TwoTone.Commute
TwoTone.Compare
TwoTone.CompareArrows
TwoTone.CompassCalibration
+TwoTone.Compost
TwoTone.Compress
TwoTone.Computer
TwoTone.ConfirmationNumber
TwoTone.ConnectWithoutContact
TwoTone.ConnectedTv
+TwoTone.ConnectingAirports
TwoTone.Construction
TwoTone.ContactMail
TwoTone.ContactPage
@@ -7429,10 +7678,12 @@
TwoTone.CropPortrait
TwoTone.CropRotate
TwoTone.CropSquare
+TwoTone.CrueltyFree
TwoTone.Dangerous
TwoTone.DarkMode
TwoTone.Dashboard
TwoTone.DashboardCustomize
+TwoTone.DataExploration
TwoTone.DataSaverOff
TwoTone.DataSaverOn
TwoTone.DataUsage
@@ -7482,6 +7733,7 @@
TwoTone.DirectionsWalk
TwoTone.DirtyLens
TwoTone.DisabledByDefault
+TwoTone.DisabledVisible
TwoTone.DiscFull
TwoTone.Dns
TwoTone.DoDisturb
@@ -7496,6 +7748,7 @@
TwoTone.DoNotStep
TwoTone.DoNotTouch
TwoTone.Dock
+TwoTone.DocumentScanner
TwoTone.Domain
TwoTone.DomainDisabled
TwoTone.DomainVerification
@@ -7517,8 +7770,10 @@
TwoTone.Drafts
TwoTone.DragHandle
TwoTone.DragIndicator
+TwoTone.Draw
TwoTone.DriveEta
TwoTone.DriveFileMove
+TwoTone.DriveFileMoveRtl
TwoTone.DriveFileRenameOutline
TwoTone.DriveFolderUpload
TwoTone.Dry
@@ -7536,8 +7791,10 @@
TwoTone.EdgesensorLow
TwoTone.Edit
TwoTone.EditAttributes
+TwoTone.EditCalendar
TwoTone.EditLocation
TwoTone.EditLocationAlt
+TwoTone.EditNote
TwoTone.EditNotifications
TwoTone.EditOff
TwoTone.EditRoad
@@ -7551,6 +7808,7 @@
TwoTone.ElectricalServices
TwoTone.Elevator
TwoTone.Email
+TwoTone.Emergency
TwoTone.EmojiEmotions
TwoTone.EmojiEvents
TwoTone.EmojiFlags
@@ -7577,6 +7835,7 @@
TwoTone.EventSeat
TwoTone.ExitToApp
TwoTone.Expand
+TwoTone.ExpandCircleDown
TwoTone.ExpandLess
TwoTone.ExpandMore
TwoTone.Explicit
@@ -7647,6 +7906,7 @@
TwoTone.Fireplace
TwoTone.FirstPage
TwoTone.FitScreen
+TwoTone.Fitbit
TwoTone.FitnessCenter
TwoTone.Flag
TwoTone.Flaky
@@ -7658,6 +7918,7 @@
TwoTone.FlashlightOn
TwoTone.Flatware
TwoTone.Flight
+TwoTone.FlightClass
TwoTone.FlightLand
TwoTone.FlightTakeoff
TwoTone.Flip
@@ -7709,6 +7970,8 @@
TwoTone.ForwardToInbox
TwoTone.Foundation
TwoTone.FreeBreakfast
+TwoTone.FreeCancellation
+TwoTone.FrontHand
TwoTone.Fullscreen
TwoTone.FullscreenExit
TwoTone.Functions
@@ -7718,9 +7981,11 @@
TwoTone.Games
TwoTone.Garage
TwoTone.Gavel
+TwoTone.GeneratingTokens
TwoTone.Gesture
TwoTone.GetApp
TwoTone.Gif
+TwoTone.GifBox
TwoTone.Gite
TwoTone.GolfCourse
TwoTone.GppBad
@@ -7743,6 +8008,8 @@
TwoTone.GridView
TwoTone.Group
TwoTone.GroupAdd
+TwoTone.GroupOff
+TwoTone.GroupRemove
TwoTone.GroupWork
TwoTone.Groups
TwoTone.HMobiledata
@@ -7796,6 +8063,7 @@
TwoTone.HorizontalSplit
TwoTone.HotTub
TwoTone.Hotel
+TwoTone.HotelClass
TwoTone.HourglassBottom
TwoTone.HourglassDisabled
TwoTone.HourglassEmpty
@@ -7808,6 +8076,7 @@
TwoTone.HowToVote
TwoTone.Http
TwoTone.Https
+TwoTone.Hub
TwoTone.Hvac
TwoTone.IceSkating
TwoTone.Icecream
@@ -7820,6 +8089,7 @@
TwoTone.ImportExport
TwoTone.ImportantDevices
TwoTone.Inbox
+TwoTone.IncompleteCircle
TwoTone.IndeterminateCheckBox
TwoTone.Info
TwoTone.Input
@@ -7833,6 +8103,8 @@
TwoTone.InsertPhoto
TwoTone.Insights
TwoTone.IntegrationInstructions
+TwoTone.Interests
+TwoTone.InterpreterMode
TwoTone.Inventory
TwoTone.Inventory2
TwoTone.InvertColors
@@ -7841,6 +8113,7 @@
TwoTone.Iron
TwoTone.Iso
TwoTone.Kayaking
+TwoTone.KebabDining
TwoTone.Keyboard
TwoTone.KeyboardAlt
TwoTone.KeyboardArrowDown
@@ -8001,6 +8274,7 @@
TwoTone.ModeEdit
TwoTone.ModeEditOutline
TwoTone.ModeNight
+TwoTone.ModeOfTravel
TwoTone.ModeStandby
TwoTone.ModelTraining
TwoTone.MonetizationOn
@@ -8051,6 +8325,7 @@
TwoTone.NetworkCheck
TwoTone.NetworkLocked
TwoTone.NetworkWifi
+TwoTone.NewLabel
TwoTone.NewReleases
TwoTone.NextPlan
TwoTone.NextWeek
@@ -8166,6 +8441,7 @@
TwoTone.PersonRemove
TwoTone.PersonRemoveAlt1
TwoTone.PersonSearch
+TwoTone.PersonalInjury
TwoTone.PersonalVideo
TwoTone.PestControl
TwoTone.PestControlRodent
@@ -8207,6 +8483,8 @@
TwoTone.PieChartOutline
TwoTone.Pin
TwoTone.PinDrop
+TwoTone.PinEnd
+TwoTone.PinInvoke
TwoTone.PivotTableChart
TwoTone.Place
TwoTone.Plagiarism
@@ -8219,6 +8497,8 @@
TwoTone.PlayLesson
TwoTone.PlaylistAdd
TwoTone.PlaylistAddCheck
+TwoTone.PlaylistAddCheckCircle
+TwoTone.PlaylistAddCircle
TwoTone.PlaylistPlay
TwoTone.Plumbing
TwoTone.PlusOne
@@ -8245,6 +8525,7 @@
TwoTone.PrintDisabled
TwoTone.PriorityHigh
TwoTone.PrivacyTip
+TwoTone.PrivateConnectivity
TwoTone.ProductionQuantityLimits
TwoTone.Psychology
TwoTone.Public
@@ -8274,11 +8555,13 @@
TwoTone.RawOff
TwoTone.RawOn
TwoTone.ReadMore
+TwoTone.RealEstateAgent
TwoTone.Receipt
TwoTone.ReceiptLong
TwoTone.RecentActors
TwoTone.Recommend
TwoTone.RecordVoiceOver
+TwoTone.Recycling
TwoTone.Redeem
TwoTone.Redo
TwoTone.ReduceCapacity
@@ -8473,12 +8756,15 @@
TwoTone.SocialDistance
TwoTone.Sort
TwoTone.SortByAlpha
+TwoTone.SoupKitchen
TwoTone.Source
TwoTone.South
+TwoTone.SouthAmerica
TwoTone.SouthEast
TwoTone.SouthWest
TwoTone.Spa
TwoTone.SpaceBar
+TwoTone.SpaceDashboard
TwoTone.Speaker
TwoTone.SpeakerGroup
TwoTone.SpeakerNotes
@@ -8487,6 +8773,7 @@
TwoTone.Speed
TwoTone.Spellcheck
TwoTone.Splitscreen
+TwoTone.Spoke
TwoTone.Sports
TwoTone.SportsBar
TwoTone.SportsBaseball
@@ -8558,6 +8845,8 @@
TwoTone.SwapVert
TwoTone.SwapVerticalCircle
TwoTone.Swipe
+TwoTone.SwitchAccessShortcut
+TwoTone.SwitchAccessShortcutAdd
TwoTone.SwitchAccount
TwoTone.SwitchCamera
TwoTone.SwitchLeft
@@ -8620,11 +8909,13 @@
TwoTone.Timer3
TwoTone.Timer3Select
TwoTone.TimerOff
+TwoTone.TipsAndUpdates
TwoTone.Title
TwoTone.Toc
TwoTone.Today
TwoTone.ToggleOff
TwoTone.ToggleOn
+TwoTone.Token
TwoTone.Toll
TwoTone.Tonality
TwoTone.Topic
@@ -8669,6 +8960,7 @@
TwoTone.UploadFile
TwoTone.Usb
TwoTone.UsbOff
+TwoTone.Vaccines
TwoTone.Verified
TwoTone.VerifiedUser
TwoTone.VerticalAlignBottom
@@ -8726,8 +9018,10 @@
TwoTone.WatchLater
TwoTone.Water
TwoTone.WaterDamage
+TwoTone.WaterDrop
TwoTone.WaterfallChart
TwoTone.Waves
+TwoTone.WavingHand
TwoTone.WbAuto
TwoTone.WbCloudy
TwoTone.WbIncandescent
@@ -8759,6 +9053,7 @@
TwoTone.Work
TwoTone.WorkOff
TwoTone.WorkOutline
+TwoTone.WorkspacePremium
TwoTone.Workspaces
TwoTone.WrapText
TwoTone.WrongLocation
diff --git a/compose/material/material/icons/generator/raw-icons/filled/ads_click.xml b/compose/material/material/icons/generator/raw-icons/filled/ads_click.xml
new file mode 100644
index 0000000..79f2284
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/ads_click.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.71,17.99C8.53,17.84 6,15.22 6,12c0,-3.31 2.69,-6 6,-6c3.22,0 5.84,2.53 5.99,5.71l-2.1,-0.63C15.48,9.31 13.89,8 12,8c-2.21,0 -4,1.79 -4,4c0,1.89 1.31,3.48 3.08,3.89L11.71,17.99zM22,12c0,0.3 -0.01,0.6 -0.04,0.9l-1.97,-0.59C20,12.21 20,12.1 20,12c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8s3.58,8 8,8c0.1,0 0.21,0 0.31,-0.01l0.59,1.97C12.6,21.99 12.3,22 12,22C6.48,22 2,17.52 2,12C2,6.48 6.48,2 12,2S22,6.48 22,12zM18.23,16.26L22,15l-10,-3l3,10l1.26,-3.77l4.27,4.27l1.98,-1.98L18.23,16.26z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/airline_stops.xml b/compose/material/material/icons/generator/raw-icons/filled/airline_stops.xml
new file mode 100644
index 0000000..f3b3692
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/airline_stops.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.21,9.21C15.93,10.78 13.45,13.3 13,17h2v2H9v-2h2c-0.5,-4.5 -4.37,-8 -9,-8V7c4.39,0 8.22,2.55 10,6.3c1.13,-2.43 2.99,-4.25 4.78,-5.52L14,5h7v7L18.21,9.21z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/airlines.xml b/compose/material/material/icons/generator/raw-icons/filled/airlines.xml
new file mode 100644
index 0000000..e578a22
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/airlines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,4L2,20h17l3,-16H13zM14.5,14c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C17,12.88 15.88,14 14.5,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/apps_outage.xml b/compose/material/material/icons/generator/raw-icons/filled/apps_outage.xml
new file mode 100644
index 0000000..bd84f8b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/apps_outage.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4,8h4V4H4V8zM10,20h4v-4h-4V20zM4,20h4v-4H4V20zM4,14h4v-4H4V14zM10,14h4v-4h-4V14zM16,20h4v-4h-4V20zM19,0c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S21.76,0 19,0zM19.5,8h-1V7h1V8zM19.5,6h-1V2h1V6zM16,14h4v-2.07C19.67,11.98 19.34,12 19,12c-1.07,0 -2.09,-0.24 -3,-0.68V14zM10,4v4h2.68C12.24,7.09 12,6.07 12,5c0,-0.34 0.02,-0.67 0.07,-1H10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/area_chart.xml b/compose/material/material/icons/generator/raw-icons/filled/area_chart.xml
new file mode 100644
index 0000000..1572332
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/area_chart.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,13v7h18v-1.5l-9,-7L8,17L3,13zM3,7l4,3l5,-7l5,4h4v8.97l-9.4,-7.31l-3.98,5.48L3,10.44V7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/arrow_forward_ios.xml b/compose/material/material/icons/generator/raw-icons/filled/arrow_forward_ios.xml
index e0b83d0..a71005d 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/arrow_forward_ios.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/arrow_forward_ios.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.88,4.12L13.76,12l-7.88,7.88L8,22l10,-10L8,2z"/>
+ android:pathData="M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/back_hand.xml b/compose/material/material/icons/generator/raw-icons/filled/back_hand.xml
new file mode 100644
index 0000000..83d8cf71
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/back_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,24c-3.26,0 -6.19,-1.99 -7.4,-5.02l-3.03,-7.61C2.26,10.58 3,9.79 3.81,10.05l0.79,0.26c0.56,0.18 1.02,0.61 1.24,1.16L7.25,15H8V3.25C8,2.56 8.56,2 9.25,2s1.25,0.56 1.25,1.25V12h1V1.25C11.5,0.56 12.06,0 12.75,0S14,0.56 14,1.25V12h1V2.75c0,-0.69 0.56,-1.25 1.25,-1.25c0.69,0 1.25,0.56 1.25,1.25V12h1V5.75c0,-0.69 0.56,-1.25 1.25,-1.25S21,5.06 21,5.75V16C21,20.42 17.42,24 13,24z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/browser_updated.xml b/compose/material/material/icons/generator/raw-icons/filled/browser_updated.xml
new file mode 100644
index 0000000..44147da
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/browser_updated.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,13v3c0,1.1 -0.9,2 -2,2h-3l1,1v2H6v-2l1,-1H4c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2l8,0v2L4,5v11h16v-3H22zM15,15l-5,-5h4V3h2v7h4L15,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/checklist.xml b/compose/material/material/icons/generator/raw-icons/filled/checklist.xml
new file mode 100644
index 0000000..64e7ee3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/checklist.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,7h-9v2h9V7zM22,15h-9v2h9V15zM5.54,11L2,7.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,11zM5.54,19L2,15.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/checklist_rtl.xml b/compose/material/material/icons/generator/raw-icons/filled/checklist_rtl.xml
new file mode 100644
index 0000000..eb4422c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/checklist_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,7H2v2h9V7zM11,15H2v2h9V15zM16.34,11l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,5.34L16.34,11zM16.34,19l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,13.34L16.34,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/co2.xml b/compose/material/material/icons/generator/raw-icons/filled/co2.xml
new file mode 100644
index 0000000..28a144a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/co2.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,9h-3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-4C15,9.45 14.55,9 14,9zM13.5,13.5h-2v-3h2V13.5zM8,13v1c0,0.55 -0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v1H6.5v-0.5h-2v3h2V13H8zM20.5,15.5h-2v1h3V18H17v-2.5c0,-0.55 0.45,-1 1,-1h2v-1h-3V12h3.5c0.55,0 1,0.45 1,1v1.5C21.5,15.05 21.05,15.5 20.5,15.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/comments_disabled.xml b/compose/material/material/icons/generator/raw-icons/filled/comments_disabled.xml
new file mode 100644
index 0000000..6e41c58
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/comments_disabled.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.83,14H18v-2h-3.17l-1,-1H18V9h-6.17l-1,-1H18V6H8.83l-4,-4H20c1.1,0 2,0.9 2,2v15.17L16.83,14zM2.1,2.1L0.69,3.51L2,4.83V16c0,1.1 0.9,2 2,2h11.17l5.31,5.31l1.41,-1.41L2.1,2.1zM6,9h0.17l2,2H6V9zM6,14v-2h3.17l2,2H6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/compost.xml b/compose/material/material/icons/generator/raw-icons/filled/compost.xml
new file mode 100644
index 0000000..b06253a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/compost.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.87,11.81c-0.23,-0.38 -0.37,-0.83 -0.37,-1.31C12.5,9.12 13.62,8 15,8l1,0c1.51,0 2,-1 2,-1s0.55,6 -3,6c-0.49,0 -0.94,-0.14 -1.32,-0.38c-0.24,0.64 -0.59,1.76 -0.76,2.96c1.26,0.22 2.28,0.89 2.77,1.77c1.69,-1.17 2.81,-3.13 2.81,-5.35h3c0,5.24 -4.26,9.5 -9.5,9.5S2.5,17.24 2.5,12S6.76,2.5 12,2.5V0l4,4l-4,4V5.5c-3.58,0 -6.5,2.92 -6.5,6.5c0,2.21 1.11,4.17 2.81,5.35c0.51,-0.92 1.63,-1.62 2.98,-1.8c-0.09,-0.69 -0.26,-1.42 -0.49,-2.03C10.45,13.82 10,14 9.5,14c-1.1,0 -2,-0.9 -2,-2v-0.99c0,-0.56 -0.19,-1.09 -0.5,-1.51c0,0 4.45,-0.23 4.5,2.5c0,0.29 -0.06,0.56 -0.17,0.8C10.91,12.48 10.47,12.2 10,12c0.58,0.43 1.37,1.37 2,2.6c0.67,-1.62 1.68,-3.27 3,-4.6C14.24,10.52 13.53,11.12 12.87,11.81z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/connecting_airports.xml b/compose/material/material/icons/generator/raw-icons/filled/connecting_airports.xml
new file mode 100644
index 0000000..12357c5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/connecting_airports.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.4,17l1.3,4.4h-1.1L13,17h-3c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h3l2.6,-4.4h1.1L15.4,15h2.85L19,14h1l-0.6,2l0.6,2h-1l-0.75,-1H15.4zM5.75,7L5,6H4l0.6,2L4,10h1l0.75,-1H8.6l-1.3,4.4h1.1L11,9h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L8.4,2.6H7.3L8.6,7H5.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/cruelty_free.xml b/compose/material/material/icons/generator/raw-icons/filled/cruelty_free.xml
new file mode 100644
index 0000000..4fc1fef
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/cruelty_free.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.84,14.52c-0.26,-0.19 -0.62,-0.63 -0.79,-0.84C17.24,12.01 19,8.87 19,5c0,-1.95 -0.74,-3 -2,-3c-1.54,0 -3.96,2.06 -5,5.97C10.96,4.06 8.54,2 7,2C5.74,2 5,3.05 5,5c0,3.87 1.76,7.01 2.95,8.68c-0.17,0.21 -0.53,0.65 -0.79,0.84c-0.5,0.41 -1.66,1.37 -1.66,2.98c0,2.21 1.79,4 4,4c1.55,0 2.5,-0.56 2.5,-0.56s0.95,0.56 2.5,0.56c2.21,0 4,-1.79 4,-4C18.5,15.89 17.34,14.93 16.84,14.52zM9.35,12.2C8.34,10.7 7,8.12 7,5c0,-0.49 0.06,-0.8 0.12,-0.97c0.94,0.31 3.24,2.71 3.38,7.64C10.03,11.79 9.66,11.97 9.35,12.2zM10.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S11,15.59 11,16C11,16.41 10.78,16.75 10.5,16.75zM12,19.5c-0.55,0 -1,-0.72 -1,-1c0,-0.28 0.45,-0.5 1,-0.5s1,0.22 1,0.5C13,18.78 12.55,19.5 12,19.5zM13.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S14,15.59 14,16C14,16.41 13.78,16.75 13.5,16.75zM13.5,11.67c0.14,-4.93 2.44,-7.33 3.38,-7.64C16.94,4.2 17,4.51 17,5c0,3.12 -1.34,5.7 -2.35,7.2C14.34,11.97 13.97,11.79 13.5,11.67z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/data_exploration.xml b/compose/material/material/icons/generator/raw-icons/filled/data_exploration.xml
new file mode 100644
index 0000000..d0abfdd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/data_exploration.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,1.33 0.26,2.61 0.74,3.77L8,10.5l3.3,2.78L14.58,10H13V8h5v5h-2v-1.58L11.41,16l-3.29,-2.79l-4.4,4.4C5.52,20.26 8.56,22 12,22h8c1.1,0 2,-0.9 2,-2v-8C22,6.48 17.52,2 12,2zM19.5,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.05,20.5 19.5,20.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/disabled_visible.xml b/compose/material/material/icons/generator/raw-icons/filled/disabled_visible.xml
new file mode 100644
index 0000000..dfeb407
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/disabled_visible.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21.99,12.34C22,12.23 22,12.11 22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12c0,5.17 3.93,9.43 8.96,9.95c-0.93,-0.73 -1.72,-1.64 -2.32,-2.68C5.9,18 4,15.22 4,12c0,-1.85 0.63,-3.55 1.69,-4.9l5.66,5.66c0.56,-0.4 1.17,-0.73 1.82,-1L7.1,5.69C8.45,4.63 10.15,4 12,4c4.24,0 7.7,3.29 7.98,7.45C20.69,11.67 21.37,11.97 21.99,12.34zM17,13c-3.18,0 -5.9,1.87 -7,4.5c1.1,2.63 3.82,4.5 7,4.5s5.9,-1.87 7,-4.5C22.9,14.87 20.18,13 17,13zM17,20c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C19.5,18.88 18.38,20 17,20zM18.5,17.5c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5S18.5,16.67 18.5,17.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/document_scanner.xml b/compose/material/material/icons/generator/raw-icons/filled/document_scanner.xml
new file mode 100644
index 0000000..24daa20
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/document_scanner.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,3H4v3H2V1h5V3zM22,6V1h-5v2h3v3H22zM7,21H4v-3H2v5h5V21zM20,18v3h-3v2h5v-5H20zM19,18c0,1.1 -0.9,2 -2,2H7c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10c1.1,0 2,0.9 2,2V18zM15,8H9v2h6V8zM15,11H9v2h6V11zM15,14H9v2h6V14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/draw.xml b/compose/material/material/icons/generator/raw-icons/filled/draw.xml
new file mode 100644
index 0000000..1a5c1e6
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/draw.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.85,10.39l1.06,-1.06c0.78,-0.78 0.78,-2.05 0,-2.83L18.5,5.09c-0.78,-0.78 -2.05,-0.78 -2.83,0l-1.06,1.06L18.85,10.39zM13.19,7.56L4,16.76V21h4.24l9.19,-9.19L13.19,7.56zM19,17.5c0,2.19 -2.54,3.5 -5,3.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1c1.54,0 3,-0.73 3,-1.5c0,-0.47 -0.48,-0.87 -1.23,-1.2l1.48,-1.48C18.32,15.45 19,16.29 19,17.5zM4.58,13.35C3.61,12.79 3,12.06 3,11c0,-1.8 1.89,-2.63 3.56,-3.36C7.59,7.18 9,6.56 9,6c0,-0.41 -0.78,-1 -2,-1C5.74,5 5.2,5.61 5.17,5.64C4.82,6.05 4.19,6.1 3.77,5.76C3.36,5.42 3.28,4.81 3.62,4.38C3.73,4.24 4.76,3 7,3c2.24,0 4,1.32 4,3c0,1.87 -1.93,2.72 -3.64,3.47C6.42,9.88 5,10.5 5,11c0,0.31 0.43,0.6 1.07,0.86L4.58,13.35z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/drive_file_move_rtl.xml b/compose/material/material/icons/generator/raw-icons/filled/drive_file_move_rtl.xml
new file mode 100644
index 0000000..c654468
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/drive_file_move_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,6h-8l-2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM12,17l-4,-4l4,-4v3h4v2h-4V17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/edit_calendar.xml b/compose/material/material/icons/generator/raw-icons/filled/edit_calendar.xml
new file mode 100644
index 0000000..94f975a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/edit_calendar.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,22H5c-1.11,0 -2,-0.9 -2,-2L3.01,6c0,-1.1 0.88,-2 1.99,-2h1V2h2v2h8V2h2v2h1c1.1,0 2,0.9 2,2v6h-2v-2H5v10h7V22zM22.13,16.99l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41l-0.71,-0.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71L22.13,16.99zM21.42,17.7l-5.3,5.3H14v-2.12l5.3,-5.3L21.42,17.7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/edit_note.xml b/compose/material/material/icons/generator/raw-icons/filled/edit_note.xml
new file mode 100644
index 0000000..1641196
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/edit_note.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/emergency.xml b/compose/material/material/icons/generator/raw-icons/filled/emergency.xml
new file mode 100644
index 0000000..0c5a61b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/emergency.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.79,9.23l-2,-3.46l-4.79,2.77l0,-5.54l-4,0l0,5.54l-4.79,-2.77l-2,3.46l4.79,2.77l-4.79,2.77l2,3.46l4.79,-2.77l0,5.54l4,0l0,-5.54l4.79,2.77l2,-3.46l-4.79,-2.77z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/expand_circle_down.xml b/compose/material/material/icons/generator/raw-icons/filled/expand_circle_down.xml
new file mode 100644
index 0000000..0ce65fd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/expand_circle_down.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,15.5L7.5,11l1.42,-1.41L12,12.67l3.08,-3.08L16.5,11L12,15.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/fitbit.xml b/compose/material/material/icons/generator/raw-icons/filled/fitbit.xml
new file mode 100644
index 0000000..da71490
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/fitbit.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.89,13.89c1.04,0 1.89,-0.85 1.89,-1.89s-0.85,-1.89 -1.89,-1.89C18.85,10.11 18,10.96 18,12S18.85,13.89 19.89,13.89zM15.65,13.68c0.93,0 1.68,-0.75 1.68,-1.68s-0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68S14.72,13.68 15.65,13.68zM15.65,9.42c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,8.67 14.72,9.42 15.65,9.42zM15.65,17.93c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,17.17 14.72,17.93 15.65,17.93zM11.41,13.47c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,13.47 11.41,13.47zM11.41,9.21c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,9.21 11.41,9.21zM11.41,17.73c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,17.07 10.59,17.73 11.41,17.73zM11.41,22c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,21.34 10.59,22 11.41,22zM11.41,4.94c0.81,0 1.47,-0.66 1.47,-1.47S12.22,2 11.41,2c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,4.94 11.41,4.94zM7.16,13.26c0.7,0 1.26,-0.57 1.26,-1.26s-0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26S6.46,13.26 7.16,13.26zM7.16,17.51c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,16.94 6.46,17.51 7.16,17.51zM7.16,9.02c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,8.45 6.46,9.02 7.16,9.02zM3.29,13.05c0.58,0 1.05,-0.47 1.05,-1.05s-0.47,-1.05 -1.05,-1.05c-0.58,0 -1.05,0.47 -1.05,1.05S2.71,13.05 3.29,13.05z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/flight_class.xml b/compose/material/material/icons/generator/raw-icons/filled/flight_class.xml
new file mode 100644
index 0000000..37879ec
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/flight_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,4h-2c-1.1,0 -2,0.9 -2,2v5c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2V6C18,4.9 17.1,4 16,4zM9.5,16H18v2H9.49c-0.88,0 -1.66,-0.58 -1.92,-1.43L5,8V4h2v4L9.5,16zM8,19h10v2H8V19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/free_cancellation.xml b/compose/material/material/icons/generator/raw-icons/filled/free_cancellation.xml
new file mode 100644
index 0000000..81d1879
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/free_cancellation.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.21,20H5V10h14v4.38l2,-2V6c0,-1.1 -0.9,-2 -2,-2h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h8.21L11.21,20zM16.54,22.5L13,18.96l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L16.54,22.5zM10.41,14L12,15.59L10.59,17L9,15.41L7.41,17L6,15.59L7.59,14L6,12.41L7.41,11L9,12.59L10.59,11L12,12.41L10.41,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/front_hand.xml b/compose/material/material/icons/generator/raw-icons/filled/front_hand.xml
new file mode 100644
index 0000000..a67ffbc
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/front_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.75,8c-0.69,0 -1.25,0.56 -1.25,1.25V15H18c-1.65,0 -3,1.35 -3,3h-1c0,-2.04 1.53,-3.72 3.5,-3.97l0,-10.78C17.5,2.56 16.94,2 16.25,2C15.56,2 15,2.56 15,3.25V11h-1V1.25C14,0.56 13.44,0 12.75,0S11.5,0.56 11.5,1.25V11h-1V2.75c0,-0.69 -0.56,-1.25 -1.25,-1.25S8,2.06 8,2.75V12H7V5.75C7,5.06 6.44,4.5 5.75,4.5S4.5,5.06 4.5,5.75v10c0,4.56 3.69,8.25 8.25,8.25S21,20.31 21,15.75v-6.5C21,8.56 20.44,8 19.75,8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/generating_tokens.xml b/compose/material/material/icons/generator/raw-icons/filled/generating_tokens.xml
new file mode 100644
index 0000000..8f331f3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/generating_tokens.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8C17,7.58 13.42,4 9,4zM12,10.5h-2v5H8v-5H6V9h6V10.5zM20.25,3.75L23,5l-2.75,1.25L19,9l-1.25,-2.75L15,5l2.75,-1.25L19,1L20.25,3.75zM20.25,17.75L23,19l-2.75,1.25L19,23l-1.25,-2.75L15,19l2.75,-1.25L19,15L20.25,17.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/gif_box.xml b/compose/material/material/icons/generator/raw-icons/filled/gif_box.xml
new file mode 100644
index 0000000..4654004
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/gif_box.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM9.5,13v-1h1v1c0,0.55 -0.45,1 -1,1h-1c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1h1c0.55,0 1,0.45 1,1h-2v2H9.5zM12.5,14h-1v-4h1V14zM16.5,11h-2v0.5H16v1h-1.5V14h-1v-4h3V11z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/group_add.xml b/compose/material/material/icons/generator/raw-icons/filled/group_add.xml
index c187a0f..2ab0b72 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/group_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/group_add.xml
@@ -6,5 +6,17 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,10L5,10L5,7L3,7v3L0,10v2h3v3h2v-3h3v-2zM18,11c1.66,0 2.99,-1.34 2.99,-3S19.66,5 18,5c-0.32,0 -0.63,0.05 -0.91,0.14 0.57,0.81 0.9,1.79 0.9,2.86s-0.34,2.04 -0.9,2.86c0.28,0.09 0.59,0.14 0.91,0.14zM13,11c1.66,0 2.99,-1.34 2.99,-3S14.66,5 13,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM19.62,13.16c0.83,0.73 1.38,1.66 1.38,2.84v2h3v-2c0,-1.54 -2.37,-2.49 -4.38,-2.84zM13,13c-2,0 -6,1 -6,3v2h12v-2c0,-2 -4,-3 -6,-3z"/>
+ android:pathData="M22,9l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0l0,-2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4S4,5.79 4,8S5.79,12 8,12z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/group_off.xml b/compose/material/material/icons/generator/raw-icons/filled/group_off.xml
new file mode 100644
index 0000000..6868f1d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/group_off.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.06,0 -0.12,0 -0.18,0l-0.77,-0.77C14.65,10.29 15,9.18 15,8zM22.83,20H23v-3c0,-2.18 -3.58,-3.47 -6.34,-3.87c1.1,0.75 1.95,1.71 2.23,2.94L22.83,20zM7.24,4.41C7.77,4.15 8.37,4 9,4c2.21,0 4,1.79 4,4c0,0.63 -0.15,1.23 -0.41,1.76L7.24,4.41zM9.17,12C9.11,12 9.06,12 9,12c-2.21,0 -4,-1.79 -4,-4c0,-0.06 0,-0.11 0,-0.17L0.69,3.51L2.1,2.1l19.8,19.8l-1.41,1.41L17,19.83V20H1v-3c0,-2.66 5.33,-4 8,-4c0.37,0 0.8,0.03 1.25,0.08L9.17,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/group_remove.xml b/compose/material/material/icons/generator/raw-icons/filled/group_remove.xml
new file mode 100644
index 0000000..c71530e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/group_remove.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,9v2h-6V9H24zM8,4C5.79,4 4,5.79 4,8s1.79,4 4,4s4,-1.79 4,-4S10.21,4 8,4zM8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13zM12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05zM16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/hotel_class.xml b/compose/material/material/icons/generator/raw-icons/filled/hotel_class.xml
new file mode 100644
index 0000000..b2aecb9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/hotel_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.58,10H1l6.17,4.41L4.83,22L11,17.31L17.18,22l-2.35,-7.59L21,10h-7.58L11,2L8.58,10zM21.36,22l-1.86,-6.01L23.68,13h-3.44l-3.08,2.2l1.46,4.72L21.36,22zM17,8l-1.82,-6l-1.04,3.45L14.91,8H17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/hub.xml b/compose/material/material/icons/generator/raw-icons/filled/hub.xml
new file mode 100644
index 0000000..fedb1a7
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/hub.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.4,18.2C8.78,18.7 9,19.32 9,20c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3s1.34,-3 3,-3c0.44,0 0.85,0.09 1.23,0.26l1.41,-1.77c-0.92,-1.03 -1.29,-2.39 -1.09,-3.69l-2.03,-0.68C4.98,11.95 4.06,12.5 3,12.5c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3c0,0.07 0,0.14 -0.01,0.21l2.03,0.68c0.64,-1.21 1.82,-2.09 3.22,-2.32l0,-2.16C9.96,5.57 9,4.4 9,3c0,-1.66 1.34,-3 3,-3s3,1.34 3,3c0,1.4 -0.96,2.57 -2.25,2.91v2.16c1.4,0.23 2.58,1.11 3.22,2.32l2.03,-0.68C18,9.64 18,9.57 18,9.5c0,-1.66 1.34,-3 3,-3s3,1.34 3,3s-1.34,3 -3,3c-1.06,0 -1.98,-0.55 -2.52,-1.37l-2.03,0.68c0.2,1.29 -0.16,2.65 -1.09,3.69l1.41,1.77C17.15,17.09 17.56,17 18,17c1.66,0 3,1.34 3,3s-1.34,3 -3,3s-3,-1.34 -3,-3c0,-0.68 0.22,-1.3 0.6,-1.8l-1.41,-1.77c-1.35,0.75 -3.01,0.76 -4.37,0L8.4,18.2z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/incomplete_circle.xml b/compose/material/material/icons/generator/raw-icons/filled/incomplete_circle.xml
new file mode 100644
index 0000000..e7e6e41
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/incomplete_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12c0,5.52 -4.48,10 -10,10S2,17.52 2,12c0,-2.76 1.12,-5.26 2.93,-7.07L12,12V2C17.52,2 22,6.48 22,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/interests.xml b/compose/material/material/icons/generator/raw-icons/filled/interests.xml
new file mode 100644
index 0000000..ab45afd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/interests.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.02,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.23,13 7.02,13zM13,13v8h8v-8H13zM7,2l-5,9h10L7,2zM19.25,2.5c-1.06,0 -1.81,0.56 -2.25,1.17c-0.44,-0.61 -1.19,-1.17 -2.25,-1.17C13.19,2.5 12,3.78 12,5.25c0,2 2.42,3.42 5,5.75c2.58,-2.33 5,-3.75 5,-5.75C22,3.78 20.81,2.5 19.25,2.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/interpreter_mode.xml b/compose/material/material/icons/generator/raw-icons/filled/interpreter_mode.xml
new file mode 100644
index 0000000..f5c71e2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/interpreter_mode.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.5,16.5c-0.83,0 -1.5,-0.67 -1.5,-1.5v-2.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5V15C22,15.83 21.33,16.5 20.5,16.5zM20,20h1c0,0 0,-1.54 0,-1.54c1.69,-0.24 3,-1.7 3,-3.46h-1c0,1.38 -1.12,2.5 -2.5,2.5S18,16.38 18,15h-1c0,1.76 1.31,3.22 3,3.46C20,18.46 20,20 20,20zM9,12c-2.21,0 -4,-1.79 -4,-4c0,-2.21 1.79,-4 4,-4c0.47,0 0.92,0.08 1.34,0.23C9.5,5.26 9,6.57 9,8c0,1.43 0.5,2.74 1.34,3.77C9.92,11.92 9.47,12 9,12zM7.11,13.13C5.79,14.05 5,15.57 5,17.22V20H1v-2.78c0,-1.12 0.61,-2.15 1.61,-2.66C3.85,13.92 5.37,13.37 7.11,13.13zM11,8c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S11,10.21 11,8zM18.32,20c-1.67,-0.81 -2.82,-2.52 -2.82,-4.5c0,-0.89 0.23,-1.73 0.64,-2.45C15.77,13.02 15.39,13 15,13c-2.53,0 -4.71,0.7 -6.39,1.56C7.61,15.07 7,16.1 7,17.22V20L18.32,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/kebab_dining.xml b/compose/material/material/icons/generator/raw-icons/filled/kebab_dining.xml
new file mode 100644
index 0000000..6e9774a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/kebab_dining.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.75,8H11v5H7.75v1H8.5c1.38,0 2.5,1.12 2.5,2.5c0,1.38 -1.12,2.5 -2.5,2.5H7.75v4h-1.5v-4H5.5C4.12,19 3,17.88 3,16.5C3,15.12 4.12,14 5.5,14h0.75v-1H3V8h3.25V7H5.5C4.12,7 3,5.88 3,4.5C3,3.12 4.12,2 5.5,2h0.75V1h1.5v1H8.5C9.88,2 11,3.12 11,4.5C11,5.88 9.88,7 8.5,7H7.75V8zM17.75,7h0.75C19.88,7 21,5.88 21,4.5C21,3.12 19.88,2 18.5,2h-0.75V1h-1.5v1H15.5C14.12,2 13,3.12 13,4.5C13,5.88 14.12,7 15.5,7h0.75v1H13v5h3.25v1H15.5c-1.38,0 -2.5,1.12 -2.5,2.5c0,1.38 1.12,2.5 2.5,2.5h0.75v4h1.5v-4h0.75c1.38,0 2.5,-1.12 2.5,-2.5c0,-1.38 -1.12,-2.5 -2.5,-2.5h-0.75v-1H21V8h-3.25V7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/mode_of_travel.xml b/compose/material/material/icons/generator/raw-icons/filled/mode_of_travel.xml
new file mode 100644
index 0000000..1cc03da
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/mode_of_travel.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.31,18.9c-0.96,1 -2.06,2.03 -3.31,3.1c-5.33,-4.55 -8,-8.48 -8,-11.8C4,5.22 7.8,2 12,2c4,0 7.64,2.92 7.97,7.5l3.53,0L19,14l-4.5,-4.5l3.47,0C17.65,6.24 15.13,4 12,4c-3.35,0 -6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14c0.64,-0.59 1.23,-1.16 1.77,-1.71c-0.17,-0.34 -0.27,-0.72 -0.27,-1.12c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S17.38,19 16,19C15.76,19 15.53,18.97 15.31,18.9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/new_label.xml b/compose/material/material/icons/generator/raw-icons/filled/new_label.xml
new file mode 100644
index 0000000..8a512a72
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/new_label.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,12l-4.37,6.16C16.26,18.68 15.65,19 15,19h-3l0,-6H9v-3H3V7c0,-1.1 0.9,-2 2,-2h10c0.65,0 1.26,0.31 1.63,0.84L21,12zM10,15H7v-3H5v3H2v2h3v3h2v-3h3V15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/palette.xml b/compose/material/material/icons/generator/raw-icons/filled/palette.xml
index 4bf1550..0d97f03 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/palette.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/palette.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
+ android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10c1.38,0 2.5,-1.12 2.5,-2.5c0,-0.61 -0.23,-1.2 -0.64,-1.67c-0.08,-0.1 -0.13,-0.21 -0.13,-0.33c0,-0.28 0.22,-0.5 0.5,-0.5H16c3.31,0 6,-2.69 6,-6C22,6.04 17.51,2 12,2zM17.5,13c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C19,12.33 18.33,13 17.5,13zM14.5,9C13.67,9 13,8.33 13,7.5C13,6.67 13.67,6 14.5,6S16,6.67 16,7.5C16,8.33 15.33,9 14.5,9zM5,11.5C5,10.67 5.67,10 6.5,10S8,10.67 8,11.5C8,12.33 7.33,13 6.5,13S5,12.33 5,11.5zM11,7.5C11,8.33 10.33,9 9.5,9S8,8.33 8,7.5C8,6.67 8.67,6 9.5,6S11,6.67 11,7.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/personal_injury.xml b/compose/material/material/icons/generator/raw-icons/filled/personal_injury.xml
new file mode 100644
index 0000000..22c5d7b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/personal_injury.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,6c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S8,8.21 8,6zM17,22h1c1.1,0 2,-0.9 2,-2l0,-4.78c0,-1.12 -0.61,-2.15 -1.61,-2.66c-0.43,-0.22 -0.9,-0.43 -1.39,-0.62L17,22zM12.34,17L15,11.33C14.07,11.12 13.07,11 12,11c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,13.07 4,14.1 4,15.22L4,22h2.34C6.12,21.55 6,21.04 6,20.5C6,18.57 7.57,17 9.5,17H12.34zM10,22l1.41,-3H9.5C8.67,19 8,19.67 8,20.5S8.67,22 9.5,22H10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/phone_locked.xml b/compose/material/material/icons/generator/raw-icons/filled/phone_locked.xml
index 7156953..7fe553c 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/phone_locked.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/phone_locked.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15.5c-1.25,0 -2.45,-0.2 -3.57,-0.57 -0.35,-0.11 -0.74,-0.03 -1.02,0.24l-2.2,2.2c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l2.2,-2.21c0.28,-0.26 0.36,-0.65 0.25,-1C8.7,6.45 8.5,5.25 8.5,4c0,-0.55 -0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1 0,9.39 7.61,17 17,17 0.55,0 1,-0.45 1,-1v-3.5c0,-0.55 -0.45,-1 -1,-1zM20,4v-0.5C20,2.12 18.88,1 17.5,1S15,2.12 15,3.5L15,4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1L21,5c0,-0.55 -0.45,-1 -1,-1zM19.2,4h-3.4v-0.5c0,-0.94 0.76,-1.7 1.7,-1.7s1.7,0.76 1.7,1.7L19.2,4z"/>
+ android:pathData="M20,5V4c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v1h-1v5h6V5H20zM19,5h-2V4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/photo_album.xml b/compose/material/material/icons/generator/raw-icons/filled/photo_album.xml
index 369a068..651a56d 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/photo_album.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/photo_album.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2L6,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM6,4h5v8l-2.5,-1.5L6,12L6,4zM6,19l3,-3.86 2.14,2.58 3,-3.86L18,19L6,19z"/>
+ android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM11,4h5v7l-2.5,-1.5L11,11V4zM7,18l2.38,-3.17L11,17l2.62,-3.5L17,18H7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/pin_end.xml b/compose/material/material/icons/generator/raw-icons/filled/pin_end.xml
new file mode 100644
index 0000000..070e4b9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/pin_end.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,12V6H4v12h10l0,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h16c1.1,0 2,0.9 2,2v6H20zM19,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c1.66,0 3,-1.34 3,-3S20.66,14 19,14zM14.66,8H9v5.66l2.12,-2.12l2.83,2.83l1.41,-1.41l-2.83,-2.83L14.66,8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/pin_invoke.xml b/compose/material/material/icons/generator/raw-icons/filled/pin_invoke.xml
new file mode 100644
index 0000000..6e78fb0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/pin_invoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12v6c0,1.1 -0.9,2 -2,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10l0,2H4v12h16v-6H22zM22,7c0,-1.66 -1.34,-3 -3,-3c-1.66,0 -3,1.34 -3,3s1.34,3 3,3C20.66,10 22,8.66 22,7zM11.47,12.12l-2.83,2.83l1.41,1.41l2.83,-2.83L15,15.66V10H9.34L11.47,12.12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/playlist_add_check_circle.xml b/compose/material/material/icons/generator/raw-icons/filled/playlist_add_check_circle.xml
new file mode 100644
index 0000000..1c67620
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/playlist_add_check_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM7,7h7v2H7V7zM7,10h7v2H7V10zM10,15H7v-2h3V15zM14.05,18.36l-2.83,-2.83l1.41,-1.41l1.41,1.41L17.59,12L19,13.41L14.05,18.36z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/playlist_add_circle.xml b/compose/material/material/icons/generator/raw-icons/filled/playlist_add_circle.xml
new file mode 100644
index 0000000..c2a7236
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/playlist_add_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7,7h7v2H7V7zM10,15H7v-2h3V15zM7,12v-2h7v2H7zM19,15h-2v2h-2v-2h-2v-2h2v-2h2v2h2V15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/private_connectivity.xml b/compose/material/material/icons/generator/raw-icons/filled/private_connectivity.xml
new file mode 100644
index 0000000..c291d3f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/private_connectivity.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.93,11c-0.49,-3.39 -3.4,-6 -6.93,-6s-6.44,2.61 -6.93,6H2v2h3.07c0.49,3.39 3.4,6 6.93,6s6.44,-2.61 6.93,-6H22v-2H18.93zM15,14.5c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1v-1c0,-1.21 1.08,-2.18 2.34,-1.97C13.32,7.69 14,8.61 14,9.61v0.89c0.55,0 1,0.45 1,1V14.5zM12.75,13c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75c0,-0.41 0.34,-0.75 0.75,-0.75S12.75,12.59 12.75,13zM13,9.5v1h-2v-1c0,-0.55 0.45,-1 1,-1S13,8.95 13,9.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/real_estate_agent.xml b/compose/material/material/icons/generator/raw-icons/filled/real_estate_agent.xml
new file mode 100644
index 0000000..68e6037
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/real_estate_agent.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M1,22h4V11H1V22zM20,17h-7l-2.09,-0.73l0.33,-0.94L13,16h2.82c0.65,0 1.18,-0.53 1.18,-1.18l0,0c0,-0.49 -0.31,-0.93 -0.77,-1.11L8.97,11H7v9.02L14,22l8,-3l0,0C21.99,17.9 21.11,17 20,17zM14,1.5l-7,5V9h2l8.14,3.26C18.26,12.71 19,13.79 19,15h2V6.5L14,1.5zM13.5,10h-1V9h1V10zM13.5,8h-1V7h1V8zM15.5,10h-1V9h1V10zM15.5,8h-1V7h1V8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/recycling.xml b/compose/material/material/icons/generator/raw-icons/filled/recycling.xml
new file mode 100644
index 0000000..bd30b8a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/recycling.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5.77,7.15L7.2,4.78l1.03,-1.71c0.39,-0.65 1.33,-0.65 1.72,0l1.48,2.46l-1.23,2.06L9.2,9.21L5.77,7.15zM21.72,12.97l-1.6,-2.66l-3.46,2L18.87,16H20c0.76,0 1.45,-0.43 1.79,-1.11C21.93,14.61 22,14.31 22,14C22,13.64 21.9,13.29 21.72,12.97zM16,21h1.5c0.76,0 1.45,-0.43 1.79,-1.11L20.74,17H16v-2l-4,4l4,4V21zM10,17H5.7l-0.84,1.41c-0.3,0.5 -0.32,1.12 -0.06,1.65l0,0C5.08,20.63 5.67,21 6.32,21H10V17zM6.12,14.35l1.73,1.04L6.48,9.9L1,11.27l1.7,1.02l-0.41,0.69c-0.35,0.59 -0.38,1.31 -0.07,1.92l1.63,3.26L6.12,14.35zM17.02,5.14l-1.3,-2.17C15.35,2.37 14.7,2 14,2h-3.53l3.12,5.2l-1.72,1.03l5.49,1.37l1.37,-5.49L17.02,5.14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/soup_kitchen.xml b/compose/material/material/icons/generator/raw-icons/filled/soup_kitchen.xml
new file mode 100644
index 0000000..e55da21
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/soup_kitchen.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.4,7C6.06,7.55 6,7.97 6,8.38C6,9.15 7,11 7,12c0,0.95 -0.4,1.5 -0.4,1.5H5.1c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62C4.5,7.97 4.56,7.55 4.9,7H6.4zM11.4,7C11.06,7.55 11,7.97 11,8.38C11,9.15 12,11 12,12c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H11.4zM8.15,7c-0.34,0.55 -0.4,0.97 -0.4,1.38c0,0.77 1,2.63 1,3.62c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H8.15zM21.47,6.5c0,0 0.13,-1.06 0.13,-1.5c0,-1.65 -1.35,-3 -3,-3c-1.54,0 -2.81,1.16 -2.98,2.65L14.53,15H4.01c-0.6,0 -1.09,0.53 -1,1.13C3.53,19.46 6.39,22 9.75,22c3.48,0 6.34,-2.73 6.71,-6.23l1.15,-10.87C17.66,4.39 18.08,4 18.6,4c0.55,0 1,0.45 1,1c0,0.3 -0.1,1.25 -0.1,1.25L21.47,6.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/south_america.xml b/compose/material/material/icons/generator/raw-icons/filled/south_america.xml
new file mode 100644
index 0000000..ca13a97
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/south_america.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM4,12c0,-1.95 0.7,-3.74 1.87,-5.13L9,10v1c0,1.1 0.9,2 2,2v5.59c0,0.27 0.11,0.52 0.29,0.71L12,20C7.58,20 4,16.42 4,12zM13,19.94V18l3.75,-5.62c0.16,-0.25 0.25,-0.54 0.25,-0.83V10.5c0,-0.55 -0.45,-1 -1,-1h-1.5l-1.4,-1.75C12.72,7.28 12.15,7 11.54,7H8V5.07C9.18,4.39 10.54,4 12,4c4.41,0 8,3.59 8,8C20,16.07 16.94,19.44 13,19.94z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/space_dashboard.xml b/compose/material/material/icons/generator/raw-icons/filled/space_dashboard.xml
new file mode 100644
index 0000000..a14b2ea
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/space_dashboard.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,21H5c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h6V21zM13,21h6c1.1,0 2,-0.9 2,-2v-7h-8V21zM21,10V5c0,-1.1 -0.9,-2 -2,-2h-6v7H21z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/spoke.xml b/compose/material/material/icons/generator/raw-icons/filled/spoke.xml
new file mode 100644
index 0000000..b271345
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/spoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,7c0,2.21 -1.79,4 -4,4S8,9.21 8,7s1.79,-4 4,-4S16,4.79 16,7zM7,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.21,13 7,13zM17,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S19.21,13 17,13z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/stop_circle.xml b/compose/material/material/icons/generator/raw-icons/filled/stop_circle.xml
index e0cf569..a25ea07 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/stop_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/stop_circle.xml
@@ -6,6 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,16h8V8H8V16zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2L12,2z"
- android:fillType="evenOdd"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM16,16H8V8h8V16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/switch_access_shortcut.xml b/compose/material/material/icons/generator/raw-icons/filled/switch_access_shortcut.xml
new file mode 100644
index 0000000..6c27e1c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/switch_access_shortcut.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-2.73 1.08,-5.27 2.75,-7.25L12,2h7v7l-2.82,-2.82C14.84,7.82 14,9.88 14,12c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/switch_access_shortcut_add.xml b/compose/material/material/icons/generator/raw-icons/filled/switch_access_shortcut_add.xml
new file mode 100644
index 0000000..84b07f9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/switch_access_shortcut_add.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,14h-2v-2h-2v2h-2v2h2v2h2v-2h2V14zM7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-2.73 1.08,-5.27 2.75,-7.25L12,2h7v7l-2.82,-2.82C14.84,7.82 14,9.88 14,12c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/sync_alt.xml b/compose/material/material/icons/generator/raw-icons/filled/sync_alt.xml
index f899b57..360b6a2 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/sync_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/sync_alt.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,8l-4,-4v3H3v2h15v3L22,8z"/>
+ android:pathData="M18,12l4,-4l-4,-4l0,3l-15,0l0,2l15,0z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M2,16l4,4v-3h15v-2H6v-3L2,16z"/>
+ android:pathData="M6,12l-4,4l4,4l0,-3l15,0l0,-2l-15,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/tips_and_updates.xml b/compose/material/material/icons/generator/raw-icons/filled/tips_and_updates.xml
new file mode 100644
index 0000000..93d5882
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/tips_and_updates.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,19h8v-2H5V19zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/token.xml b/compose/material/material/icons/generator/raw-icons/filled/token.xml
new file mode 100644
index 0000000..b43943e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/token.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.97,6.43L12,2L4.03,6.43L9.1,9.24C9.83,8.48 10.86,8 12,8s2.17,0.48 2.9,1.24L19.97,6.43zM10,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2s-0.9,2 -2,2S10,13.1 10,12zM11,21.44L3,17V8.14l5.13,2.85C8.04,11.31 8,11.65 8,12c0,1.86 1.27,3.43 3,3.87V21.44zM13,21.44v-5.57c1.73,-0.44 3,-2.01 3,-3.87c0,-0.35 -0.04,-0.69 -0.13,-1.01L21,8.14L21,17L13,21.44z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/vaccines.xml b/compose/material/material/icons/generator/raw-icons/filled/vaccines.xml
new file mode 100644
index 0000000..6ec33a2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/vaccines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,5.5H8V4h0.5c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1H6v1.5H3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1V15c0,1.1 0.9,2 2,2h1v4l2,1.5V17h1c1.1,0 2,-0.9 2,-2V7.5c0.55,0 1,-0.45 1,-1C12,5.95 11.55,5.5 11,5.5zM9,9H7.25C6.84,9 6.5,9.34 6.5,9.75c0,0.41 0.34,0.75 0.75,0.75H9V12H7.25c-0.41,0 -0.75,0.34 -0.75,0.75c0,0.41 0.34,0.75 0.75,0.75H9L9,15H5V7.5h4V9zM19.5,10.5V10c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-5c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1v0.5c0,0.5 -1.5,1.16 -1.5,3V20c0,1.1 0.9,2 2,2h4c1.1,0 2,-0.9 2,-2v-6.5C21,11.66 19.5,11 19.5,10.5zM16.5,10.5V10h1v0.5c0,1.6 1.5,2 1.5,3V14h-4c0,-0.21 0,-0.39 0,-0.5C15,12.5 16.5,12.1 16.5,10.5zM15,20c0,0 0,-0.63 0,-1.5h4V20H15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_agenda.xml b/compose/material/material/icons/generator/raw-icons/filled/view_agenda.xml
index 238ff4d..18e3342 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_agenda.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_agenda.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,13L3,13c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1zM20,3L3,3c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1z"/>
+ android:pathData="M19,13H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4C21,13.9 20.1,13 19,13z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_array.xml b/compose/material/material/icons/generator/raw-icons/filled/view_array.xml
index b7a7cb9..0fa8195 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_array.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_array.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h3V5H4v13zM18,5v13h3V5h-3zM8,18h9V5H8v13z"/>
+ android:pathData="M21,5h-3v14h3V5zM17,5H7v14h10V5zM6,5H3v14h3V5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_carousel.xml b/compose/material/material/icons/generator/raw-icons/filled/view_carousel.xml
index c045023..838b749 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_carousel.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_carousel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,19h10L17,4L7,4v15zM2,17h4L6,6L2,6v11zM18,6v11h4L22,6h-4z"/>
+ android:pathData="M2,7h4v10H2V7zM7,19h10V5H7V19zM18,7h4v10h-4V7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_column.xml b/compose/material/material/icons/generator/raw-icons/filled/view_column.xml
index 7d8a647..49d8ddc 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_column.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_column.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,18h5L15,5h-5v13zM4,18h5L9,5L4,5v13zM16,5v13h5L21,5h-5z"/>
+ android:pathData="M14.67,5v14H9.33V5H14.67zM15.67,19H21V5h-5.33V19zM8.33,19V5H3v14H8.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_list.xml b/compose/material/material/icons/generator/raw-icons/filled/view_list.xml
index 37ffb91..4510516 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_list.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_list.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,14h4v-4L4,10v4zM4,19h4v-4L4,15v4zM4,9h4L8,5L4,5v4zM9,14h12v-4L9,10v4zM9,19h12v-4L9,15v4zM9,5v4h12L21,5L9,5z"/>
+ android:pathData="M3,14h4v-4H3V14zM3,19h4v-4H3V19zM3,9h4V5H3V9zM8,14h13v-4H8V14zM8,19h13v-4H8V19zM8,5v4h13V5H8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_module.xml b/compose/material/material/icons/generator/raw-icons/filled/view_module.xml
index 78298cd..56ca7a8 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_module.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_module.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,11h5L9,5L4,5v6zM4,18h5v-6L4,12v6zM10,18h5v-6h-5v6zM16,18h5v-6h-5v6zM10,11h5L15,5h-5v6zM16,5v6h5L21,5h-5z"/>
+ android:pathData="M14.67,5v6.5H9.33V5H14.67zM15.67,11.5H21V5h-5.33V11.5zM14.67,19v-6.5H9.33V19H14.67zM15.67,12.5V19H21v-6.5H15.67zM8.33,12.5H3V19h5.33V12.5zM8.33,11.5V5H3v6.5H8.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_quilt.xml b/compose/material/material/icons/generator/raw-icons/filled/view_quilt.xml
index f128c20..bf98fe5 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_quilt.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_quilt.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,18h5v-6h-5v6zM4,18h5L9,5L4,5v13zM16,18h5v-6h-5v6zM10,5v6h11L21,5L10,5z"/>
+ android:pathData="M21,5v6.5H9.33V5H21zM14.67,19v-6.5H9.33V19H14.67zM15.67,12.5V19H21v-6.5H15.67zM8.33,19V5H3v14H8.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_stream.xml b/compose/material/material/icons/generator/raw-icons/filled/view_stream.xml
index 3906c772..06bf209 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_stream.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_stream.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h17v-6H4v6zM4,5v6h17V5H4z"/>
+ android:pathData="M3,17v-2c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2v2c0,1.1 -0.9,2 -2,2H5C3.9,19 3,18.1 3,17zM3,7v2c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H5C3.9,5 3,5.9 3,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/view_week.xml b/compose/material/material/icons/generator/raw-icons/filled/view_week.xml
index c5c2047..2cc8d6e 100644
--- a/compose/material/material/icons/generator/raw-icons/filled/view_week.xml
+++ b/compose/material/material/icons/generator/raw-icons/filled/view_week.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,5L3,5c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1L7,6c0,-0.55 -0.45,-1 -1,-1zM20,5h-3c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1L21,6c0,-0.55 -0.45,-1 -1,-1zM13,5h-3c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1L14,6c0,-0.55 -0.45,-1 -1,-1z"/>
+ android:pathData="M5.33,20H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h1.33c1.1,0 2,0.9 2,2v12C7.33,19.1 6.44,20 5.33,20zM22,18V6c0,-1.1 -0.9,-2 -2,-2h-1.33c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2H20C21.11,20 22,19.1 22,18zM14.67,18V6c0,-1.1 -0.9,-2 -2,-2h-1.33c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h1.33C13.77,20 14.67,19.1 14.67,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/water_drop.xml b/compose/material/material/icons/generator/raw-icons/filled/water_drop.xml
new file mode 100644
index 0000000..9883980
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/water_drop.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2c-5.33,4.55 -8,8.48 -8,11.8c0,4.98 3.8,8.2 8,8.2s8,-3.22 8,-8.2C20,10.48 17.33,6.55 12,2zM7.83,14c0.37,0 0.67,0.26 0.74,0.62c0.41,2.22 2.28,2.98 3.64,2.87c0.43,-0.02 0.79,0.32 0.79,0.75c0,0.4 -0.32,0.73 -0.72,0.75c-2.13,0.13 -4.62,-1.09 -5.19,-4.12C7.01,14.42 7.37,14 7.83,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/waving_hand.xml b/compose/material/material/icons/generator/raw-icons/filled/waving_hand.xml
new file mode 100644
index 0000000..afe0200
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/waving_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M23,17c0,3.31 -2.69,6 -6,6v-1.5c2.48,0 4.5,-2.02 4.5,-4.5H23zM1,7c0,-3.31 2.69,-6 6,-6v1.5C4.52,2.5 2.5,4.52 2.5,7H1zM8.01,4.32l-4.6,4.6c-3.22,3.22 -3.22,8.45 0,11.67s8.45,3.22 11.67,0l7.07,-7.07c0.49,-0.49 0.49,-1.28 0,-1.77c-0.49,-0.49 -1.28,-0.49 -1.77,0l-4.42,4.42l-0.71,-0.71l6.54,-6.54c0.49,-0.49 0.49,-1.28 0,-1.77s-1.28,-0.49 -1.77,0l-5.83,5.83l-0.71,-0.71l6.89,-6.89c0.49,-0.49 0.49,-1.28 0,-1.77s-1.28,-0.49 -1.77,0l-6.89,6.89L11.02,9.8l5.48,-5.48c0.49,-0.49 0.49,-1.28 0,-1.77s-1.28,-0.49 -1.77,0l-7.62,7.62c1.22,1.57 1.11,3.84 -0.33,5.28l-0.71,-0.71c1.17,-1.17 1.17,-3.07 0,-4.24l-0.35,-0.35l4.07,-4.07c0.49,-0.49 0.49,-1.28 0,-1.77C9.29,3.83 8.5,3.83 8.01,4.32z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/filled/workspace_premium.xml b/compose/material/material/icons/generator/raw-icons/filled/workspace_premium.xml
new file mode 100644
index 0000000..41420c0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/filled/workspace_premium.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9.68,13.69L12,11.93l2.31,1.76l-0.88,-2.85L15.75,9h-2.84L12,6.19L11.09,9H8.25l2.31,1.84L9.68,13.69zM20,10c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8c0,2.03 0.76,3.87 2,5.28V23l6,-2l6,2v-7.72C19.24,13.87 20,12.03 20,10zM12,4c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6S8.69,4 12,4z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/ads_click.xml b/compose/material/material/icons/generator/raw-icons/outlined/ads_click.xml
new file mode 100644
index 0000000..79f2284
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/ads_click.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.71,17.99C8.53,17.84 6,15.22 6,12c0,-3.31 2.69,-6 6,-6c3.22,0 5.84,2.53 5.99,5.71l-2.1,-0.63C15.48,9.31 13.89,8 12,8c-2.21,0 -4,1.79 -4,4c0,1.89 1.31,3.48 3.08,3.89L11.71,17.99zM22,12c0,0.3 -0.01,0.6 -0.04,0.9l-1.97,-0.59C20,12.21 20,12.1 20,12c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8s3.58,8 8,8c0.1,0 0.21,0 0.31,-0.01l0.59,1.97C12.6,21.99 12.3,22 12,22C6.48,22 2,17.52 2,12C2,6.48 6.48,2 12,2S22,6.48 22,12zM18.23,16.26L22,15l-10,-3l3,10l1.26,-3.77l4.27,4.27l1.98,-1.98L18.23,16.26z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/airline_stops.xml b/compose/material/material/icons/generator/raw-icons/outlined/airline_stops.xml
new file mode 100644
index 0000000..20f26a1
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/airline_stops.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,8.7c-2.46,1.5 -5.5,4.17 -6,8.3h2v2H9v-2h2c-0.5,-4.5 -4.37,-8 -9,-8V7c4.39,0 8.22,2.55 10,6.3c1.38,-2.97 3.86,-5.03 5.96,-6.31L14,7V5h7v7h-2V8.7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/airlines.xml b/compose/material/material/icons/generator/raw-icons/outlined/airlines.xml
new file mode 100644
index 0000000..3a1c4ad
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/airlines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.34,18H5.8l8.25,-12h5.54L17.34,18zM13,4L2,20h17l3,-16H13zM14.5,9c-1.38,0 -2.5,1.12 -2.5,2.5s1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5S15.88,9 14.5,9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/android.xml b/compose/material/material/icons/generator/raw-icons/outlined/android.xml
index bf91766..28c533f 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/android.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/android.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71s-0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
+ android:pathData="M17.6,9.48l1.84,-3.18c0.16,-0.31 0.04,-0.69 -0.26,-0.85c-0.29,-0.15 -0.65,-0.06 -0.83,0.22l-1.88,3.24c-2.86,-1.21 -6.08,-1.21 -8.94,0L5.65,5.67c-0.19,-0.29 -0.58,-0.38 -0.87,-0.2C4.5,5.65 4.41,6.01 4.56,6.3L6.4,9.48C3.3,11.25 1.28,14.44 1,18h22C22.72,14.44 20.7,11.25 17.6,9.48zM7,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25S8.25,13.31 8.25,14C8.25,14.69 7.69,15.25 7,15.25zM17,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25C18.25,14.69 17.69,15.25 17,15.25z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/apps_outage.xml b/compose/material/material/icons/generator/raw-icons/outlined/apps_outage.xml
new file mode 100644
index 0000000..bd84f8b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/apps_outage.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4,8h4V4H4V8zM10,20h4v-4h-4V20zM4,20h4v-4H4V20zM4,14h4v-4H4V14zM10,14h4v-4h-4V14zM16,20h4v-4h-4V20zM19,0c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S21.76,0 19,0zM19.5,8h-1V7h1V8zM19.5,6h-1V2h1V6zM16,14h4v-2.07C19.67,11.98 19.34,12 19,12c-1.07,0 -2.09,-0.24 -3,-0.68V14zM10,4v4h2.68C12.24,7.09 12,6.07 12,5c0,-0.34 0.02,-0.67 0.07,-1H10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/area_chart.xml b/compose/material/material/icons/generator/raw-icons/outlined/area_chart.xml
new file mode 100644
index 0000000..063099fe
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/area_chart.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17,7l-5,-4l-5,7L3,7v13h18V7H17zM19,16.95l-7,-5.45L8,17l-3,-2.4V11l2.44,1.83l4.96,-6.95L16.3,9H19V16.95z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/arrow_forward_ios.xml b/compose/material/material/icons/generator/raw-icons/outlined/arrow_forward_ios.xml
index f9d6a55..a71005d 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/arrow_forward_ios.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/arrow_forward_ios.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.49,20.13l1.77,1.77 9.9,-9.9 -9.9,-9.9 -1.77,1.77L14.62,12l-8.13,8.13z"/>
+ android:pathData="M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/back_hand.xml b/compose/material/material/icons/generator/raw-icons/outlined/back_hand.xml
new file mode 100644
index 0000000..c057564
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/back_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,7c0,-1.38 -1.12,-2.5 -2.5,-2.5c-0.17,0 -0.34,0.02 -0.5,0.05V4c0,-1.38 -1.12,-2.5 -2.5,-2.5c-0.23,0 -0.46,0.03 -0.67,0.09C14.46,0.66 13.56,0 12.5,0c-1.23,0 -2.25,0.89 -2.46,2.06C9.87,2.02 9.69,2 9.5,2C8.12,2 7,3.12 7,4.5v5.89c-0.34,-0.31 -0.76,-0.54 -1.22,-0.66L5.01,9.52c-0.83,-0.23 -1.7,0.09 -2.19,0.83c-0.38,0.57 -0.4,1.31 -0.15,1.95l2.56,6.43C6.49,21.91 9.57,24 13,24h0c4.42,0 8,-3.58 8,-8V7zM19,16c0,3.31 -2.69,6 -6,6h0c-2.61,0 -4.95,-1.59 -5.91,-4.01l-2.6,-6.54l0.53,0.14c0.46,0.12 0.83,0.46 1,0.9L7,15h2V4.5C9,4.22 9.22,4 9.5,4S10,4.22 10,4.5V12h2V2.5C12,2.22 12.22,2 12.5,2S13,2.22 13,2.5V12h2V4c0,-0.28 0.22,-0.5 0.5,-0.5S16,3.72 16,4v8h2V7c0,-0.28 0.22,-0.5 0.5,-0.5S19,6.72 19,7L19,16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/browser_updated.xml b/compose/material/material/icons/generator/raw-icons/outlined/browser_updated.xml
new file mode 100644
index 0000000..ff06c5e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/browser_updated.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,13v3c0,1.1 -0.9,2 -2,2h-3l1,1v2H6v-2l1,-1H4c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2l8,0v2L4,5v11h16v-3H22zM15,15l-5,-5l1.41,-1.41L14,11.17V3h2v8.17l2.59,-2.58L20,10L15,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/checklist.xml b/compose/material/material/icons/generator/raw-icons/outlined/checklist.xml
new file mode 100644
index 0000000..64e7ee3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/checklist.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,7h-9v2h9V7zM22,15h-9v2h9V15zM5.54,11L2,7.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,11zM5.54,19L2,15.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/checklist_rtl.xml b/compose/material/material/icons/generator/raw-icons/outlined/checklist_rtl.xml
new file mode 100644
index 0000000..eb4422c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/checklist_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,7H2v2h9V7zM11,15H2v2h9V15zM16.34,11l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,5.34L16.34,11zM16.34,19l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,13.34L16.34,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/co2.xml b/compose/material/material/icons/generator/raw-icons/outlined/co2.xml
new file mode 100644
index 0000000..28a144a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/co2.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,9h-3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-4C15,9.45 14.55,9 14,9zM13.5,13.5h-2v-3h2V13.5zM8,13v1c0,0.55 -0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v1H6.5v-0.5h-2v3h2V13H8zM20.5,15.5h-2v1h3V18H17v-2.5c0,-0.55 0.45,-1 1,-1h2v-1h-3V12h3.5c0.55,0 1,0.45 1,1v1.5C21.5,15.05 21.05,15.5 20.5,15.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/comments_disabled.xml b/compose/material/material/icons/generator/raw-icons/outlined/comments_disabled.xml
new file mode 100644
index 0000000..8046985
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/comments_disabled.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.83,16H20V4H6.83l-2,-2H20c1.1,0 2,0.9 2,2l0,15.17L18.83,16zM18,6H8.83l2,2H18V6zM18,9h-6.17l2,2H18V9zM18,14v-2h-3.17l2,2H18zM21.9,21.9l-1.41,1.41L15.17,18H4c-1.1,0 -2,-0.9 -2,-2V4.83L0.69,3.51L2.1,2.1L21.9,21.9zM13.17,16l-2,-2H6v-2h3.17l-1,-1H6V9h0.17L4,6.83V16H13.17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/compost.xml b/compose/material/material/icons/generator/raw-icons/outlined/compost.xml
new file mode 100644
index 0000000..b06253a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/compost.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.87,11.81c-0.23,-0.38 -0.37,-0.83 -0.37,-1.31C12.5,9.12 13.62,8 15,8l1,0c1.51,0 2,-1 2,-1s0.55,6 -3,6c-0.49,0 -0.94,-0.14 -1.32,-0.38c-0.24,0.64 -0.59,1.76 -0.76,2.96c1.26,0.22 2.28,0.89 2.77,1.77c1.69,-1.17 2.81,-3.13 2.81,-5.35h3c0,5.24 -4.26,9.5 -9.5,9.5S2.5,17.24 2.5,12S6.76,2.5 12,2.5V0l4,4l-4,4V5.5c-3.58,0 -6.5,2.92 -6.5,6.5c0,2.21 1.11,4.17 2.81,5.35c0.51,-0.92 1.63,-1.62 2.98,-1.8c-0.09,-0.69 -0.26,-1.42 -0.49,-2.03C10.45,13.82 10,14 9.5,14c-1.1,0 -2,-0.9 -2,-2v-0.99c0,-0.56 -0.19,-1.09 -0.5,-1.51c0,0 4.45,-0.23 4.5,2.5c0,0.29 -0.06,0.56 -0.17,0.8C10.91,12.48 10.47,12.2 10,12c0.58,0.43 1.37,1.37 2,2.6c0.67,-1.62 1.68,-3.27 3,-4.6C14.24,10.52 13.53,11.12 12.87,11.81z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/connecting_airports.xml b/compose/material/material/icons/generator/raw-icons/outlined/connecting_airports.xml
new file mode 100644
index 0000000..12357c5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/connecting_airports.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.4,17l1.3,4.4h-1.1L13,17h-3c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h3l2.6,-4.4h1.1L15.4,15h2.85L19,14h1l-0.6,2l0.6,2h-1l-0.75,-1H15.4zM5.75,7L5,6H4l0.6,2L4,10h1l0.75,-1H8.6l-1.3,4.4h1.1L11,9h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L8.4,2.6H7.3L8.6,7H5.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/cruelty_free.xml b/compose/material/material/icons/generator/raw-icons/outlined/cruelty_free.xml
new file mode 100644
index 0000000..3b0c5cc
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/cruelty_free.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17,14c-0.24,-0.24 -0.44,-0.49 -0.65,-0.75C17.51,11.5 19,8.56 19,5c0,-1.95 -0.74,-3 -2,-3c-1.54,0 -3.96,2.06 -5,5.97C10.96,4.06 8.54,2 7,2C5.74,2 5,3.05 5,5c0,3.56 1.49,6.5 2.65,8.25C7.44,13.51 7.24,13.76 7,14c-0.25,0.25 -2,1.39 -2,3.5C5,19.98 7.02,22 9.5,22c1.5,0 2.5,-0.5 2.5,-0.5s1,0.5 2.5,0.5c2.48,0 4.5,-2.02 4.5,-4.5C19,15.39 17.25,14.25 17,14zM16.88,4.03C16.94,4.2 17,4.51 17,5c0,2.84 -1.11,5.24 -2.07,6.78c-0.38,-0.26 -0.83,-0.48 -1.4,-0.62C13.77,6.64 15.97,4.33 16.88,4.03zM7,5c0,-0.49 0.06,-0.8 0.12,-0.97c0.91,0.3 3.11,2.61 3.36,7.13c-0.58,0.14 -1.03,0.35 -1.4,0.62C8.11,10.24 7,7.84 7,5zM14.5,20c-1,0 -1.8,-0.33 -2.22,-0.56C12.7,19.26 13,18.73 13,18.5c0,-0.28 -0.45,-0.5 -1,-0.5s-1,0.22 -1,0.5c0,0.23 0.3,0.76 0.72,0.94C11.3,19.67 10.5,20 9.5,20C8.12,20 7,18.88 7,17.5c0,-0.7 0.43,-1.24 1,-1.73c0.44,-0.36 0.61,-0.52 1.3,-1.37c0.76,-0.95 1.09,-1.4 2.7,-1.4s1.94,0.45 2.7,1.4c0.69,0.85 0.86,1.01 1.3,1.37c0.57,0.49 1,1.03 1,1.73C17,18.88 15.88,20 14.5,20zM14,16c0,0.41 -0.22,0.75 -0.5,0.75S13,16.41 13,16c0,-0.41 0.22,-0.75 0.5,-0.75S14,15.59 14,16zM11,16c0,0.41 -0.22,0.75 -0.5,0.75S10,16.41 10,16c0,-0.41 0.22,-0.75 0.5,-0.75S11,15.59 11,16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/data_exploration.xml b/compose/material/material/icons/generator/raw-icons/outlined/data_exploration.xml
new file mode 100644
index 0000000..ca26eff
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/data_exploration.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10h8c1.1,0 2,-0.9 2,-2v-8C22,6.48 17.52,2 12,2zM12,20c-2.89,0 -5.43,-1.54 -6.83,-3.84l2.95,-2.95L11.41,16L16,11.42V13h2V8h-5v2h1.58l-3.28,3.28L8,10.5l-3.69,3.7C4.11,13.5 4,12.76 4,12c0,-4.41 3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM19.5,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.05,20.5 19.5,20.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/disabled_visible.xml b/compose/material/material/icons/generator/raw-icons/outlined/disabled_visible.xml
new file mode 100644
index 0000000..33f5a15
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/disabled_visible.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17,15c1.95,0 3.76,0.98 4.75,2.5C20.76,19.02 18.95,20 17,20s-3.76,-0.98 -4.75,-2.5C13.24,15.98 15.05,15 17,15zM17,13c-3.18,0 -5.9,1.87 -7,4.5c1.1,2.63 3.82,4.5 7,4.5s5.9,-1.87 7,-4.5C22.9,14.87 20.18,13 17,13zM17,19c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.17,16 17,16s1.5,0.67 1.5,1.5S17.83,19 17,19zM21.99,12.34C22,12.23 22,12.11 22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12c0,5.17 3.93,9.43 8.96,9.95c-0.93,-0.73 -1.72,-1.64 -2.32,-2.68C5.9,18 4,15.22 4,12c0,-1.85 0.63,-3.55 1.69,-4.9l5.66,5.66c0.56,-0.4 1.17,-0.73 1.82,-1L7.1,5.69C8.45,4.63 10.15,4 12,4c4.24,0 7.7,3.29 7.98,7.45C20.69,11.67 21.37,11.97 21.99,12.34z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/document_scanner.xml b/compose/material/material/icons/generator/raw-icons/outlined/document_scanner.xml
new file mode 100644
index 0000000..74f399c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/document_scanner.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,3H4v3H2V1h5V3zM22,6V1h-5v2h3v3H22zM7,21H4v-3H2v5h5V21zM20,18v3h-3v2h5v-5H20zM17,6H7v12h10V6zM19,18c0,1.1 -0.9,2 -2,2H7c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10c1.1,0 2,0.9 2,2V18zM15,8H9v2h6V8zM15,11H9v2h6V11zM15,14H9v2h6V14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/draw.xml b/compose/material/material/icons/generator/raw-icons/outlined/draw.xml
new file mode 100644
index 0000000..01912c3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/draw.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.85,10.39l1.06,-1.06c0.78,-0.78 0.78,-2.05 0,-2.83L18.5,5.09c-0.78,-0.78 -2.05,-0.78 -2.83,0l-1.06,1.06L18.85,10.39zM14.61,11.81L7.41,19H6v-1.41l7.19,-7.19L14.61,11.81zM13.19,7.56L4,16.76V21h4.24l9.19,-9.19L13.19,7.56L13.19,7.56zM19,17.5c0,2.19 -2.54,3.5 -5,3.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1c1.54,0 3,-0.73 3,-1.5c0,-0.47 -0.48,-0.87 -1.23,-1.2l1.48,-1.48C18.32,15.45 19,16.29 19,17.5zM4.58,13.35C3.61,12.79 3,12.06 3,11c0,-1.8 1.89,-2.63 3.56,-3.36C7.59,7.18 9,6.56 9,6c0,-0.41 -0.78,-1 -2,-1C5.74,5 5.2,5.61 5.17,5.64C4.82,6.05 4.19,6.1 3.77,5.76C3.36,5.42 3.28,4.81 3.62,4.38C3.73,4.24 4.76,3 7,3c2.24,0 4,1.32 4,3c0,1.87 -1.93,2.72 -3.64,3.47C6.42,9.88 5,10.5 5,11c0,0.31 0.43,0.6 1.07,0.86L4.58,13.35z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/drive_file_move_rtl.xml b/compose/material/material/icons/generator/raw-icons/outlined/drive_file_move_rtl.xml
new file mode 100644
index 0000000..6dc9d2a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/drive_file_move_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,6h-8l-2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM20,18H4V6h5.17l2,2H20V18zM13.41,15.59L12,17l-4,-4l4,-4l1.41,1.41L11.83,12H16v2h-4.17L13.41,15.59z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/edit_calendar.xml b/compose/material/material/icons/generator/raw-icons/outlined/edit_calendar.xml
new file mode 100644
index 0000000..1f1a454
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/edit_calendar.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,10h14v2h2V6c0,-1.1 -0.9,-2 -2,-2h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h7v-2H5V10zM5,6h14v2H5V6zM22.84,16.28l-0.71,0.71l-2.12,-2.12l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71C23.23,15.26 23.23,15.89 22.84,16.28zM19.3,15.58l2.12,2.12l-5.3,5.3H14v-2.12L19.3,15.58z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/edit_note.xml b/compose/material/material/icons/generator/raw-icons/outlined/edit_note.xml
new file mode 100644
index 0000000..1641196
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/edit_note.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/emergency.xml b/compose/material/material/icons/generator/raw-icons/outlined/emergency.xml
new file mode 100644
index 0000000..b5f2a6d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/emergency.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21.29,13.9L18,12l3.29,-1.9c0.48,-0.28 0.64,-0.89 0.37,-1.37l-2,-3.46c-0.28,-0.48 -0.89,-0.64 -1.37,-0.37L15,6.8V3c0,-0.55 -0.45,-1 -1,-1h-4C9.45,2 9,2.45 9,3v3.8L5.71,4.9C5.23,4.63 4.62,4.79 4.34,5.27l-2,3.46C2.06,9.21 2.23,9.82 2.71,10.1L6,12l-3.29,1.9c-0.48,0.28 -0.64,0.89 -0.37,1.37l2,3.46c0.28,0.48 0.89,0.64 1.37,0.37L9,17.2V21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-3.8l3.29,1.9c0.48,0.28 1.09,0.11 1.37,-0.37l2,-3.46C21.94,14.79 21.77,14.18 21.29,13.9zM18.43,16.87l-4.68,-2.7C13.42,13.97 13,14.21 13,14.6V20h-2v-5.4c0,-0.38 -0.42,-0.63 -0.75,-0.43l-4.68,2.7l-1,-1.73l4.68,-2.7c0.33,-0.19 0.33,-0.67 0,-0.87l-4.68,-2.7l1,-1.73l4.68,2.7C10.58,10.03 11,9.79 11,9.4V4h2v5.4c0,0.38 0.42,0.63 0.75,0.43l4.68,-2.7l1,1.73l-4.68,2.7c-0.33,0.19 -0.33,0.67 0,0.87l4.68,2.7L18.43,16.87z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/expand_circle_down.xml b/compose/material/material/icons/generator/raw-icons/outlined/expand_circle_down.xml
new file mode 100644
index 0000000..f8e376c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/expand_circle_down.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.08,9.59L12,12.67L8.92,9.59L7.5,11l4.5,4.5l4.5,-4.5L15.08,9.59zM12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/fitbit.xml b/compose/material/material/icons/generator/raw-icons/outlined/fitbit.xml
new file mode 100644
index 0000000..da71490
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/fitbit.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.89,13.89c1.04,0 1.89,-0.85 1.89,-1.89s-0.85,-1.89 -1.89,-1.89C18.85,10.11 18,10.96 18,12S18.85,13.89 19.89,13.89zM15.65,13.68c0.93,0 1.68,-0.75 1.68,-1.68s-0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68S14.72,13.68 15.65,13.68zM15.65,9.42c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,8.67 14.72,9.42 15.65,9.42zM15.65,17.93c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,17.17 14.72,17.93 15.65,17.93zM11.41,13.47c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,13.47 11.41,13.47zM11.41,9.21c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,9.21 11.41,9.21zM11.41,17.73c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,17.07 10.59,17.73 11.41,17.73zM11.41,22c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,21.34 10.59,22 11.41,22zM11.41,4.94c0.81,0 1.47,-0.66 1.47,-1.47S12.22,2 11.41,2c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,4.94 11.41,4.94zM7.16,13.26c0.7,0 1.26,-0.57 1.26,-1.26s-0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26S6.46,13.26 7.16,13.26zM7.16,17.51c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,16.94 6.46,17.51 7.16,17.51zM7.16,9.02c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,8.45 6.46,9.02 7.16,9.02zM3.29,13.05c0.58,0 1.05,-0.47 1.05,-1.05s-0.47,-1.05 -1.05,-1.05c-0.58,0 -1.05,0.47 -1.05,1.05S2.71,13.05 3.29,13.05z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/flight_class.xml b/compose/material/material/icons/generator/raw-icons/outlined/flight_class.xml
new file mode 100644
index 0000000..c763faa
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/flight_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,4h-2c-1.1,0 -2,0.9 -2,2v5c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2V6C18,4.9 17.1,4 16,4zM16,11h-2V6h2V11zM9.5,16H18v2H9.49c-0.88,0 -1.66,-0.58 -1.92,-1.43L5,8V4h2v4L9.5,16zM8,19h10v2H8V19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/free_cancellation.xml b/compose/material/material/icons/generator/raw-icons/outlined/free_cancellation.xml
new file mode 100644
index 0000000..95a5824
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/free_cancellation.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.21,20H5V10h14v4.38l2,-2V6c0,-1.1 -0.9,-2 -2,-2h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h8.21L11.21,20zM5,6h14v2H5V6zM16.54,22.5L13,18.96l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L16.54,22.5zM10.41,14L12,15.59L10.59,17L9,15.41L7.41,17L6,15.59L7.59,14L6,12.41L7.41,11L9,12.59L10.59,11L12,12.41L10.41,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/front_hand.xml b/compose/material/material/icons/generator/raw-icons/outlined/front_hand.xml
new file mode 100644
index 0000000..86e05e0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/front_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.5,8c-0.17,0 -0.34,0.02 -0.5,0.05V4.5C18,3.12 16.88,2 15.5,2c-0.19,0 -0.37,0.02 -0.54,0.06C14.75,0.89 13.73,0 12.5,0c-1.06,0 -1.96,0.66 -2.33,1.59C9.96,1.53 9.73,1.5 9.5,1.5C8.12,1.5 7,2.62 7,4v0.55C6.84,4.52 6.67,4.5 6.5,4.5C5.12,4.5 4,5.62 4,7v8.5c0,4.69 3.81,8.5 8.5,8.5s8.5,-3.81 8.5,-8.5v-5C21,9.12 19.88,8 18.5,8zM19,15.5c0,3.59 -2.91,6.5 -6.5,6.5S6,19.09 6,15.5V7c0,-0.28 0.22,-0.5 0.5,-0.5S7,6.72 7,7v5h2V4c0,-0.28 0.22,-0.5 0.5,-0.5S10,3.72 10,4v7h2V2.5C12,2.22 12.22,2 12.5,2S13,2.22 13,2.5V11h2V4.5C15,4.22 15.22,4 15.5,4S16,4.22 16,4.5v8.92c-1.77,0.77 -3,2.53 -3,4.58h2c0,-1.66 1.34,-3 3,-3v-4.5c0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5V15.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/generating_tokens.xml b/compose/material/material/icons/generator/raw-icons/outlined/generating_tokens.xml
new file mode 100644
index 0000000..dc32538
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/generating_tokens.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8C17,7.58 13.42,4 9,4zM9,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6s6,2.69 6,6S12.31,18 9,18zM12,10.5h-2v5H8v-5H6V9h6V10.5zM20.25,3.75L23,5l-2.75,1.25L19,9l-1.25,-2.75L15,5l2.75,-1.25L19,1L20.25,3.75zM20.25,17.75L23,19l-2.75,1.25L19,23l-1.25,-2.75L15,19l2.75,-1.25L19,15L20.25,17.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/gif_box.xml b/compose/material/material/icons/generator/raw-icons/outlined/gif_box.xml
new file mode 100644
index 0000000..a2ff3d5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/gif_box.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,19H5V5h14V19zM5,3C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2H5zM11.5,14h1v-4h-1V14zM13.5,14h1v-1.5H16v-1h-1.5V11h2v-1h-3V14zM9.5,12v1h-1v-2h2c0,-0.55 -0.45,-1 -1,-1h-1c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-1H9.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/group_add.xml b/compose/material/material/icons/generator/raw-icons/outlined/group_add.xml
index 7ad3ce8..b21a269 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/group_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/group_add.xml
@@ -6,5 +6,17 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,15v-3h3v-2L5,10L5,7L3,7v3L0,10v2h3v3zM12,13.75c-2.34,0 -7,1.17 -7,3.5L5,19h14v-1.75c0,-2.33 -4.66,-3.5 -7,-3.5zM7.34,17c0.84,-0.58 2.87,-1.25 4.66,-1.25s3.82,0.67 4.66,1.25L7.34,17zM12,12c1.93,0 3.5,-1.57 3.5,-3.5S13.93,5 12,5 8.5,6.57 8.5,8.5 10.07,12 12,12zM12,7c0.83,0 1.5,0.67 1.5,1.5S12.83,10 12,10s-1.5,-0.67 -1.5,-1.5S11.17,7 12,7zM17,12c1.93,0 3.5,-1.57 3.5,-3.5S18.93,5 17,5c-0.24,0 -0.48,0.02 -0.71,0.07 0.76,0.94 1.21,2.13 1.21,3.43 0,1.3 -0.47,2.48 -1.23,3.42 0.24,0.05 0.48,0.08 0.73,0.08zM19.32,14.02c1,0.81 1.68,1.87 1.68,3.23L21,19h3v-1.75c0,-1.69 -2.44,-2.76 -4.68,-3.23z"/>
+ android:pathData="M22,9l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0l0,-2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4S4,5.79 4,8S5.79,12 8,12zM8,6c1.1,0 2,0.9 2,2s-0.9,2 -2,2S6,9.1 6,8S6.9,6 8,6z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13zM14,18H2v-0.99C2.2,16.29 5.3,15 8,15s5.8,1.29 6,2V18z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/group_off.xml b/compose/material/material/icons/generator/raw-icons/outlined/group_off.xml
new file mode 100644
index 0000000..d70d9c8
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/group_off.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.06,0 -0.12,0 -0.18,0l-0.77,-0.77C14.65,10.29 15,9.18 15,8zM22.83,20H23v-3c0,-2.18 -3.58,-3.47 -6.34,-3.87c1.1,0.75 1.95,1.71 2.23,2.94L22.83,20zM9,6C8.94,6 8.89,6 8.84,6.01l-1.6,-1.6C7.77,4.15 8.37,4 9,4c2.21,0 4,1.79 4,4c0,0.63 -0.15,1.23 -0.41,1.76l-1.6,-1.6C11,8.11 11,8.06 11,8C11,6.9 10.1,6 9,6zM9.17,12C9.11,12 9.06,12 9,12c-2.21,0 -4,-1.79 -4,-4c0,-0.06 0,-0.11 0,-0.17L0.69,3.51L2.1,2.1l19.8,19.8l-1.41,1.41L17,19.83V20H1v-3c0,-2.66 5.33,-4 8,-4c0.37,0 0.8,0.03 1.25,0.08L9.17,12zM9,15c-2.7,0 -5.8,1.29 -6,2.01V18h12v-0.17l-2.11,-2.11C11.76,15.31 10.33,15 9,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/group_remove.xml b/compose/material/material/icons/generator/raw-icons/outlined/group_remove.xml
new file mode 100644
index 0000000..2cf68b1
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/group_remove.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,9v2h-6V9H24zM8,4C5.79,4 4,5.79 4,8s1.79,4 4,4s4,-1.79 4,-4S10.21,4 8,4zM8,10c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S9.1,10 8,10zM8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13zM14,18H2v-0.99C2.2,16.29 5.3,15 8,15s5.8,1.29 6,2V18zM12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05zM16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/hotel_class.xml b/compose/material/material/icons/generator/raw-icons/outlined/hotel_class.xml
new file mode 100644
index 0000000..972e1a5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/hotel_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,8.89L11.94,12h2.82l-2.27,1.62l0.93,3.01L11,14.79l-2.42,1.84l0.93,-3.01L7.24,12h2.82L11,8.89zM8.58,10H1l6.17,4.41L4.83,22L11,17.31L17.18,22l-2.35,-7.59L21,10h-7.58L11,2L8.58,10zM21.36,22l-1.86,-6.01L23.68,13h-3.44l-3.08,2.2l1.46,4.72L21.36,22zM17,8l-1.82,-6l-1.04,3.45L14.91,8H17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/hub.xml b/compose/material/material/icons/generator/raw-icons/outlined/hub.xml
new file mode 100644
index 0000000..ac23da4
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/hub.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,6.5c-1.66,0 -3,1.34 -3,3c0,0.07 0,0.14 0.01,0.21l-2.03,0.68c-0.64,-1.21 -1.82,-2.09 -3.22,-2.32V5.91C14.04,5.57 15,4.4 15,3c0,-1.66 -1.34,-3 -3,-3S9,1.34 9,3c0,1.4 0.96,2.57 2.25,2.91v2.16c-1.4,0.23 -2.58,1.11 -3.22,2.32L5.99,9.71C6,9.64 6,9.57 6,9.5c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3s1.34,3 3,3c1.06,0 1.98,-0.55 2.52,-1.37l2.03,0.68c-0.2,1.29 0.17,2.66 1.09,3.69l-1.41,1.77C6.85,17.09 6.44,17 6,17c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3c0,-0.68 -0.22,-1.3 -0.6,-1.8l1.41,-1.77c1.36,0.76 3.02,0.75 4.37,0l1.41,1.77C15.22,18.7 15,19.32 15,20c0,1.66 1.34,3 3,3s3,-1.34 3,-3s-1.34,-3 -3,-3c-0.44,0 -0.85,0.09 -1.23,0.26l-1.41,-1.77c0.93,-1.04 1.29,-2.4 1.09,-3.69l2.03,-0.68c0.53,0.82 1.46,1.37 2.52,1.37c1.66,0 3,-1.34 3,-3S22.66,6.5 21,6.5zM3,10.5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C4,10.05 3.55,10.5 3,10.5zM6,21c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C7,20.55 6.55,21 6,21zM11,3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1c0,0.55 -0.45,1 -1,1S11,3.55 11,3zM12,15c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C14.5,13.88 13.38,15 12,15zM18,19c0.55,0 1,0.45 1,1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1C17,19.45 17.45,19 18,19zM21,10.5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C22,10.05 21.55,10.5 21,10.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/incomplete_circle.xml b/compose/material/material/icons/generator/raw-icons/outlined/incomplete_circle.xml
new file mode 100644
index 0000000..e7e6e41
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/incomplete_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12c0,5.52 -4.48,10 -10,10S2,17.52 2,12c0,-2.76 1.12,-5.26 2.93,-7.07L12,12V2C17.52,2 22,6.48 22,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/interests.xml b/compose/material/material/icons/generator/raw-icons/outlined/interests.xml
new file mode 100644
index 0000000..a39ac41
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/interests.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.02,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.23,13 7.02,13zM7.02,19c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S8.12,19 7.02,19zM13,13v8h8v-8H13zM19,19h-4v-4h4V19zM7,2l-5,9h10L7,2zM7,6.12L8.6,9H5.4L7,6.12zM19.25,2.5c-1.06,0 -1.81,0.56 -2.25,1.17c-0.44,-0.61 -1.19,-1.17 -2.25,-1.17C13.19,2.5 12,3.78 12,5.25c0,2 2.42,3.42 5,5.75c2.58,-2.33 5,-3.75 5,-5.75C22,3.78 20.81,2.5 19.25,2.5zM17,8.35c-1.45,-1.22 -3,-2.4 -3,-3.1c0,-0.43 0.35,-0.75 0.75,-0.75c0.31,0 0.52,0.17 0.73,0.37L17,6.3l1.52,-1.43c0.21,-0.2 0.42,-0.37 0.73,-0.37c0.4,0 0.75,0.32 0.75,0.75C20,5.95 18.45,7.13 17,8.35z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/interpreter_mode.xml b/compose/material/material/icons/generator/raw-icons/outlined/interpreter_mode.xml
new file mode 100644
index 0000000..5c88b1a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/interpreter_mode.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.5,16.5c-0.83,0 -1.5,-0.67 -1.5,-1.5v-2.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5V15C22,15.83 21.33,16.5 20.5,16.5zM20,20h1c0,0 0,-1.54 0,-1.54c1.69,-0.24 3,-1.7 3,-3.46h-1c0,1.38 -1.12,2.5 -2.5,2.5S18,16.38 18,15h-1c0,1.76 1.31,3.22 3,3.46C20,18.46 20,20 20,20zM9,12c-2.21,0 -4,-1.79 -4,-4c0,-2.21 1.79,-4 4,-4c0.47,0 0.92,0.08 1.34,0.23C9.5,5.26 9,6.57 9,8c0,1.43 0.5,2.74 1.34,3.77C9.92,11.92 9.47,12 9,12zM7.11,13.13C5.79,14.05 5,15.57 5,17.22V20H1v-2.78c0,-1.12 0.61,-2.15 1.61,-2.66C3.85,13.92 5.37,13.37 7.11,13.13zM11,8c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S11,10.21 11,8zM13,8c0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2S13,6.9 13,8zM15,15c-2.37,0 -4.29,0.73 -5.48,1.34C9.2,16.5 9,16.84 9,17.22V18l7.17,0c0.5,0.86 1.25,1.56 2.15,2L7,20v-2.78c0,-1.12 0.61,-2.15 1.61,-2.66C10.29,13.7 12.47,13 15,13c0.39,0 0.77,0.02 1.14,0.05c-0.33,0.59 -0.55,1.26 -0.62,1.96C15.35,15 15.18,15 15,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/kebab_dining.xml b/compose/material/material/icons/generator/raw-icons/outlined/kebab_dining.xml
new file mode 100644
index 0000000..2ac2b2b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/kebab_dining.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.75,7h0.75C19.88,7 21,5.88 21,4.5C21,3.12 19.88,2 18.5,2h-0.75V1h-1.5v1H15.5C14.12,2 13,3.12 13,4.5C13,5.88 14.12,7 15.5,7h0.75v1H13v5h3.25v1H15.5c-1.38,0 -2.5,1.12 -2.5,2.5c0,1.38 1.12,2.5 2.5,2.5h0.75v4h1.5v-4h0.75c1.38,0 2.5,-1.12 2.5,-2.5c0,-1.38 -1.12,-2.5 -2.5,-2.5h-0.75v-1H21V8h-3.25V7zM15.5,5C15.22,5 15,4.78 15,4.5S15.22,4 15.5,4h3C18.78,4 19,4.22 19,4.5S18.78,5 18.5,5H15.5zM18.5,16c0.28,0 0.5,0.22 0.5,0.5S18.78,17 18.5,17h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5H18.5zM19,10v1h-4v-1H19zM7.75,7H8.5C9.88,7 11,5.88 11,4.5C11,3.12 9.88,2 8.5,2H7.75V1h-1.5v1H5.5C4.12,2 3,3.12 3,4.5C3,5.88 4.12,7 5.5,7h0.75v1H3v5h3.25v1H5.5C4.12,14 3,15.12 3,16.5C3,17.88 4.12,19 5.5,19h0.75v4h1.5v-4H8.5c1.38,0 2.5,-1.12 2.5,-2.5c0,-1.38 -1.12,-2.5 -2.5,-2.5H7.75v-1H11V8H7.75V7zM5.5,5C5.22,5 5,4.78 5,4.5S5.22,4 5.5,4h3C8.78,4 9,4.22 9,4.5S8.78,5 8.5,5H5.5zM8.5,16C8.78,16 9,16.22 9,16.5S8.78,17 8.5,17h-3C5.22,17 5,16.78 5,16.5S5.22,16 5.5,16H8.5zM9,10v1H5v-1H9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/mode_of_travel.xml b/compose/material/material/icons/generator/raw-icons/outlined/mode_of_travel.xml
new file mode 100644
index 0000000..dd79f62
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/mode_of_travel.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.31,18.9c-0.96,1 -2.06,2.03 -3.31,3.1c-5.33,-4.55 -8,-8.48 -8,-11.8C4,5.22 7.8,2 12,2c4.19,0 7.99,3.21 8,8.17l2.09,-2.09L23.5,9.5L19,14l-4.5,-4.5l1.41,-1.41L18,10.17C17.99,6.55 15.34,4 12,4c-3.35,0 -6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14c0.64,-0.59 1.23,-1.16 1.77,-1.71c-0.17,-0.34 -0.27,-0.72 -0.27,-1.12c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S17.38,19 16,19C15.76,19 15.53,18.97 15.31,18.9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/new_label.xml b/compose/material/material/icons/generator/raw-icons/outlined/new_label.xml
new file mode 100644
index 0000000..0d44eec
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/new_label.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,12l-4.37,6.16C16.26,18.68 15.65,19 15,19h-3l0,-2h3l3.55,-5L15,7H5v3H3V7c0,-1.1 0.9,-2 2,-2h10c0.65,0 1.26,0.31 1.63,0.84L21,12zM10,15H7v-3H5v3H2v2h3v3h2v-3h3V15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/palette.xml b/compose/material/material/icons/generator/raw-icons/outlined/palette.xml
index 78ddce5..9b6684f 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/palette.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/palette.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,22C6.49,22 2,17.51 2,12S6.49,2 12,2s10,4.04 10,9c0,3.31 -2.69,6 -6,6h-1.77c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.12 0.05,0.23 0.13,0.33 0.41,0.47 0.64,1.06 0.64,1.67 0,1.38 -1.12,2.5 -2.5,2.5zM12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5 0,-0.16 -0.08,-0.28 -0.14,-0.35 -0.41,-0.46 -0.63,-1.05 -0.63,-1.65 0,-1.38 1.12,-2.5 2.5,-2.5L16,15c2.21,0 4,-1.79 4,-4 0,-3.86 -3.59,-7 -8,-7z"/>
+ android:pathData="M12,22C6.49,22 2,17.51 2,12S6.49,2 12,2s10,4.04 10,9c0,3.31 -2.69,6 -6,6h-1.77c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.12 0.05,0.23 0.13,0.33c0.41,0.47 0.64,1.06 0.64,1.67C14.5,20.88 13.38,22 12,22zM12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5c0,-0.16 -0.08,-0.28 -0.14,-0.35c-0.41,-0.46 -0.63,-1.05 -0.63,-1.65c0,-1.38 1.12,-2.5 2.5,-2.5H16c2.21,0 4,-1.79 4,-4C20,7.14 16.41,4 12,4z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M6.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/personal_injury.xml b/compose/material/material/icons/generator/raw-icons/outlined/personal_injury.xml
new file mode 100644
index 0000000..27ab0e0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/personal_injury.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,10c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S8,3.79 8,6C8,8.21 9.79,10 12,10zM12,4c1.1,0 2,0.9 2,2c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2C10,4.9 10.9,4 12,4zM18.39,12.56C16.71,11.7 14.53,11 12,11c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,13.07 4,14.1 4,15.22V22h2v-6.78c0,-0.38 0.2,-0.72 0.52,-0.88C7.71,13.73 9.63,13 12,13c0.76,0 1.47,0.07 2.13,0.2l-1.55,3.3H9.75C8.23,16.5 7,17.73 7,19.25C7,20.77 8.23,22 9.75,22h2.18H18c1.1,0 2,-0.9 2,-2v-4.78C20,14.1 19.39,13.07 18.39,12.56zM10.94,20H9.75C9.34,20 9,19.66 9,19.25c0,-0.41 0.34,-0.75 0.75,-0.75h1.89L10.94,20zM18,20h-4.85l2.94,-6.27c0.54,0.2 1.01,0.41 1.4,0.61C17.8,14.5 18,14.84 18,15.22V20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/phone_locked.xml b/compose/material/material/icons/generator/raw-icons/outlined/phone_locked.xml
index 1336f48..9c49d43 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/phone_locked.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/phone_locked.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15.5c-1.25,0 -2.45,-0.2 -3.57,-0.57 -0.1,-0.03 -0.21,-0.05 -0.31,-0.05 -0.26,0 -0.51,0.1 -0.71,0.29l-2.2,2.2c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l2.2,-2.21c0.28,-0.26 0.36,-0.65 0.25,-1C8.7,6.45 8.5,5.25 8.5,4c0,-0.55 -0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1 0,9.39 7.61,17 17,17 0.55,0 1,-0.45 1,-1v-3.5c0,-0.55 -0.45,-1 -1,-1zM5.03,5h1.5c0.07,0.88 0.22,1.75 0.45,2.58l-1.2,1.21c-0.4,-1.21 -0.66,-2.47 -0.75,-3.79zM19,18.97c-1.32,-0.09 -2.6,-0.35 -3.8,-0.76l1.2,-1.2c0.85,0.24 1.72,0.39 2.6,0.45v1.51zM20,4v-0.5C20,2.12 18.88,1 17.5,1S15,2.12 15,3.5L15,4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1L21,5c0,-0.55 -0.45,-1 -1,-1zM19,4h-3v-0.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5L19,4z"/>
+ android:pathData="M20,5V4c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v1h-1v5h6V5H20zM19,5h-2V4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.2,14.87l-3.67,-0.73c-0.5,-0.1 -0.83,0.2 -0.9,0.27l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.55,0.03 1.03,-0.43 1.03,-1v-4.15C21,15.37 20.66,14.96 20.2,14.87zM5.1,5h2.23L7.8,7.35L6.17,9C5.63,7.7 5.27,6.37 5.1,5zM19,18.9c-1.37,-0.18 -2.7,-0.53 -4,-1.07l1.65,-1.63L19,16.67V18.9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/photo_album.xml b/compose/material/material/icons/generator/raw-icons/outlined/photo_album.xml
index 7863911..3d26bc9 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/photo_album.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/photo_album.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2L6,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM11,4v5l-1,-0.75L9,9L9,4h2zM18,20L6,20L6,4h1v9l3,-2.25L13,13L13,4h5v16zM11.28,17.96L9.5,15.81 7,19h10l-3.22,-4.26z"/>
+ android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM18,20H6V4h5v7l2.5,-1.5L16,11V4h2V20zM13.62,13.5L17,18H7l2.38,-3.17L11,17L13.62,13.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/pin_end.xml b/compose/material/material/icons/generator/raw-icons/outlined/pin_end.xml
new file mode 100644
index 0000000..348668cc
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/pin_end.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,12V6H4v12h10l0,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h16c1.1,0 2,0.9 2,2v6H20zM19,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c1.66,0 3,-1.34 3,-3S20.66,14 19,14zM14.66,8H9v5.66h2v-2.24l2.95,2.95l1.41,-1.41L12.41,10h2.24V8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/pin_invoke.xml b/compose/material/material/icons/generator/raw-icons/outlined/pin_invoke.xml
new file mode 100644
index 0000000..349c2a9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/pin_invoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12v6c0,1.1 -0.9,2 -2,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10l0,2H4v12h16v-6H22zM22,7c0,-1.66 -1.34,-3 -3,-3c-1.66,0 -3,1.34 -3,3s1.34,3 3,3C20.66,10 22,8.66 22,7zM9.34,12h2.24l-2.95,2.95l1.41,1.41L13,13.42v2.24h2V10H9.34V12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/playlist_add_check_circle.xml b/compose/material/material/icons/generator/raw-icons/outlined/playlist_add_check_circle.xml
new file mode 100644
index 0000000..5a3d2a7
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/playlist_add_check_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4c4.41,0 8,3.59 8,8s-3.59,8 -8,8s-8,-3.59 -8,-8S7.59,4 12,4zM12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM14,10H7v2h7V10zM14,7H7v2h7V7zM7,15h3v-2H7V15zM19,13.41L17.59,12l-3.54,3.54l-1.41,-1.41l-1.41,1.41l2.83,2.83L19,13.41z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/playlist_add_circle.xml b/compose/material/material/icons/generator/raw-icons/outlined/playlist_add_circle.xml
new file mode 100644
index 0000000..2951dcd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/playlist_add_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM14,10H7v2h7V10zM14,7H7v2h7V7zM7,15h3v-2H7V15zM19,13v2h-2v2h-2v-2h-2v-2h2v-2h2v2H19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/private_connectivity.xml b/compose/material/material/icons/generator/raw-icons/outlined/private_connectivity.xml
new file mode 100644
index 0000000..f7128a3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/private_connectivity.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,7c2.76,0 5,2.24 5,5s-2.24,5 -5,5s-5,-2.24 -5,-5S9.24,7 12,7zM5.07,13c0.49,3.39 3.4,6 6.93,6c3.53,0 6.44,-2.61 6.93,-6L22,13v-2l-3.07,0c-0.49,-3.39 -3.4,-6 -6.93,-6l0,0c-3.53,0 -6.44,2.61 -6.93,6c0,0 -3.07,0 -3.07,0v2L5.07,13zM14,10.5V9.61c0,-1 -0.68,-1.92 -1.66,-2.08C11.08,7.32 10,8.29 10,9.5v1c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-3C15,10.95 14.55,10.5 14,10.5zM12,13.75c-0.41,0 -0.75,-0.34 -0.75,-0.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75C12.75,13.41 12.41,13.75 12,13.75zM13,10.5h-2v-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V10.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/real_estate_agent.xml b/compose/material/material/icons/generator/raw-icons/outlined/real_estate_agent.xml
new file mode 100644
index 0000000..feda83e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/real_estate_agent.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,6.5V14h-2V7.5L14,4L9,7.5V9H7V6.5l7,-5L21,6.5zM15.5,7h-1v1h1V7zM13.5,7h-1v1h1V7zM15.5,9h-1v1h1V9zM13.5,9h-1v1h1V9zM19,16h-2c0,-1.2 -0.75,-2.28 -1.87,-2.7L8.97,11H1v11h6v-1.44l7,1.94l8,-2.5v-1C22,17.34 20.66,16 19,16zM3,20v-7h2v7H3zM13.97,20.41L7,18.48V13h1.61l5.82,2.17C14.77,15.3 15,15.63 15,16c0,0 -1.99,-0.05 -2.3,-0.15l-2.38,-0.79l-0.63,1.9l2.38,0.79c0.51,0.17 1.04,0.26 1.58,0.26H19c0.39,0 0.74,0.23 0.9,0.56L13.97,20.41z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/recycling.xml b/compose/material/material/icons/generator/raw-icons/outlined/recycling.xml
new file mode 100644
index 0000000..bd30b8a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/recycling.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5.77,7.15L7.2,4.78l1.03,-1.71c0.39,-0.65 1.33,-0.65 1.72,0l1.48,2.46l-1.23,2.06L9.2,9.21L5.77,7.15zM21.72,12.97l-1.6,-2.66l-3.46,2L18.87,16H20c0.76,0 1.45,-0.43 1.79,-1.11C21.93,14.61 22,14.31 22,14C22,13.64 21.9,13.29 21.72,12.97zM16,21h1.5c0.76,0 1.45,-0.43 1.79,-1.11L20.74,17H16v-2l-4,4l4,4V21zM10,17H5.7l-0.84,1.41c-0.3,0.5 -0.32,1.12 -0.06,1.65l0,0C5.08,20.63 5.67,21 6.32,21H10V17zM6.12,14.35l1.73,1.04L6.48,9.9L1,11.27l1.7,1.02l-0.41,0.69c-0.35,0.59 -0.38,1.31 -0.07,1.92l1.63,3.26L6.12,14.35zM17.02,5.14l-1.3,-2.17C15.35,2.37 14.7,2 14,2h-3.53l3.12,5.2l-1.72,1.03l5.49,1.37l1.37,-5.49L17.02,5.14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/soup_kitchen.xml b/compose/material/material/icons/generator/raw-icons/outlined/soup_kitchen.xml
new file mode 100644
index 0000000..31ff61f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/soup_kitchen.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.4,7C6.06,7.55 6,7.97 6,8.38C6,9.15 7,11 7,12c0,0.95 -0.4,1.5 -0.4,1.5H5.1c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62C4.5,7.97 4.56,7.55 4.9,7H6.4zM11.4,7C11.06,7.55 11,7.97 11,8.38C11,9.15 12,11 12,12c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H11.4zM8.15,7c-0.34,0.55 -0.4,0.97 -0.4,1.38c0,0.77 1,2.63 1,3.62c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H8.15zM18.6,2c-1.54,0 -2.81,1.16 -2.98,2.65L14.53,15H4.01c-0.6,0 -1.09,0.53 -1,1.13C3.53,19.46 6.39,22 9.75,22c3.48,0 6.34,-2.73 6.71,-6.23l1.15,-10.87C17.66,4.39 18.08,4 18.6,4c0.55,0 1,0.45 1,1c0,0.3 -0.1,1.25 -0.1,1.25l1.97,0.25c0,0 0.13,-1.06 0.13,-1.5C21.6,3.35 20.25,2 18.6,2zM9.75,20c-1.94,0 -3.67,-1.23 -4.43,-3h8.78h0.01C13.39,18.78 11.69,20 9.75,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/south_america.xml b/compose/material/material/icons/generator/raw-icons/outlined/south_america.xml
new file mode 100644
index 0000000..ca13a97
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/south_america.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM4,12c0,-1.95 0.7,-3.74 1.87,-5.13L9,10v1c0,1.1 0.9,2 2,2v5.59c0,0.27 0.11,0.52 0.29,0.71L12,20C7.58,20 4,16.42 4,12zM13,19.94V18l3.75,-5.62c0.16,-0.25 0.25,-0.54 0.25,-0.83V10.5c0,-0.55 -0.45,-1 -1,-1h-1.5l-1.4,-1.75C12.72,7.28 12.15,7 11.54,7H8V5.07C9.18,4.39 10.54,4 12,4c4.41,0 8,3.59 8,8C20,16.07 16.94,19.44 13,19.94z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/space_dashboard.xml b/compose/material/material/icons/generator/raw-icons/outlined/space_dashboard.xml
new file mode 100644
index 0000000..4bee91f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/space_dashboard.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM5,19V5h6v14H5zM19,19h-6v-7h6V19zM19,10h-6V5h6V10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/spoke.xml b/compose/material/material/icons/generator/raw-icons/outlined/spoke.xml
new file mode 100644
index 0000000..45b8ea1
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/spoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,7c0,-2.21 -1.79,-4 -4,-4S8,4.79 8,7c0,2.21 1.79,4 4,4S16,9.21 16,7zM12,9c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C14,8.1 13.1,9 12,9zM7,13c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C11,14.79 9.21,13 7,13zM7,19c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C9,18.1 8.1,19 7,19zM17,13c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C21,14.79 19.21,13 17,13zM17,19c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C19,18.1 18.1,19 17,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/stop_circle.xml b/compose/material/material/icons/generator/raw-icons/outlined/stop_circle.xml
index 791762a..efbbad5 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/stop_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/stop_circle.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,8h8v8h-8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8s8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20zM16,16H8V8h8V16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/switch_access_shortcut.xml b/compose/material/material/icons/generator/raw-icons/outlined/switch_access_shortcut.xml
new file mode 100644
index 0000000..9a8bd21
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/switch_access_shortcut.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-3.09 1.38,-5.94 3.44,-8L12,4V2h7v7h-2l0,-3.72c-1.8,1.74 -3,4.2 -3,6.72c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/switch_access_shortcut_add.xml b/compose/material/material/icons/generator/raw-icons/outlined/switch_access_shortcut_add.xml
new file mode 100644
index 0000000..729d070
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/switch_access_shortcut_add.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-3.09 1.38,-5.94 3.44,-8L12,4V2h7v7h-2l0,-3.72c-1.8,1.74 -3,4.2 -3,6.72c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12zM24,14h-2v-2h-2v2h-2v2h2v2h2v-2h2V14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/sync_alt.xml b/compose/material/material/icons/generator/raw-icons/outlined/sync_alt.xml
index f899b57..07b1499 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/sync_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/sync_alt.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,8l-4,-4v3H3v2h15v3L22,8z"/>
+ android:pathData="M7.41,13.41l-1.41,-1.41l-4,4l4,4l1.41,-1.41l-1.58,-1.59l15.17,0l0,-2l-15.17,0z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M2,16l4,4v-3h15v-2H6v-3L2,16z"/>
+ android:pathData="M16.59,10.59l1.41,1.41l4,-4l-4,-4l-1.41,1.41l1.58,1.59l-15.17,0l0,2l15.17,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/tips_and_updates.xml b/compose/material/material/icons/generator/raw-icons/outlined/tips_and_updates.xml
new file mode 100644
index 0000000..db5f8c0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/tips_and_updates.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,19h8v-2H5V19zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM14.5,9.5C14.5,6.47 12.03,4 9,4S3.5,6.47 3.5,9.5c0,2.47 1.49,3.89 2.35,4.5h6.3C13.01,13.39 14.5,11.97 14.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/token.xml b/compose/material/material/icons/generator/raw-icons/outlined/token.xml
new file mode 100644
index 0000000..83d4c7d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/token.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,7l-9,-5L3,7v10l9,5l9,-5L21,7zM12,4.29l5.91,3.28L14.9,9.24C14.17,8.48 13.14,8 12,8S9.83,8.48 9.1,9.24L6.09,7.57L12,4.29zM11,19.16l-6,-3.33V9.26l3.13,1.74C8.04,11.31 8,11.65 8,12c0,1.86 1.27,3.43 3,3.87V19.16zM10,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2s-0.9,2 -2,2S10,13.1 10,12zM13,19.16v-3.28c1.73,-0.44 3,-2.01 3,-3.87c0,-0.35 -0.04,-0.69 -0.13,-1.01L19,9.26l0,6.57L13,19.16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/vaccines.xml b/compose/material/material/icons/generator/raw-icons/outlined/vaccines.xml
new file mode 100644
index 0000000..267358f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/vaccines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,5.5H8V4h0.5c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1H6v1.5H3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1V15c0,1.1 0.9,2 2,2h1v4l2,1.5V17h1c1.1,0 2,-0.9 2,-2V7.5c0.55,0 1,-0.45 1,-1C12,5.95 11.55,5.5 11,5.5zM9,9H7.25C6.84,9 6.5,9.34 6.5,9.75c0,0.41 0.34,0.75 0.75,0.75H9V12H7.25c-0.41,0 -0.75,0.34 -0.75,0.75c0,0.41 0.34,0.75 0.75,0.75H9L9,15H5V7.5h4V9zM19.5,10.5V10c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-5c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1v0.5c0,0.5 -1.5,1.16 -1.5,3V20c0,1.1 0.9,2 2,2h4c1.1,0 2,-0.9 2,-2v-6.5C21,11.66 19.5,11 19.5,10.5zM16.5,10.5V10h1v0.5c0,1.6 1.5,2 1.5,3V14h-4c0,-0.21 0,-0.39 0,-0.5C15,12.5 16.5,12.1 16.5,10.5zM19,15.5V17h-4c0,-0.51 0,-1.02 0,-1.5H19zM15,20c0,0 0,-0.63 0,-1.5h4V20H15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_agenda.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_agenda.xml
index 3e4c6fc..282a1dd 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_agenda.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_agenda.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,5v4L4,9L4,5h15m0,10v4L4,19v-4h15m1,-12L3,3c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1zM20,13L3,13c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1z"/>
+ android:pathData="M19,13H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4C21,13.9 20.1,13 19,13zM19,19H5v-4h14V19z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,9H5V5h14V9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_array.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_array.xml
index 15781e6..f069a4a 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_array.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_array.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,7v9h-5L10,7h5m6,-2h-3v13h3L21,5zM17,5L8,5v13h9L17,5zM7,5L4,5v13h3L7,5z"/>
+ android:pathData="M15,7v10H9V7H15zM21,5h-3v14h3V5zM17,5H7v14h10V5zM6,5H3v14h3V5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_carousel.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_carousel.xml
index bf4d53f..64cfc3e 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_carousel.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_carousel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,6h4v11L2,17zM7,19h10L17,4L7,4v15zM9,6h6v11L9,17L9,6zM18,6h4v11h-4z"/>
+ android:pathData="M2,7h4v10H2V7zM7,19h10V5H7V19zM9,7h6v10H9V7zM18,7h4v10h-4V7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_column.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_column.xml
index 935c43a..cadebef 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_column.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_column.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,5v13h17L21,5L4,5zM14,7v9h-3L11,7h3zM6,7h3v9L6,16L6,7zM19,16h-3L16,7h3v9z"/>
+ android:pathData="M3,5v14h18V5H3zM8.33,17H5V7h3.33V17zM13.67,17h-3.33V7h3.33V17zM19,17h-3.33V7H19V17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_list.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_list.xml
index b13c7dd..b2cd4d4 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_list.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_list.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,5v14h17L20,5L3,5zM7,7v2L5,9L5,7h2zM5,13v-2h2v2L5,13zM5,15h2v2L5,17v-2zM18,17L9,17v-2h9v2zM18,13L9,13v-2h9v2zM18,9L9,9L9,7h9v2z"/>
+ android:pathData="M3,5v14h18V5H3zM7,7v2H5V7H7zM5,13v-2h2v2H5zM5,15h2v2H5V15zM19,17H9v-2h10V17zM19,13H9v-2h10V13zM19,9H9V7h10V9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_module.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_module.xml
index 787b876..8bb64c6 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_module.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_module.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,5v13h17L21,5L4,5zM14,7v3.5h-3L11,7h3zM6,7h3v3.5L6,10.5L6,7zM6,16v-3.5h3L9,16L6,16zM11,16v-3.5h3L14,16h-3zM19,16h-3v-3.5h3L19,16zM16,10.5L16,7h3v3.5h-3z"/>
+ android:pathData="M3,5v14h18V5H3zM19,11h-3.33V7H19V11zM13.67,11h-3.33V7h3.33V11zM8.33,7v4H5V7H8.33zM5,17v-4h3.33v4H5zM10.33,17v-4h3.33v4H10.33zM15.67,17v-4H19v4H15.67z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_quilt.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_quilt.xml
index 9824e2b..fe94f61 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_quilt.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_quilt.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,5v13h17L21,5L4,5zM6,16L6,7h3v9L6,16zM11,16v-3.5h3L14,16h-3zM19,16h-3v-3.5h3L19,16zM11,10.5L11,7h8v3.5h-8z"/>
+ android:pathData="M3,5v14h18V5H3zM8.33,17H5V7h3.33V17zM13.67,17h-3.33v-4h3.33V17zM19,17h-3.33v-4H19V17zM19,11h-8.67V7H19V11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_stream.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_stream.xml
index 51ac46e..859c1df 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_stream.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_stream.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,6v12h17L21,6L4,6zM19,16L6,16v-3h13v3zM6,11L6,8h13v3L6,11z"/>
+ android:pathData="M3,7v10c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H5C3.9,5 3,5.9 3,7zM19,17H5v-4h14V17zM5,11V7h14v4H5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/view_week.xml b/compose/material/material/icons/generator/raw-icons/outlined/view_week.xml
index 0e6e4de..a5a50a2 100644
--- a/compose/material/material/icons/generator/raw-icons/outlined/view_week.xml
+++ b/compose/material/material/icons/generator/raw-icons/outlined/view_week.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,4L3,4c-0.55,0 -1,0.45 -1,1v14c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1L22,5c0,-0.55 -0.45,-1 -1,-1zM8,18L4,18L4,6h4v12zM14,18h-4L10,6h4v12zM20,18h-4L16,6h4v12z"/>
+ android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM8,18H4V6h4V18zM14,18h-4V6h4V18zM20,18h-4V6h4V18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/water_drop.xml b/compose/material/material/icons/generator/raw-icons/outlined/water_drop.xml
new file mode 100644
index 0000000..5e49745
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/water_drop.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2c-5.33,4.55 -8,8.48 -8,11.8c0,4.98 3.8,8.2 8,8.2s8,-3.22 8,-8.2C20,10.48 17.33,6.55 12,2zM12,20c-3.35,0 -6,-2.57 -6,-6.2c0,-2.34 1.95,-5.44 6,-9.14c4.05,3.7 6,6.79 6,9.14C18,17.43 15.35,20 12,20zM7.83,14c0.37,0 0.67,0.26 0.74,0.62c0.41,2.22 2.28,2.98 3.64,2.87c0.43,-0.02 0.79,0.32 0.79,0.75c0,0.4 -0.32,0.73 -0.72,0.75c-2.13,0.13 -4.62,-1.09 -5.19,-4.12C7.01,14.42 7.37,14 7.83,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/waving_hand.xml b/compose/material/material/icons/generator/raw-icons/outlined/waving_hand.xml
new file mode 100644
index 0000000..3751772
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/waving_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.03,4.95L3.49,8.49c-3.32,3.32 -3.32,8.7 0,12.02s8.7,3.32 12.02,0l6.01,-6.01c0.97,-0.97 0.97,-2.56 0,-3.54c-0.12,-0.12 -0.25,-0.23 -0.39,-0.32l0.39,-0.39c0.97,-0.97 0.97,-2.56 0,-3.54c-0.16,-0.16 -0.35,-0.3 -0.54,-0.41c0.4,-0.92 0.23,-2.02 -0.52,-2.77c-0.87,-0.87 -2.22,-0.96 -3.2,-0.28c-0.1,-0.15 -0.21,-0.29 -0.34,-0.42c-0.97,-0.97 -2.56,-0.97 -3.54,0l-2.51,2.51c-0.09,-0.14 -0.2,-0.27 -0.32,-0.39C9.58,3.98 8,3.98 7.03,4.95zM8.44,6.37c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-3.18,3.18c1.17,1.17 1.17,3.07 0,4.24l1.41,1.41c1.45,-1.45 1.82,-3.57 1.12,-5.36l6.3,-6.3c0.2,-0.2 0.51,-0.2 0.71,0s0.2,0.51 0,0.71l-4.6,4.6l1.41,1.41l6.01,-6.01c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-6.01,6.01l1.41,1.41l4.95,-4.95c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-5.66,5.66l1.41,1.41l3.54,-3.54c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71L14.1,19.1c-2.54,2.54 -6.65,2.54 -9.19,0s-2.54,-6.65 0,-9.19L8.44,6.37zM23,17c0,3.31 -2.69,6 -6,6v-1.5c2.48,0 4.5,-2.02 4.5,-4.5H23zM1,7c0,-3.31 2.69,-6 6,-6v1.5C4.52,2.5 2.5,4.52 2.5,7H1z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/outlined/workspace_premium.xml b/compose/material/material/icons/generator/raw-icons/outlined/workspace_premium.xml
new file mode 100644
index 0000000..0cf44c9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/outlined/workspace_premium.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9.68,13.69L12,11.93l2.31,1.76l-0.88,-2.85L15.75,9h-2.84L12,6.19L11.09,9H8.25l2.31,1.84L9.68,13.69zM20,10c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8c0,2.03 0.76,3.87 2,5.28V23l6,-2l6,2v-7.72C19.24,13.87 20,12.03 20,10zM12,4c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6S8.69,4 12,4zM12,19l-4,1.02v-3.1C9.18,17.6 10.54,18 12,18s2.82,-0.4 4,-1.08v3.1L12,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/360.xml b/compose/material/material/icons/generator/raw-icons/rounded/360.xml
index 0fa8242..9b849d3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/360.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/360.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7C6.48,7 2,9.24 2,12c0,2.24 2.94,4.13 7,4.77v2.02c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C9.54,12.54 9,12.76 9,13.21v1.52c-3.15,-0.56 -5,-1.9 -5,-2.73c0,-1.06 3.04,-3 8,-3s8,1.94 8,3c0,0.66 -1.2,1.68 -3.32,2.34C16.27,14.47 16,14.85 16,15.28l0,0c0,0.67 0.65,1.16 1.28,0.96C20.11,15.36 22,13.79 22,12C22,9.24 17.52,7 12,7z"/>
+ android:pathData="M12,7C6.48,7 2,9.24 2,12c0,2.24 2.94,4.13 7,4.77v2.02c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36v1.52c-3.15,-0.56 -5,-1.9 -5,-2.73 0,-1.06 3.04,-3 8,-3s8,1.94 8,3c0,0.66 -1.2,1.68 -3.32,2.34 -0.41,0.13 -0.68,0.51 -0.68,0.94 0,0.67 0.65,1.16 1.28,0.96C20.11,15.36 22,13.79 22,12c0,-2.76 -4.48,-5 -10,-5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/3d_rotation.xml b/compose/material/material/icons/generator/raw-icons/rounded/3d_rotation.xml
index 71d74c9..f74db7b05 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/3d_rotation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/3d_rotation.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.01,2C12,2 12,2 12.01,2c-0.9,0 -1.76,0.12 -2.59,0.35c-0.37,0.1 -0.5,0.57 -0.23,0.84l2.96,2.96C12.46,6.46 13,6.24 13,5.79V4.07c3.65,0.46 6.55,3.38 6.95,7.05c0.05,0.5 0.48,0.88 0.99,0.88h0c0.6,0 1.07,-0.53 1,-1.12C21.38,5.89 17.14,2 12.01,2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10.85,17.85C10.54,17.54 10,17.76 10,18.21v1.53c-3.17,-0.82 -5.59,-3.54 -5.95,-6.86C3.99,12.37 3.56,12 3.06,12c-0.6,0 -1.07,0.53 -1,1.12C2.62,18.11 6.87,22 12,22c0.59,0 1.17,-0.06 1.73,-0.16c0.4,-0.07 0.55,-0.56 0.27,-0.85L10.85,17.85z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,9h-3v6h3c0.55,0 1,-0.45 1,-1v-4C16.5,9.45 16.05,9 15.5,9zM15,13.5h-1v-3h1V13.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8.25,13.5c-0.41,0 -0.75,0.34 -0.75,0.75C7.5,14.66 7.84,15 8.25,15h2.25c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1H8.25C7.84,9 7.5,9.34 7.5,9.75c0,0.41 0.34,0.75 0.75,0.75H10v1H9c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h1v1H8.25z"/>
+ android:pathData="M8.41,14.96c-0.19,0 -0.37,-0.03 -0.52,-0.08 -0.16,-0.06 -0.29,-0.13 -0.4,-0.24 -0.11,-0.1 -0.2,-0.22 -0.26,-0.37 -0.06,-0.14 -0.09,-0.3 -0.09,-0.47h-1.3c0,0.36 0.07,0.68 0.21,0.95 0.14,0.27 0.33,0.5 0.56,0.69 0.24,0.18 0.51,0.32 0.82,0.41 0.3,0.1 0.62,0.15 0.96,0.15 0.37,0 0.72,-0.05 1.03,-0.15 0.32,-0.1 0.6,-0.25 0.83,-0.44s0.42,-0.43 0.55,-0.72 0.2,-0.61 0.2,-0.97c0,-0.19 -0.02,-0.38 -0.07,-0.56 -0.05,-0.18 -0.12,-0.35 -0.23,-0.51 -0.1,-0.16 -0.24,-0.3 -0.4,-0.43 -0.17,-0.13 -0.37,-0.23 -0.61,-0.31 0.2,-0.09 0.37,-0.2 0.52,-0.33 0.15,-0.13 0.27,-0.27 0.37,-0.42 0.1,-0.15 0.17,-0.3 0.22,-0.46s0.07,-0.32 0.07,-0.48c0,-0.36 -0.06,-0.68 -0.18,-0.96s-0.29,-0.51 -0.51,-0.69c-0.2,-0.19 -0.47,-0.33 -0.77,-0.43C9.1,8.05 8.76,8 8.39,8c-0.36,0 -0.69,0.05 -1,0.16 -0.3,0.11 -0.57,0.26 -0.79,0.45 -0.21,0.19 -0.38,0.41 -0.51,0.67 -0.12,0.26 -0.18,0.54 -0.18,0.85h1.3c0,-0.17 0.03,-0.32 0.09,-0.45s0.14,-0.25 0.25,-0.34 0.23,-0.17 0.38,-0.22 0.3,-0.08 0.48,-0.08c0.4,0 0.7,0.1 0.89,0.31 0.19,0.2 0.29,0.49 0.29,0.86 0,0.18 -0.03,0.34 -0.08,0.49s-0.14,0.27 -0.25,0.37c-0.11,0.1 -0.25,0.18 -0.41,0.24 -0.16,0.06 -0.36,0.09 -0.58,0.09L7.5,11.4v1.03h0.77c0.22,0 0.42,0.02 0.6,0.07s0.33,0.13 0.45,0.23c0.12,0.11 0.22,0.24 0.29,0.4s0.1,0.35 0.1,0.57c0,0.41 -0.12,0.72 -0.35,0.93 -0.23,0.23 -0.55,0.33 -0.95,0.33zM17.71,10.24c-0.18,-0.47 -0.43,-0.87 -0.75,-1.2 -0.32,-0.33 -0.7,-0.59 -1.14,-0.77 -0.43,-0.18 -0.92,-0.27 -1.46,-0.27L12,8v8h2.3c0.55,0 1.06,-0.09 1.51,-0.27s0.84,-0.43 1.16,-0.76c0.32,-0.33 0.57,-0.73 0.74,-1.19 0.17,-0.47 0.26,-0.99 0.26,-1.57v-0.4c0,-0.58 -0.09,-1.1 -0.26,-1.57zM16.58,12.2c0,0.42 -0.05,0.79 -0.14,1.13 -0.1,0.33 -0.24,0.62 -0.43,0.85s-0.43,0.41 -0.71,0.53c-0.29,0.12 -0.62,0.18 -0.99,0.18h-0.91L13.4,9.11h0.97c0.72,0 1.27,0.23 1.64,0.69 0.38,0.46 0.57,1.12 0.57,1.99v0.41zM15.15,3.84l1.33,-1.33c3.09,1.46 5.34,4.37 5.89,7.86 0.06,0.41 0.44,0.69 0.86,0.62 0.41,-0.06 0.69,-0.45 0.62,-0.86 -0.6,-3.81 -2.96,-7.01 -6.24,-8.75C15.94,0.49 13.78,-0.13 11.34,0.02l3.81,3.82zM8.85,20.15l-1.33,1.33c-3.09,-1.46 -5.34,-4.37 -5.89,-7.86 -0.06,-0.41 -0.44,-0.69 -0.86,-0.62 -0.41,0.06 -0.69,0.45 -0.62,0.86 0.6,3.81 2.96,7.01 6.24,8.75 1.67,0.89 3.83,1.51 6.27,1.36l-3.81,-3.82z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/4k.xml b/compose/material/material/icons/generator/raw-icons/rounded/4k.xml
index aa15959..821b9d8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/4k.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/4k.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.11,3 19,3zM12,12.76c0,0.41 -0.34,0.75 -0.75,0.75H11v0.74c0,0.41 -0.34,0.75 -0.75,0.75S9.5,14.66 9.5,14.25V13.5h-2c-0.55,0 -1,-0.45 -1,-1V9.75C6.5,9.34 6.84,9 7.25,9S8,9.34 8,9.75V12h1.5V9.75C9.5,9.34 9.84,9 10.25,9S11,9.34 11,9.75V12h0.25c0.41,0 0.75,0.34 0.75,0.75V12.76zM17.16,13.88C17.5,14.34 17.17,15 16.59,15c-0.22,0 -0.42,-0.1 -0.55,-0.27l-1.54,-1.98v1.5c0,0.41 -0.34,0.75 -0.75,0.75S13,14.66 13,14.25v-4.5C13,9.34 13.34,9 13.75,9s0.75,0.34 0.75,0.75v1.5l1.54,-1.98C16.17,9.1 16.38,9 16.59,9c0.58,0 0.91,0.66 0.56,1.12L15.75,12L17.16,13.88z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.89,-2 -2,-2zM12,12.76c0,0.41 -0.34,0.75 -0.75,0.75L11,13.51v0.74c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75v-0.75h-2c-0.55,0 -1,-0.45 -1,-1L6.5,9.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75L8,12h1.5L9.5,9.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75L11,12h0.25c0.41,0 0.75,0.34 0.75,0.75v0.01zM17.47,13.9c0.22,0.33 0.13,0.77 -0.2,0.98 -0.12,0.08 -0.26,0.12 -0.39,0.12 -0.23,0 -0.45,-0.11 -0.59,-0.32L14.5,12v2.24c0,0.41 -0.34,0.75 -0.75,0.75 -0.41,0.01 -0.75,-0.33 -0.75,-0.74v-4.5c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75v2.24l1.79,-2.68c0.22,-0.33 0.66,-0.41 0.98,-0.2 0.33,0.22 0.41,0.66 0.2,0.98L16.2,12l1.27,1.9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/ac_unit.xml b/compose/material/material/icons/generator/raw-icons/rounded/ac_unit.xml
index 6ff3843..fa78aa8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/ac_unit.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/ac_unit.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,11h-3.17l2.54,-2.54c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.03,-0.39 -1.42,0L15,11h-2V9l3.95,-3.95c0.39,-0.39 0.39,-1.03 0,-1.42l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L13,6.17V3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v3.17L8.46,3.63c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.03 0,1.42L11,9v2H9L5.05,7.05c-0.39,-0.39 -1.03,-0.39 -1.42,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L6.17,11H3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3.17l-2.54,2.54c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.03,0.39 1.42,0L9,13h2v2l-3.95,3.95c-0.39,0.39 -0.39,1.03 0,1.42l0,0c0.39,0.39 1.02,0.39 1.41,0L11,17.83V21c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-3.17l2.54,2.54c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.03 0,-1.42L13,15v-2h2l3.95,3.95c0.39,0.39 1.03,0.39 1.42,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L17.83,13H21c0.55,0 1,-0.45 1,-1l0,0C22,11.45 21.55,11 21,11z"/>
+ android:pathData="M21,11h-3.17l2.54,-2.54c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.03,-0.39 -1.42,0L15,11h-2V9l3.95,-3.95c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0L13,6.17V3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3.17L8.46,3.63c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.03 0,1.42L11,9v2H9L5.05,7.05c-0.39,-0.39 -1.03,-0.39 -1.42,0 -0.39,0.39 -0.39,1.02 0,1.41L6.17,11H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3.17l-2.54,2.54c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.03,0.39 1.42,0L9,13h2v2l-3.95,3.95c-0.39,0.39 -0.39,1.03 0,1.42 0.39,0.39 1.02,0.39 1.41,0L11,17.83V21c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3.17l2.54,2.54c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.03 0,-1.42L13,15v-2h2l3.95,3.95c0.39,0.39 1.03,0.39 1.42,0 0.39,-0.39 0.39,-1.02 0,-1.41L17.83,13H21c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/access_alarm.xml b/compose/material/material/icons/generator/raw-icons/rounded/access_alarm.xml
index 20601f5..1aa074c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/access_alarm.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/access_alarm.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c4.97,0 9,-4.03 9,-9S16.97,4 12,4zM15.5,16.5c-0.39,0.39 -1.02,0.39 -1.41,0l-2.79,-2.79C11.11,13.52 11,13.27 11,13V9c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3.59l2.5,2.5C15.89,15.48 15.89,16.11 15.5,16.5zM4.88,3.05L2.05,5.88c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l2.83,-2.83c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C5.9,2.66 5.27,2.66 4.88,3.05zM17.71,3.05L17.71,3.05c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.83,-2.83C18.73,2.66 18.1,2.66 17.71,3.05z"/>
+ android:pathData="M15.87,15.25l-3.37,-2L12.5,8.72c0,-0.4 -0.32,-0.72 -0.72,-0.72h-0.06c-0.4,0 -0.72,0.32 -0.72,0.72v4.72c0,0.35 0.18,0.68 0.49,0.86l3.65,2.19c0.34,0.2 0.78,0.1 0.98,-0.24 0.21,-0.35 0.1,-0.8 -0.25,-1zM21.18,5.01L18.1,2.45c-0.42,-0.35 -1.05,-0.3 -1.41,0.13 -0.35,0.42 -0.29,1.05 0.13,1.41l3.07,2.56c0.42,0.35 1.05,0.3 1.41,-0.13 0.36,-0.42 0.3,-1.05 -0.12,-1.41zM4.1,6.55l3.07,-2.56c0.43,-0.36 0.49,-0.99 0.13,-1.41 -0.35,-0.43 -0.98,-0.48 -1.4,-0.13L2.82,5.01c-0.42,0.36 -0.48,0.99 -0.12,1.41 0.35,0.43 0.98,0.48 1.4,0.13zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/access_alarms.xml b/compose/material/material/icons/generator/raw-icons/rounded/access_alarms.xml
index 20601f5..1aa074c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/access_alarms.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/access_alarms.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c4.97,0 9,-4.03 9,-9S16.97,4 12,4zM15.5,16.5c-0.39,0.39 -1.02,0.39 -1.41,0l-2.79,-2.79C11.11,13.52 11,13.27 11,13V9c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3.59l2.5,2.5C15.89,15.48 15.89,16.11 15.5,16.5zM4.88,3.05L2.05,5.88c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l2.83,-2.83c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C5.9,2.66 5.27,2.66 4.88,3.05zM17.71,3.05L17.71,3.05c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.83,-2.83C18.73,2.66 18.1,2.66 17.71,3.05z"/>
+ android:pathData="M15.87,15.25l-3.37,-2L12.5,8.72c0,-0.4 -0.32,-0.72 -0.72,-0.72h-0.06c-0.4,0 -0.72,0.32 -0.72,0.72v4.72c0,0.35 0.18,0.68 0.49,0.86l3.65,2.19c0.34,0.2 0.78,0.1 0.98,-0.24 0.21,-0.35 0.1,-0.8 -0.25,-1zM21.18,5.01L18.1,2.45c-0.42,-0.35 -1.05,-0.3 -1.41,0.13 -0.35,0.42 -0.29,1.05 0.13,1.41l3.07,2.56c0.42,0.35 1.05,0.3 1.41,-0.13 0.36,-0.42 0.3,-1.05 -0.12,-1.41zM4.1,6.55l3.07,-2.56c0.43,-0.36 0.49,-0.99 0.13,-1.41 -0.35,-0.43 -0.98,-0.48 -1.4,-0.13L2.82,5.01c-0.42,0.36 -0.48,0.99 -0.12,1.41 0.35,0.43 0.98,0.48 1.4,0.13zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/access_time.xml b/compose/material/material/icons/generator/raw-icons/rounded/access_time.xml
index b82761b..07b7ee3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/access_time.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/access_time.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM16,16c-0.39,0.39 -1.02,0.39 -1.41,0l-3.29,-3.29C11.11,12.52 11,12.27 11,12V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3.59l3,3C16.39,14.98 16.39,15.61 16,16z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM11.78,7h-0.06c-0.4,0 -0.72,0.32 -0.72,0.72v4.72c0,0.35 0.18,0.68 0.49,0.86l4.15,2.49c0.34,0.2 0.78,0.1 0.98,-0.24 0.21,-0.34 0.1,-0.79 -0.25,-0.99l-3.87,-2.3L12.5,7.72c0,-0.4 -0.32,-0.72 -0.72,-0.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/accessibility.xml b/compose/material/material/icons/generator/raw-icons/rounded/accessibility.xml
index 9351542..c500592 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/accessibility.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/accessibility.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2c1.1,0 2,0.9 2,2s-0.9,2 -2,2s-2,-0.9 -2,-2S10.9,2 12,2zM20,9h-5v12c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-5h-2v5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V9H4C3.45,9 3,8.55 3,8s0.45,-1 1,-1h16c0.55,0 1,0.45 1,1S20.55,9 20,9z"/>
+ android:pathData="M12,2c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2zM20,9h-5v12c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-5h-2v5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L9,9L4,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h16c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/accessibility_new.xml b/compose/material/material/icons/generator/raw-icons/rounded/accessibility_new.xml
index 2eb6176..e760276 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/accessibility_new.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/accessibility_new.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.75,6.99c-0.14,-0.55 -0.69,-0.87 -1.24,-0.75C17.13,6.77 14.48,7 12,7S6.87,6.77 4.49,6.24c-0.55,-0.12 -1.1,0.2 -1.24,0.75C3.11,7.55 3.45,8.12 4,8.25C5.61,8.61 7.35,8.86 9,9v12c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5h2v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1V9c1.65,-0.14 3.39,-0.39 4.99,-0.75C20.55,8.12 20.89,7.55 20.75,6.99zM12,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S10.9,6 12,6z"/>
+ android:pathData="M20.75,6.99c-0.14,-0.55 -0.69,-0.87 -1.24,-0.75 -2.38,0.53 -5.03,0.76 -7.51,0.76s-5.13,-0.23 -7.51,-0.76c-0.55,-0.12 -1.1,0.2 -1.24,0.75 -0.14,0.56 0.2,1.13 0.75,1.26 1.61,0.36 3.35,0.61 5,0.75v12c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5h2v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1V9c1.65,-0.14 3.39,-0.39 4.99,-0.75 0.56,-0.13 0.9,-0.7 0.76,-1.26zM12,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/accessible.xml b/compose/material/material/icons/generator/raw-icons/rounded/accessible.xml
index 4ca30c5..97960e3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/accessible.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/accessible.xml
@@ -10,5 +10,5 @@
android:pathData="M12,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11.91L19,11.91c0,-0.49 -0.36,-0.89 -0.84,-0.96c-2.2,-0.33 -3.46,-2.04 -4.52,-3.2C12.37,6.32 10,7.07 10,9.12V15c0,1.1 0.9,2 2,2h5v4c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-4.5c0,-1.1 -0.9,-2 -2,-2h-3v-3.45c1,0.83 2.41,1.54 3.81,1.82C18.42,13 19,12.54 19,11.91zM12.83,18c-0.41,1.16 -1.52,2 -2.83,2c-1.66,0 -3,-1.34 -3,-3c0,-1.31 0.84,-2.41 2,-2.83V12.1c-2.28,0.46 -4,2.48 -4,4.9c0,2.76 2.24,5 5,5c2.42,0 4.44,-1.72 4.9,-4H12.83z"/>
+ android:pathData="M19,11.9c0,-0.49 -0.36,-0.89 -0.84,-0.97 -1.25,-0.21 -2.43,-0.88 -3.23,-1.76l-1.29,-1.43c-0.17,-0.19 -0.38,-0.34 -0.61,-0.45 -0.01,0 -0.01,-0.01 -0.02,-0.01H13c-0.37,-0.21 -0.78,-0.31 -1.25,-0.25C10.73,7.15 10,8.07 10,9.1V15c0,1.1 0.9,2 2,2h5v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4.5c0,-1.1 -0.9,-2 -2,-2h-3v-3.45c1,0.83 2.4,1.54 3.8,1.82 0.62,0.13 1.2,-0.34 1.2,-0.97zM12.83,18c-0.41,1.16 -1.52,2 -2.83,2 -1.66,0 -3,-1.34 -3,-3 0,-1.31 0.84,-2.41 2,-2.83V12.1c-2.28,0.46 -4,2.48 -4,4.9 0,2.76 2.24,5 5,5 2.42,0 4.44,-1.72 4.9,-4h-2.07z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/accessible_forward.xml b/compose/material/material/icons/generator/raw-icons/rounded/accessible_forward.xml
index 37c68e4..d50cad1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/accessible_forward.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/accessible_forward.xml
@@ -7,11 +7,8 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,4.5m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M18,4.54m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M10,20c-1.65,0 -3,-1.35 -3,-3s1.35,-3 3,-3v-2c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5h-2C13,18.65 11.65,20 10,20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,13.5h-1.86l1.67,-3.67C18.42,8.5 17.44,7 15.96,7h-5.2C9.95,7 9.22,7.47 8.89,8.2L8.61,8.96c-0.21,0.56 0.11,1.17 0.68,1.33c0.49,0.14 1,-0.11 1.2,-0.58L10.79,9H13l-1.83,4.1c-0.6,1.33 0.39,2.9 1.85,2.9H18v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4.5C20,14.4 19.1,13.5 18,13.5z"/>
+ android:pathData="M15,17h-2c0,1.65 -1.35,3 -3,3s-3,-1.35 -3,-3 1.35,-3 3,-3v-2c-2.76,0 -5,2.24 -5,5s2.24,5 5,5 5,-2.24 5,-5zM18,13.5h-1.86l1.67,-3.67C18.42,8.5 17.44,7 15.96,7h-5.2c-0.81,0 -1.54,0.47 -1.87,1.2l-0.28,0.76c-0.21,0.56 0.11,1.17 0.68,1.33 0.49,0.14 1,-0.11 1.2,-0.58l0.3,-0.71L13,9l-1.83,4.1c-0.6,1.33 0.39,2.9 1.85,2.9L18,16v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4.5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/account_balance.xml b/compose/material/material/icons/generator/raw-icons/rounded/account_balance.xml
index d88707e..82568cb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/account_balance.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/account_balance.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,11v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5c0,-0.55 -0.45,-1 -1,-1S5,10.45 5,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,11v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5c0,-0.55 -0.45,-1 -1,-1S11,10.45 11,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,19H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h18c0.55,0 1,-0.45 1,-1S21.55,19 21,19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,11v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5c0,-0.55 -0.45,-1 -1,-1S17,10.45 17,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.24,8h17.53c1.31,0 1.71,-1.76 0.55,-2.34l-8.42,-4.21c-0.56,-0.28 -1.23,-0.28 -1.79,0L2.68,5.66C1.52,6.24 1.94,8 3.24,8z"/>
+ android:pathData="M4,11.5v4c0,0.83 0.67,1.5 1.5,1.5S7,16.33 7,15.5v-4c0,-0.83 -0.67,-1.5 -1.5,-1.5S4,10.67 4,11.5zM10,11.5v4c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5zM3.5,22h16c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5h-16c-0.83,0 -1.5,0.67 -1.5,1.5S2.67,22 3.5,22zM16,11.5v4c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5zM10.57,1.49l-7.9,4.16c-0.41,0.21 -0.67,0.64 -0.67,1.1C2,7.44 2.56,8 3.25,8h16.51C20.44,8 21,7.44 21,6.75c0,-0.46 -0.26,-0.89 -0.67,-1.1l-7.9,-4.16c-0.58,-0.31 -1.28,-0.31 -1.86,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/account_balance_wallet.xml b/compose/material/material/icons/generator/raw-icons/rounded/account_balance_wallet.xml
index a7244a8..b21e69d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/account_balance_wallet.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/account_balance_wallet.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,16V8c0,-1.1 0.89,-2 2,-2h9V5c0,-1.1 -0.9,-2 -2,-2H5C3.89,3 3,3.9 3,5v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-1h-9C10.89,18 10,17.1 10,16zM13,8c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1H13zM16,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S16.83,13.5 16,13.5z"/>
+ android:pathData="M10,16L10,8c0,-1.1 0.89,-2 2,-2h9L21,5c0,-1.1 -0.9,-2 -2,-2L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-1h-9c-1.11,0 -2,-0.9 -2,-2zM13,8c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h9L22,8h-9zM16,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/account_box.xml b/compose/material/material/icons/generator/raw-icons/rounded/account_box.xml
index 32f6b3f..3481c02 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/account_box.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/account_box.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,6c1.93,0 3.5,1.57 3.5,3.5c0,1.93 -1.57,3.5 -3.5,3.5s-3.5,-1.57 -3.5,-3.5C8.5,7.57 10.07,6 12,6zM19,19H5v-0.23c0,-0.62 0.28,-1.2 0.76,-1.58C7.47,15.82 9.64,15 12,15s4.53,0.82 6.24,2.19c0.48,0.38 0.76,0.97 0.76,1.58V19z"/>
+ android:pathData="M3,5v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2L5,3c-1.11,0 -2,0.9 -2,2zM15,9c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3 1.34,-3 3,-3 3,1.34 3,3zM6,17c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1L6,18v-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/account_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/account_circle.xml
index 6476320..89199eb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/account_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/account_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,6c1.93,0 3.5,1.57 3.5,3.5S13.93,13 12,13s-3.5,-1.57 -3.5,-3.5S10.07,6 12,6zM12,20c-2.03,0 -4.43,-0.82 -6.14,-2.88C7.55,15.8 9.68,15 12,15s4.45,0.8 6.14,2.12C16.43,19.18 14.03,20 12,20z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/account_tree.xml b/compose/material/material/icons/generator/raw-icons/rounded/account_tree.xml
index b13bb4e..fb02e0f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/account_tree.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/account_tree.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,11h3c1.11,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2h-3c-1.1,0 -2,0.9 -2,2v1H9.01V5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v4c0,1.1 0.9,2 2,2h3c1.1,0 2,-0.9 2,-2V8h2v8c0,1.1 0.9,2 2,2h2v1c0,1.11 0.9,2 2,2h3c1.11,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2h-3c-1.1,0 -2,0.9 -2,2v1h-2V8h2v1C15,10.1 15.9,11 17,11z"/>
+ android:pathData="M17,11h3c1.11,0 2,-0.9 2,-2V5c0,-1.11 -0.9,-2 -2,-2h-3c-1.11,0 -2,0.9 -2,2v1H9.01V5c0,-1.11 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v4c0,1.11 0.9,2 2,2h3c1.11,0 2,-0.9 2,-2V8H11v7.01c0,1.65 1.34,2.99 2.99,2.99H15v1c0,1.11 0.9,2 2,2h3c1.11,0 2,-0.9 2,-2v-4c0,-1.11 -0.9,-2 -2,-2h-3c-1.11,0 -2,0.9 -2,2v1h-1.01C13.45,16 13,15.55 13,15.01V8h2v1C15,10.1 15.9,11 17,11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/ad_units.xml b/compose/material/material/icons/generator/raw-icons/rounded/ad_units.xml
index 246d430..64c855e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/ad_units.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/ad_units.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1 17,1zM17,18H7V6h10V18zM9,9h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H9C8.45,7 8,7.45 8,8S8.45,9 9,9z"/>
+ android:pathData="M17,1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1 17,1zM16,19H8c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v12C17,18.55 16.55,19 16,19z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,6H9C8.45,6 8,6.45 8,7v0c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v0C16,6.45 15.55,6 15,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/adb.xml b/compose/material/material/icons/generator/raw-icons/rounded/adb.xml
index 07f0815..c96346e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/adb.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/adb.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,10v1h14v-1c0,-2.38 -1.19,-4.48 -3,-5.74l1.87,-1.87L16.99,1.5l-2.12,2.12C13.99,3.22 13.02,3 12,3s-1.99,0.22 -2.87,0.62L7.01,1.5L6.13,2.38L8,4.26C6.19,5.52 5,7.62 5,10zM15,7c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S14.45,7 15,7zM9,7c0.55,0 1,0.45 1,1S9.55,9 9,9S8,8.55 8,8S8.45,7 9,7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5,12v4c0,3.87 3.13,7 7,7s7,-3.13 7,-7v-4H5z"/>
+ android:pathData="M5,16c0,3.87 3.13,7 7,7s7,-3.13 7,-7v-4L5,12v4zM16.12,4.37l2.1,-2.1 -0.82,-0.83 -2.3,2.31C14.16,3.28 13.12,3 12,3s-2.16,0.28 -3.09,0.75L6.6,1.44l-0.82,0.83 2.1,2.1C6.14,5.64 5,7.68 5,10v1h14v-1c0,-2.32 -1.14,-4.36 -2.88,-5.63zM9,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM15,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add.xml b/compose/material/material/icons/generator/raw-icons/rounded/add.xml
index 4767482..24877ee 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,13h-5v5c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-5H6c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h5V6c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v5h5c0.55,0 1,0.45 1,1l0,0C19,12.55 18.55,13 18,13z"/>
+ android:pathData="M18,13h-5v5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-5H6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h5V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5h5c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_a_photo.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_a_photo.xml
index 588e84c..b34e69e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_a_photo.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_a_photo.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,14m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+ android:pathData="M3,8c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2H1c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M21,4V3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1h-1c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1v1c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V6h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H21z"/>
+ android:pathData="M13,14m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17,8h-1c-0.55,0 -1,-0.45 -1,-1V4H8.88c-0.56,0 -1.1,0.24 -1.48,0.65L6.17,6H3C1.9,6 1,6.9 1,8v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V10h-3c-0.55,0 -1,-0.45 -1,-1V8zM11,18.5c-2.48,0 -4.5,-2.02 -4.5,-4.5S8.52,9.5 11,9.5s4.5,2.02 4.5,4.5S13.48,18.5 11,18.5z"/>
+ android:pathData="M21,6h-3.17l-1.24,-1.35c-0.37,-0.41 -0.91,-0.65 -1.47,-0.65h-6.4c0.17,0.3 0.28,0.63 0.28,1 0,1.1 -0.9,2 -2,2L6,7v1c0,1.1 -0.9,2 -2,2 -0.37,0 -0.7,-0.11 -1,-0.28L3,20c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L23,8c0,-1.1 -0.9,-2 -2,-2zM13,19c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_alarm.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_alarm.xml
index 9a36a2a..2b64fd2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_alarm.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_alarm.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.97,0 -9,4.03 -9,9c0,4.97 4.03,9 9,9s9,-4.03 9,-9C21,8.03 16.97,4 12,4zM15,14h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1S15.55,14 15,14z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.29,4.46c0.39,-0.39 0.39,-1.02 0,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0L2.05,5.88c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0L6.29,4.46z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.95,5.88l-2.83,-2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0v0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0v0C22.34,6.9 22.34,6.27 21.95,5.88z"/>
+ android:pathData="M15,12h-2v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2L9,12c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM21.18,5.01L18.1,2.45c-0.42,-0.35 -1.05,-0.3 -1.41,0.13 -0.35,0.42 -0.29,1.05 0.13,1.41l3.07,2.56c0.42,0.35 1.05,0.3 1.41,-0.13 0.36,-0.42 0.3,-1.05 -0.12,-1.41zM4.1,6.55l3.07,-2.56c0.43,-0.36 0.49,-0.99 0.13,-1.41 -0.35,-0.43 -0.98,-0.48 -1.4,-0.13L2.82,5.01c-0.42,0.36 -0.48,0.99 -0.12,1.41 0.35,0.43 0.98,0.48 1.4,0.13zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_box.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_box.xml
index d258c7a..2cefe36 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_box.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_box.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.89,3 3,3.9 3,5v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM16,13h-3v3c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-3H8c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h3V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v3h3c0.55,0 1,0.45 1,1l0,0C17,12.55 16.55,13 16,13z"/>
+ android:pathData="M19,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM16,13h-3v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_business.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_business.xml
index 5809280..d15e3bf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_business.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_business.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,4h13c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H3C2.45,6 2,5.55 2,5v0C2,4.45 2.45,4 3,4z"/>
+ android:pathData="M3,6h13c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1H3C2.45,4 2,4.45 2,5C2,5.55 2.45,6 3,6z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M16,17L16,17c0.55,0 1,-0.45 1,-1v-2h0c0.55,0 1,-0.45 1,-1v-0.9c0,-0.07 -0.01,-0.13 -0.02,-0.2l-0.82,-4.1C17.07,7.34 16.66,7 16.18,7H2.82C2.34,7 1.93,7.34 1.84,7.8l-0.82,4.1C1.01,11.97 1,12.03 1,12.1V13c0,0.55 0.45,1 1,1h0v5c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1v-5h4v2C15,16.55 15.45,17 16,17zM9,18H4v-4h5V18z"/>
+ android:pathData="M15,17h2v-3h0.18c0.63,0 1.1,-0.58 0.98,-1.2l-1,-5C17.07,7.34 16.66,7 16.18,7H2.82C2.34,7 1.93,7.34 1.84,7.8l-1,5C0.72,13.42 1.19,14 1.82,14H2v5c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1v-5h4V17zM9,18H4v-4h5V18z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M22,18h-2v-2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1v0C23,18.45 22.55,18 22,18z"/>
+ android:pathData="M22,18h-2v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1C23,18.45 22.55,18 22,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_circle.xml
index 0409efd..1906afe 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM16,13h-3v3c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-3H8c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h3V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v3h3c0.55,0 1,0.45 1,1l0,0C17,12.55 16.55,13 16,13z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM16,13h-3v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_circle_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_circle_outline.xml
index 8740374..28bd03f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_circle_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_circle_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7L12,7c-0.55,0 -1,0.45 -1,1v3H8c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-3V8C13,7.45 12.55,7 12,7zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/>
+ android:pathData="M12,7c-0.55,0 -1,0.45 -1,1v3L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L13,8c0,-0.55 -0.45,-1 -1,-1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_comment.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_comment.xml
index 8b93553..1b22ee4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_comment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_comment.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3.71,20.29L6,18h14c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2H4C2.9,2 2,2.9 2,4v15.59C2,20.48 3.08,20.92 3.71,20.29zM11,11H9c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h2V7c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2h2c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1h-2v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V11z"/>
+ android:pathData="M22,4c0,-1.1 -0.9,-2 -2,-2L4,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4L22,4zM16,11h-3v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3L8,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3L11,6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_ic_call.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_ic_call.xml
index abdd836..92faa8d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_ic_call.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_ic_call.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,8h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V8h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2V4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1S13.45,8 14,8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M14,8h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L18,8h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2L18,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM19.21,15.27l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.04 0.57,-1.64l-0.29,-2.52c-0.11,-1.01 -0.97,-1.78 -1.98,-1.78L5.02,3.01c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1 -0.76,-1.86 -1.77,-1.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_photo_alternate.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_photo_alternate.xml
index 5eaf9d8..84e79d6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_photo_alternate.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_photo_alternate.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,9h-1c-0.55,0 -1,-0.45 -1,-1V3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-8h-5c-0.55,0 -1,-0.45 -1,-1V9zM17,17H7c-0.41,0 -0.65,-0.47 -0.4,-0.8l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,16l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67C17.65,16.53 17.41,17 17,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,5V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1h-1c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1v1c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V7h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H19z"/>
+ android:pathData="M21.02,5H19V2.98c0,-0.54 -0.44,-0.98 -0.98,-0.98h-0.03c-0.55,0 -0.99,0.44 -0.99,0.98V5h-2.01c-0.54,0 -0.98,0.44 -0.99,0.98v0.03c0,0.55 0.44,0.99 0.99,0.99H17v2.01c0,0.54 0.44,0.99 0.99,0.98h0.03c0.54,0 0.98,-0.44 0.98,-0.98V7h2.02c0.54,0 0.98,-0.44 0.98,-0.98v-0.04c0,-0.54 -0.44,-0.98 -0.98,-0.98zM16,9.01V8h-1.01c-0.53,0 -1.03,-0.21 -1.41,-0.58 -0.37,-0.38 -0.58,-0.88 -0.58,-1.44 0,-0.36 0.1,-0.69 0.27,-0.98H5c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-8.28c-0.3,0.17 -0.64,0.28 -1.02,0.28 -1.09,-0.01 -1.98,-0.9 -1.98,-1.99zM15.96,19H6c-0.41,0 -0.65,-0.47 -0.4,-0.8l1.98,-2.63c0.21,-0.28 0.62,-0.26 0.82,0.02L10,18l2.61,-3.48c0.2,-0.26 0.59,-0.27 0.79,-0.01l2.95,3.68c0.26,0.33 0.03,0.81 -0.39,0.81z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_road.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_road.xml
index 27ea912..07aa064 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_road.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_road.xml
@@ -6,20 +6,20 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,18v-2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H20z"/>
+ android:pathData="M20,18v-2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H20z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4L19,4c-0.55,0 -1,0.45 -1,1v7c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5C20,4.45 19.55,4 19,4z"/>
+ android:pathData="M19,4L19,4c-0.55,0 -1,0.45 -1,1v7c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5C20,4.45 19.55,4 19,4z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M5,20L5,20c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1l0,0C4.45,4 4,4.45 4,5v14C4,19.55 4.45,20 5,20z"/>
+ android:pathData="M5,20L5,20c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1h0C4.45,4 4,4.45 4,5v14C4,19.55 4.45,20 5,20z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8L12,8c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v2C11,7.55 11.45,8 12,8z"/>
+ android:pathData="M12,8L12,8c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2C11,7.55 11.45,8 12,8z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,14L12,14c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v2C11,13.55 11.45,14 12,14z"/>
+ android:pathData="M12,14L12,14c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2C11,13.55 11.45,14 12,14z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,20L12,20c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v2C11,19.55 11.45,20 12,20z"/>
+ android:pathData="M12,20L12,20c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2C11,19.55 11.45,20 12,20z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_to_home_screen.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_to_home_screen.xml
index f265bf6..427631f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_to_home_screen.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_to_home_screen.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.29,13.29c0.63,0.63 1.71,0.18 1.71,-0.71V9c0,-0.55 -0.45,-1 -1,-1H7.41C6.52,8 6.08,9.08 6.71,9.71l1.09,1.09L3.7,14.89c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0l4.09,-4.09L10.29,13.29z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,1H8C6.9,1 6,1.9 6,3v4h2V6h10v12H8v-1H6v4c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C20,1.9 19.1,1 18,1z"/>
+ android:pathData="M18,1.01L8,1c-1.1,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1V5h10v14H8v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM11,15c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2.59L3.7,14.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L10,11.41V14c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_to_photos.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_to_photos.xml
index fe89126..1fee4b6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_to_photos.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_to_photos.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,11h-2v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-2h-2c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h2V7c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2h2c0.55,0 1,0.45 1,1v0C18,10.55 17.55,11 17,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M3,6c-0.55,0 -1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,11h-3v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3L13,6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/add_to_queue.xml b/compose/material/material/icons/generator/raw-icons/rounded/add_to_queue.xml
index 2d19981..a1adb4a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/add_to_queue.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/add_to_queue.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h4c1.1,0 2,-0.9 2,-2V5C22,3.89 21.1,3 20,3zM20,17H4V5h16V17zM16,11L16,11c0,0.55 -0.45,1 -1,1h-2v2c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h2V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v2h2C15.55,10 16,10.45 16,11z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h5c1.1,0 2,-0.9 2,-2L23,5c0,-1.11 -0.9,-2 -2,-2zM20,17L4,17c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1zM16,11c0,0.55 -0.45,1 -1,1h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2L9,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/addchart.xml b/compose/material/material/icons/generator/raw-icons/rounded/addchart.xml
index 8c4efe3..9e0b573 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/addchart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/addchart.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,17c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2C15,16.55 15.45,17 16,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,10c-0.55,0 -1,0.45 -1,1v8H5V5h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-8C21,10.45 20.55,10 20,10z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,11v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5c0,-0.55 -0.45,-1 -1,-1S7,10.45 7,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,8v8c0,0.55 0.45,1 1,1s1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1S11,7.45 11,8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,7h1v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1V4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1h-1c-0.55,0 -1,0.45 -1,1S15.45,7 16,7z"/>
+ android:pathData="M11,10c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v7h-2V10zM20,13c-0.55,0 -1,0.45 -1,1v5H5V5h5c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-5C21,13.45 20.55,13 20,13zM21,5h-2V3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7h2c0.55,0 1,-0.45 1,-1C22,5.45 21.55,5 21,5zM16,13c-0.55,0 -1,0.45 -1,1v3h2v-3C17,13.45 16.55,13 16,13zM7,12v5h2v-5c0,-0.55 -0.45,-1 -1,-1S7,11.45 7,12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/adjust.xml b/compose/material/material/icons/generator/raw-icons/rounded/adjust.xml
index ef7b898..85c2377 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/adjust.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/adjust.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10s10,-4.49 10,-10S17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM15,12c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3s1.34,-3 3,-3S15,10.34 15,12z"/>
+ android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10 10,-4.49 10,-10S17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15,12c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3 1.34,-3 3,-3 3,1.34 3,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/admin_panel_settings.xml b/compose/material/material/icons/generator/raw-icons/rounded/admin_panel_settings.xml
index 9c6a41e..d3c0b67 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/admin_panel_settings.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/admin_panel_settings.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,10c1.08,0 2.09,0.25 3,0.68v-4.3c0,-0.83 -0.52,-1.58 -1.3,-1.87l-6,-2.25c-0.45,-0.17 -0.95,-0.17 -1.4,0l-6,2.25C4.52,4.81 4,5.55 4,6.39v4.7c0,5.05 3.41,9.76 8,10.91c0.03,-0.01 0.05,-0.02 0.08,-0.02C10.8,20.71 10,18.95 10,17C10,13.13 13.13,10 17,10z"/>
+ android:pathData="M17,11c0.34,0 0.67,0.04 1,0.09V7.58c0,-0.8 -0.47,-1.52 -1.2,-1.83l-5.5,-2.4c-0.51,-0.22 -1.09,-0.22 -1.6,0l-5.5,2.4C3.47,6.07 3,6.79 3,7.58v3.6c0,4.54 3.2,8.79 7.5,9.82c0.55,-0.13 1.08,-0.32 1.6,-0.55C11.41,19.47 11,18.28 11,17C11,13.69 13.69,11 17,11z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17,12c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S19.76,12 17,12zM17,14c0.83,0 1.5,0.67 1.5,1.5S17.83,17 17,17s-1.5,-0.67 -1.5,-1.5S16.17,14 17,14zM17,20c-1.03,0 -1.94,-0.52 -2.48,-1.32C15.25,18.26 16.09,18 17,18s1.75,0.26 2.48,0.68C18.94,19.48 18.03,20 17,20z"/>
+ android:pathData="M17,13c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C21,14.79 19.21,13 17,13zM17,14.38c0.62,0 1.12,0.51 1.12,1.12s-0.51,1.12 -1.12,1.12s-1.12,-0.51 -1.12,-1.12S16.38,14.38 17,14.38zM17,19.75c-0.93,0 -1.74,-0.46 -2.24,-1.17c0.05,-0.72 1.51,-1.08 2.24,-1.08s2.19,0.36 2.24,1.08C18.74,19.29 17.93,19.75 17,19.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/ads_click.xml b/compose/material/material/icons/generator/raw-icons/rounded/ads_click.xml
new file mode 100644
index 0000000..d63f34d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/ads_click.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.71,17.99C8.53,17.84 6,15.22 6,12c0,-3.31 2.69,-6 6,-6c3.22,0 5.84,2.53 5.99,5.71l-2.1,-0.63C15.48,9.31 13.89,8 12,8c-2.21,0 -4,1.79 -4,4c0,1.89 1.31,3.48 3.08,3.89L11.71,17.99zM22,12c0,0.3 -0.01,0.6 -0.04,0.9l-1.97,-0.59C20,12.21 20,12.1 20,12c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8s3.58,8 8,8c0.1,0 0.21,0 0.31,-0.01l0.59,1.97C12.6,21.99 12.3,22 12,22C6.48,22 2,17.52 2,12C2,6.48 6.48,2 12,2S22,6.48 22,12zM18.23,16.26l2.27,-0.76c0.46,-0.15 0.45,-0.81 -0.01,-0.95l-7.6,-2.28c-0.38,-0.11 -0.74,0.24 -0.62,0.62l2.28,7.6c0.14,0.47 0.8,0.48 0.95,0.01l0.76,-2.27l3.91,3.91c0.2,0.2 0.51,0.2 0.71,0l1.27,-1.27c0.2,-0.2 0.2,-0.51 0,-0.71L18.23,16.26z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/agriculture.xml b/compose/material/material/icons/generator/raw-icons/rounded/agriculture.xml
index 1cd6ef9..c1ed5ba 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/agriculture.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/agriculture.xml
@@ -6,17 +6,14 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.5,12.1c0.93,0 1.78,0.28 2.5,0.76V8.1c0,-1.1 -0.9,-2 -2,-2h-6.29l-1.06,-1.06l1.05,-1.05c0.2,-0.2 0.2,-0.51 0,-0.71l0,0c-0.2,-0.2 -0.51,-0.2 -0.71,0L10.18,6.1c-0.2,0.2 -0.2,0.51 0,0.71l0,0c0.2,0.2 0.51,0.2 0.71,0l1.06,-1.06L13,6.81V9.1c0,1.1 -0.9,2 -2,2h-0.54c0.95,1.06 1.54,2.46 1.54,4c0,0.34 -0.04,0.67 -0.09,1h3.14C15.3,13.85 17.19,12.1 19.5,12.1z"/>
+ android:pathData="M19.5,11.97c0.93,0 1.78,0.28 2.5,0.76V7.97c0,-1.1 -0.9,-2 -2,-2h-6.29l-1.06,-1.06l1.06,-1.06c0.2,-0.2 0.2,-0.51 0,-0.71s-0.51,-0.2 -0.71,0l-2.83,2.83c-0.2,0.2 -0.2,0.51 0,0.71l0,0c0.2,0.2 0.51,0.2 0.71,0l1.06,-1.06L13,6.68v2.29c0,1.1 -0.9,2 -2,2h-0.54c0.95,1.06 1.54,2.46 1.54,4c0,0.34 -0.04,0.67 -0.09,1h3.14C15.3,13.73 17.19,11.97 19.5,11.97z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19.5,13.1c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S21.43,13.1 19.5,13.1zM19.5,18.1c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C21,17.43 20.33,18.1 19.5,18.1z"/>
+ android:pathData="M19.5,12.97c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S21.43,12.97 19.5,12.97zM19.5,17.97c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S20.33,17.97 19.5,17.97z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M4,9.1h5c0,-1.1 -0.9,-2 -2,-2H4c-0.55,0 -1,0.45 -1,1S3.45,9.1 4,9.1z"/>
+ android:pathData="M4,8.97h5c0,-1.1 -0.9,-2 -2,-2H4c-0.55,0 -1,0.45 -1,1C3,8.53 3.45,8.97 4,8.97z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M6,10.1c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S8.76,10.1 6,10.1zM6,18.1c-1.65,0 -3,-1.35 -3,-3s1.35,-3 3,-3s3,1.35 3,3S7.65,18.1 6,18.1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,15.1m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ android:pathData="M9.83,13.79l-0.18,-0.47l0.93,-0.35c-0.46,-1.06 -1.28,-1.91 -2.31,-2.43l-0.4,0.89l-0.46,-0.21l0.4,-0.9C7.26,10.11 6.64,9.97 6,9.97c-0.53,0 -1.04,0.11 -1.52,0.26l0.34,0.91l-0.47,0.18L4,10.4c-1.06,0.46 -1.91,1.28 -2.43,2.31l0.89,0.4l-0.21,0.46l-0.9,-0.4C1.13,13.72 1,14.33 1,14.97c0,0.53 0.11,1.04 0.26,1.52l0.91,-0.34l0.18,0.47l-0.93,0.35c0.46,1.06 1.28,1.91 2.31,2.43l0.4,-0.89l0.46,0.21l-0.4,0.9c0.57,0.22 1.18,0.35 1.82,0.35c0.53,0 1.04,-0.11 1.52,-0.26L7.18,18.8l0.47,-0.18L8,19.55c1.06,-0.46 1.91,-1.28 2.43,-2.31l-0.89,-0.4l0.21,-0.46l0.9,0.4c0.22,-0.57 0.35,-1.18 0.35,-1.82c0,-0.53 -0.11,-1.04 -0.26,-1.52L9.83,13.79zM7.15,17.75c-1.53,0.63 -3.29,-0.09 -3.92,-1.62c-0.63,-1.53 0.09,-3.29 1.62,-3.92c1.53,-0.63 3.29,0.09 3.92,1.62C9.41,15.36 8.68,17.11 7.15,17.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat.xml
index c2f8287..ceaf1eb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7h-7C9.9,7 9,7.9 9,9v5h13v-3C22,8.79 20.21,7 18,7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5,11m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,17h18c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1v0C2,16.55 2.45,17 3,17z"/>
+ android:pathData="M22,11v2L9,13L9,9c0,-1.1 0.9,-2 2,-2h7c2.21,0 4,1.79 4,4zM2,15c0,0.55 0.45,1 1,1h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,14c-0.55,0 -1,0.45 -1,1zM7.14,12.1c1.16,-1.19 1.14,-3.08 -0.04,-4.24 -1.19,-1.16 -3.08,-1.14 -4.24,0.04 -1.16,1.19 -1.14,3.08 0.04,4.24 1.19,1.16 3.08,1.14 4.24,-0.04z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat_angled.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat_angled.xml
index 93dc9c5..1aa6fdf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat_angled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_flat_angled.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.91,9.23l-7.05,-2.57c-0.78,-0.28 -1.64,0.12 -1.92,0.9l-1.88,5.17l12.22,4.45l1.03,-2.82C23.06,12.29 21.99,9.99 19.91,9.23z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.33,8.55m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.4,13.5l16.91,6.16c0.52,0.19 1.09,-0.08 1.28,-0.6l0,0c0.19,-0.52 -0.08,-1.09 -0.6,-1.28L3.08,11.62c-0.52,-0.19 -1.09,0.08 -1.28,0.6l0,0C1.61,12.74 1.88,13.31 2.4,13.5z"/>
+ android:pathData="M22.25,14.29l-0.69,1.89L9.2,11.71l1.39,-3.79c0.38,-1.03 1.52,-1.56 2.56,-1.19l6.69,2.41c2.1,0.76 3.18,3.06 2.41,5.15zM2.45,12.48l5.55,2L8,18c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-0.63l3.58,1.29c0.52,0.19 1.1,-0.08 1.29,-0.6 0.19,-0.52 -0.08,-1.1 -0.6,-1.29L3.13,10.59c-0.52,-0.19 -1.1,0.08 -1.29,0.6 -0.18,0.52 0.09,1.1 0.61,1.29zM7.3,10.2c1.49,-0.72 2.12,-2.51 1.41,-4C7.99,4.71 6.2,4.08 4.7,4.8c-1.49,0.71 -2.12,2.5 -1.4,4 0.71,1.49 2.5,2.12 4,1.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_individual_suite.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_individual_suite.xml
index 6679696..9a55475 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_individual_suite.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_individual_suite.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,14c1.65,0 3,-1.35 3,-3S8.65,8 7,8s-3,1.35 -3,3S5.35,14 7,14zM19,7h-6c-1.1,0 -2,0.9 -2,2v6H3V8c0,-0.55 -0.45,-1 -1,-1l0,0C1.45,7 1,7.45 1,8v7c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2v-4C23,8.79 21.21,7 19,7z"/>
+ android:pathData="M7,13c1.65,0 3,-1.35 3,-3S8.65,7 7,7s-3,1.35 -3,3 1.35,3 3,3zM19,7h-6c-1.1,0 -2,0.9 -2,2v5L3,14L3,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v7c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2v-4c0,-2.21 -1.79,-4 -4,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_extra.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_extra.xml
index d329ab8..02d1f1d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_extra.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_extra.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,12V4c0,-0.55 -0.45,-1 -1,-1l0,0C2.45,3 2,3.45 2,4v8c0,2.76 2.24,5 5,5h5c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H7C5.34,15 4,13.66 4,12zM22.83,17.24c-0.38,-0.72 -1.29,-0.97 -2.03,-0.63l-1.09,0.5l-3.41,-6.98C15.96,9.45 15.27,9 14.51,9H11V3H5v8c0,1.66 1.34,3 3,3h7l2.56,5.25c0.48,0.98 1.64,1.39 2.63,0.94l1.95,-0.89C22.9,18.94 23.23,18 22.83,17.24z"/>
+ android:pathData="M4,12L4,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8c0,2.76 2.24,5 5,5h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L7,15c-1.66,0 -3,-1.34 -3,-3zM22.83,17.24c-0.38,-0.72 -1.29,-0.97 -2.03,-0.63l-1.09,0.5 -3.41,-6.98C15.96,9.45 15.27,9 14.51,9L11,9L11,3L5,3v8c0,1.66 1.34,3 3,3h7l2.56,5.25c0.48,0.98 1.64,1.39 2.63,0.94l1.95,-0.89c0.76,-0.36 1.09,-1.3 0.69,-2.06z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_normal.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_normal.xml
index d64c77d..47dba52 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_normal.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_normal.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,12V4c0,-0.55 -0.45,-1 -1,-1l0,0C3.45,3 3,3.45 3,4v8c0,2.76 2.24,5 5,5h5c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C6.34,15 5,13.66 5,12zM20.5,18H19v-7c0,-1.1 -0.9,-2 -2,-2h-5V3H6v8c0,1.65 1.35,3 3,3h7v5c0,1.1 0.9,2 2,2h2.5c0.83,0 1.5,-0.67 1.5,-1.5S21.33,18 20.5,18z"/>
+ android:pathData="M5,12L5,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8c0,2.76 2.24,5 5,5h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,15c-1.66,0 -3,-1.34 -3,-3zM20.5,18L19,18v-7c0,-1.1 -0.9,-2 -2,-2h-5L12,3L6,3v8c0,1.65 1.35,3 3,3h7v5c0,1.1 0.9,2 2,2h2.5c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_reduced.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_reduced.xml
index fdccb15..880c699 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_reduced.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_legroom_reduced.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.97,19.2c0.18,0.96 -0.55,1.8 -1.47,1.8h-2.69c-1.3,0 -2.26,-1.22 -1.94,-2.49L15,14H9c-1.65,0 -3,-1.35 -3,-3V3h6v6h5c1.1,0 2,0.9 2,2l-2,7h1.44C19.17,18 19.83,18.49 19.97,19.2zM5,12V4c0,-0.55 -0.45,-1 -1,-1l0,0C3.45,3 3,3.45 3,4v8c0,2.76 2.24,5 5,5h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C6.34,15 5,13.66 5,12z"/>
+ android:pathData="M19.97,19.2c0.18,0.96 -0.55,1.8 -1.47,1.8h-2.69c-1.3,0 -2.26,-1.22 -1.94,-2.49L15,14H9c-1.65,0 -3,-1.35 -3,-3V3h6v6h5c1.1,0 2,0.9 2,2l-2,7h1.44c0.73,0 1.39,0.49 1.53,1.2zM5,12V4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8c0,2.76 2.24,5 5,5h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8c-1.66,0 -3,-1.34 -3,-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_extra.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_extra.xml
index b39fc10..f91745f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_extra.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_extra.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.35,5.64C4.45,5 4.23,3.76 4.86,2.85c0.63,-0.9 1.88,-1.12 2.79,-0.49C8.55,3 8.77,4.24 8.14,5.15C7.5,6.05 6.26,6.27 5.35,5.64zM16,20c0,-0.55 -0.45,-1 -1,-1H8.93c-1.48,0 -2.74,-1.08 -2.96,-2.54L4.16,7.78C4.07,7.33 3.67,7 3.2,7l0,0C2.58,7 2.12,7.57 2.24,8.18l1.75,8.58C4.37,19.2 6.47,21 8.94,21H15C15.55,21 16,20.55 16,20L16,20zM15.54,15h-4.19l-1.03,-4.1c1.28,0.72 2.63,1.28 4.1,1.3c0.58,0.01 1.05,-0.49 1.05,-1.07l0,0c0,-0.59 -0.49,-1.04 -1.08,-1.06c-2.29,-0.07 -3.57,-1.3 -5.25,-2.6C8.83,7.23 8.16,6.89 7.39,7.03H7.37C6.14,7.25 5.32,8.42 5.53,9.64l1.35,5.92C7.16,16.98 8.39,18 9.83,18h6.85l3.09,2.42c0.42,0.33 1.02,0.29 1.39,-0.08l0,0c0.45,-0.45 0.4,-1.18 -0.1,-1.57l-4.29,-3.35C16.42,15.15 15.99,15 15.54,15z"/>
+ android:pathData="M5.35,5.64c-0.9,-0.64 -1.12,-1.88 -0.49,-2.79 0.63,-0.9 1.88,-1.12 2.79,-0.49 0.9,0.64 1.12,1.88 0.49,2.79 -0.64,0.9 -1.88,1.12 -2.79,0.49zM16,20c0,-0.55 -0.45,-1 -1,-1L8.93,19c-1.48,0 -2.74,-1.08 -2.96,-2.54L4.16,7.78C4.07,7.33 3.67,7 3.2,7c-0.62,0 -1.08,0.57 -0.96,1.18l1.75,8.58C4.37,19.2 6.47,21 8.94,21L15,21c0.55,0 1,-0.45 1,-1zM15.54,15h-4.19l-1.03,-4.1c1.28,0.72 2.63,1.28 4.1,1.3 0.58,0.01 1.05,-0.49 1.05,-1.07 0,-0.59 -0.49,-1.04 -1.08,-1.06 -1.31,-0.04 -2.63,-0.56 -3.61,-1.33L9.14,7.47c-0.23,-0.18 -0.49,-0.3 -0.76,-0.38 -0.32,-0.09 -0.66,-0.12 -0.99,-0.06h-0.02c-1.23,0.22 -2.05,1.39 -1.84,2.61l1.35,5.92C7.16,16.98 8.39,18 9.83,18h6.85l3.09,2.42c0.42,0.33 1.02,0.29 1.39,-0.08 0.45,-0.45 0.4,-1.18 -0.1,-1.57l-4.29,-3.35c-0.35,-0.27 -0.78,-0.42 -1.23,-0.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_normal.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_normal.xml
index 341d505..74e582d1d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_normal.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_seat_recline_normal.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.59,5.41c-0.78,-0.78 -0.78,-2.05 0,-2.82s2.05,-0.78 2.83,0s0.78,2.05 0,2.82C9.62,6.2 8.36,6.2 7.59,5.41zM6,16V8c0,-0.55 -0.45,-1 -1,-1l0,0C4.45,7 4,7.45 4,8v8c0,2.76 2.24,5 5,5h5c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H9C7.34,19 6,17.66 6,16zM19.28,19.35l-3.77,-3.77C15.14,15.21 14.63,15 14.1,15h-2.6v-3.68c1.09,0.89 2.66,1.7 4.2,2.02c0.67,0.14 1.3,-0.36 1.3,-1.04l0,0c0,-0.53 -0.39,-0.96 -0.92,-1.05c-1.42,-0.24 -2.88,-1.01 -3.75,-1.97l-1.4,-1.55c-0.19,-0.21 -0.43,-0.38 -0.69,-0.5C9.95,7.09 9.62,7 9.28,7H9.25C8.01,7 7,8.01 7,9.25V15c0,1.66 1.34,3 3,3h5.07l2.78,2.78c0.39,0.39 1.04,0.39 1.43,0l0,0C19.68,20.39 19.68,19.75 19.28,19.35z"/>
+ android:pathData="M7.59,5.41c-0.78,-0.78 -0.78,-2.05 0,-2.83s2.05,-0.78 2.83,0 0.78,2.05 0,2.83c-0.79,0.79 -2.05,0.79 -2.83,0zM6,16L6,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8c0,2.76 2.24,5 5,5h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L9,19c-1.66,0 -3,-1.34 -3,-3zM19.28,19.35l-3.77,-3.77c-0.37,-0.37 -0.88,-0.58 -1.41,-0.58h-2.6v-3.68c1.09,0.89 2.66,1.7 4.2,2.02 0.67,0.14 1.3,-0.36 1.3,-1.04 0,-0.53 -0.39,-0.96 -0.92,-1.05 -1.42,-0.24 -2.88,-1.01 -3.75,-1.97l-1.4,-1.55c-0.19,-0.21 -0.43,-0.38 -0.69,-0.5 -0.29,-0.14 -0.62,-0.23 -0.96,-0.23h-0.03C8.01,7 7,8.01 7,9.25L7,15c0,1.66 1.34,3 3,3h5.07l2.78,2.78c0.39,0.39 1.04,0.39 1.43,0 0.4,-0.39 0.4,-1.03 0,-1.43z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airline_stops.xml b/compose/material/material/icons/generator/raw-icons/rounded/airline_stops.xml
new file mode 100644
index 0000000..6b8045f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airline_stops.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,18c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h1c-0.47,-4.21 -3.89,-7.55 -8.12,-7.96C2.37,8.99 2,8.56 2,8.05c0,-0.59 0.52,-1.06 1.11,-1C7.03,7.44 10.37,9.87 12,13.3c1.13,-2.43 2.99,-4.25 4.78,-5.52l-1.92,-1.92C14.54,5.54 14.76,5 15.21,5h5.29C20.78,5 21,5.22 21,5.5v5.29c0,0.45 -0.54,0.67 -0.85,0.35l-1.94,-1.94C15.93,10.78 13.45,13.3 13,17h1C14.55,17 15,17.45 15,18z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airlines.xml b/compose/material/material/icons/generator/raw-icons/rounded/airlines.xml
new file mode 100644
index 0000000..cc92b97
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airlines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.59,4h-5.01c-0.99,0 -1.91,0.49 -2.47,1.3L2,20h17l2.56,-13.63C21.79,5.14 20.84,4 19.59,4zM14.5,14c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C17,12.88 15.88,14 14.5,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_active.xml b/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_active.xml
index 7a6c65f..360739c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_active.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_active.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,14.6L22,14.6c0,-0.37 -0.2,-0.72 -0.52,-0.9L13.5,9l0,-5.42c0,-0.81 -0.61,-1.54 -1.42,-1.58c-0.87,-0.04 -1.58,0.64 -1.58,1.5V9l-7.98,4.7C2.2,13.88 2,14.23 2,14.6v0c0,0.7 0.67,1.2 1.34,1.01l7.16,-2.1V19l-1.67,1.25c-0.21,0.16 -0.33,0.4 -0.33,0.66l0,0c0,0.55 0.52,0.94 1.05,0.79L12,21l2.45,0.7c0.52,0.15 1.05,-0.24 1.05,-0.79l0,0c0,-0.26 -0.12,-0.5 -0.33,-0.66L13.5,19v-5.5l7.16,2.1C21.33,15.8 22,15.3 22,14.6z"/>
+ android:pathData="M21.48,13.7L13.5,9V3.5C13.5,2.67 12.83,2 12,2c-0.83,0 -1.5,0.67 -1.5,1.5V9l-7.98,4.7C2.2,13.88 2,14.23 2,14.6c0,0.7 0.67,1.2 1.34,1.01l7.16,-2.1V19l-2.26,1.35C8.09,20.44 8,20.61 8,20.78l0,0.5h0v0.08c0,0.33 0.31,0.57 0.62,0.49l2.92,-0.73L12,21l0.38,0.09c0,0 0,0 0,0l0.42,0.11l1.9,0.48l0,0l0.67,0.17c0.32,0.08 0.62,-0.16 0.62,-0.49v-0.37c0,0 0,0 0,0v-0.21c0,-0.18 -0.09,-0.34 -0.24,-0.43L13.5,19v-5.5l7.16,2.1C21.33,15.8 22,15.3 22,14.6C22,14.23 21.8,13.88 21.48,13.7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_inactive.xml b/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_inactive.xml
index 94020a6..794079d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_inactive.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airplanemode_inactive.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.48,13.7L13.5,9V3.58c0,-0.81 -0.61,-1.54 -1.42,-1.58c-0.87,-0.04 -1.58,0.64 -1.58,1.5v4.59l6.42,6.42l3.74,1.1C21.33,15.8 22,15.3 22,14.6C22,14.23 21.8,13.88 21.48,13.7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.31,3.72c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l5.62,5.62l-5,2.94C2.2,13.88 2,14.23 2,14.6c0,0.7 0.67,1.2 1.34,1.01l6.97,-2.05l0.19,0.19V19l-1.67,1.25c-0.21,0.16 -0.33,0.4 -0.33,0.66c0,0.55 0.52,0.94 1.05,0.79L12,21l2.45,0.7c0.52,0.15 1.05,-0.24 1.05,-0.79c0,-0.26 -0.12,-0.5 -0.33,-0.66L13.5,19v-2.26l5.36,5.36c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.31,3.72z"/>
+ android:pathData="M22,14.6c0,0.7 -0.67,1.2 -1.34,1.01l-3.15,-0.93L10.5,7.67V3.5C10.5,2.67 11.17,2 12,2c0.83,0 1.5,0.67 1.5,1.5V9l7.98,4.7C21.8,13.88 22,14.23 22,14.6zM13.5,13.5L9.56,9.56L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l5.67,5.67L2.52,13.7C2.2,13.88 2,14.23 2,14.6c0,0.7 0.67,1.2 1.34,1.01l7.16,-2.1V19l-2.26,1.35C8.09,20.44 8,20.61 8,20.78l0,0.5h0v0.08c0,0.33 0.31,0.57 0.62,0.49l2.92,-0.73L12,21l0.38,0.09c0,0 0,0 0,0l0.42,0.11l1.9,0.48l0,0l0.67,0.17c0.32,0.08 0.62,-0.16 0.62,-0.49v-0.37c0,0 0,0 0,0v-0.21c0,-0.18 -0.09,-0.34 -0.24,-0.43L13.5,19v-2.67l5.57,5.57h0l0,0c0.39,0.39 1.02,0.39 1.41,0s0.39,-1.02 0,-1.41L13.5,13.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airplay.xml b/compose/material/material/icons/generator/raw-icons/rounded/airplay.xml
index a7e176a..df7f674 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airplay.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airplay.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.41,21h7.17c0.89,0 1.34,-1.08 0.71,-1.71l-3.59,-3.59c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.59,3.59C7.08,19.92 7.52,21 8.41,21zM20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V5h16v12h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2c1.1,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3z"/>
+ android:pathData="M8.41,22h7.17c0.89,0 1.34,-1.08 0.71,-1.71L12.7,16.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L7.7,20.29c-0.62,0.63 -0.18,1.71 0.71,1.71zM21,3H3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/airport_shuttle.xml b/compose/material/material/icons/generator/raw-icons/rounded/airport_shuttle.xml
index 3c10771..461c6ad 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/airport_shuttle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/airport_shuttle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.59,5.59C17.21,5.21 16.7,5 16.17,5H3C1.9,5 1,5.89 1,7v7c0,1.1 0.9,2 2,2h0c0,1.66 1.34,3 3,3s3,-1.34 3,-3h6c0,1.66 1.34,3 3,3s3,-1.34 3,-3h0c1.1,0 2,-0.9 2,-2v-2.17c0,-0.53 -0.21,-1.04 -0.59,-1.41L17.59,5.59zM15,7h1l3,3h-4V7zM9,7h4v3H9V7zM3,7h4v3H3V7zM6,17.25c-0.69,0 -1.25,-0.56 -1.25,-1.25S5.31,14.75 6,14.75S7.25,15.31 7.25,16C7.25,16.69 6.69,17.25 6,17.25zM18,17.25c-0.69,0 -1.25,-0.56 -1.25,-1.25s0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25C19.25,16.69 18.69,17.25 18,17.25z"/>
+ android:pathData="M22.41,10.41l-4.83,-4.83c-0.37,-0.37 -0.88,-0.58 -1.41,-0.58L3,5c-1.1,0 -2,0.89 -2,2v7c0,1.1 0.9,2 2,2 0,1.66 1.34,3 3,3s3,-1.34 3,-3h6c0,1.66 1.34,3 3,3s3,-1.34 3,-3c1.1,0 2,-0.9 2,-2v-2.17c0,-0.53 -0.21,-1.04 -0.59,-1.42zM3,10L3,8c0,-0.55 0.45,-1 1,-1h3v4L4,11c-0.55,0 -1,-0.45 -1,-1zM6,17.25c-0.69,0 -1.25,-0.56 -1.25,-1.25s0.56,-1.25 1.25,-1.25 1.25,0.56 1.25,1.25 -0.56,1.25 -1.25,1.25zM13,11L9,11L9,7h4v4zM18,17.25c-0.69,0 -1.25,-0.56 -1.25,-1.25s0.56,-1.25 1.25,-1.25 1.25,0.56 1.25,1.25 -0.56,1.25 -1.25,1.25zM15,11L15,7h1l4,4h-5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/alarm.xml b/compose/material/material/icons/generator/raw-icons/rounded/alarm.xml
index 20601f5..1aa074c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/alarm.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/alarm.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c4.97,0 9,-4.03 9,-9S16.97,4 12,4zM15.5,16.5c-0.39,0.39 -1.02,0.39 -1.41,0l-2.79,-2.79C11.11,13.52 11,13.27 11,13V9c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3.59l2.5,2.5C15.89,15.48 15.89,16.11 15.5,16.5zM4.88,3.05L2.05,5.88c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l2.83,-2.83c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C5.9,2.66 5.27,2.66 4.88,3.05zM17.71,3.05L17.71,3.05c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.83,-2.83C18.73,2.66 18.1,2.66 17.71,3.05z"/>
+ android:pathData="M15.87,15.25l-3.37,-2L12.5,8.72c0,-0.4 -0.32,-0.72 -0.72,-0.72h-0.06c-0.4,0 -0.72,0.32 -0.72,0.72v4.72c0,0.35 0.18,0.68 0.49,0.86l3.65,2.19c0.34,0.2 0.78,0.1 0.98,-0.24 0.21,-0.35 0.1,-0.8 -0.25,-1zM21.18,5.01L18.1,2.45c-0.42,-0.35 -1.05,-0.3 -1.41,0.13 -0.35,0.42 -0.29,1.05 0.13,1.41l3.07,2.56c0.42,0.35 1.05,0.3 1.41,-0.13 0.36,-0.42 0.3,-1.05 -0.12,-1.41zM4.1,6.55l3.07,-2.56c0.43,-0.36 0.49,-0.99 0.13,-1.41 -0.35,-0.43 -0.98,-0.48 -1.4,-0.13L2.82,5.01c-0.42,0.36 -0.48,0.99 -0.12,1.41 0.35,0.43 0.98,0.48 1.4,0.13zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/alarm_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/alarm_add.xml
index 9a36a2a..3dfcb89 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/alarm_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/alarm_add.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.97,0 -9,4.03 -9,9c0,4.97 4.03,9 9,9s9,-4.03 9,-9C21,8.03 16.97,4 12,4zM15,14h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1S15.55,14 15,14z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.29,4.46c0.39,-0.39 0.39,-1.02 0,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0L2.05,5.88c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0L6.29,4.46z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.95,5.88l-2.83,-2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0v0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0v0C22.34,6.9 22.34,6.27 21.95,5.88z"/>
+ android:pathData="M21.18,5.01L18.1,2.45c-0.42,-0.35 -1.05,-0.3 -1.41,0.13 -0.35,0.42 -0.29,1.05 0.13,1.41l3.07,2.56c0.42,0.35 1.05,0.3 1.41,-0.13 0.36,-0.42 0.3,-1.05 -0.12,-1.41zM4.1,6.55l3.07,-2.56c0.43,-0.36 0.49,-0.99 0.13,-1.41 -0.35,-0.43 -0.98,-0.48 -1.4,-0.13L2.82,5.01c-0.42,0.36 -0.48,0.99 -0.12,1.41 0.35,0.43 0.98,0.48 1.4,0.13zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM15,12h-2v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2L9,12c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/alarm_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/alarm_off.xml
index 61edea2..ff5937d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/alarm_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/alarm_off.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,13c0,-4.97 -4.03,-9 -9,-9c-1.5,0 -2.91,0.37 -4.15,1.02l12.13,12.13C20.63,15.91 21,14.5 21,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.95,5.88l-2.83,-2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0C22.34,6.9 22.34,6.27 21.95,5.88z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1.39,2.81C1,3.2 1,3.83 1.39,4.22l1.16,1.16l-0.5,0.5c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0l0.5,-0.5l0.83,0.83c-1.4,1.87 -2.1,4.29 -1.67,6.89c0.61,3.74 3.63,6.75 7.37,7.37c2.6,0.43 5.01,-0.27 6.88,-1.67l2.4,2.4c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81C2.42,2.42 1.78,2.42 1.39,2.81L1.39,2.81z"/>
+ android:pathData="M10.04,6.29C10.66,6.11 11.32,6 12,6c3.86,0 7,3.14 7,7 0,0.68 -0.11,1.34 -0.29,1.96l1.56,1.56c0.47,-1.08 0.73,-2.27 0.73,-3.52 0,-4.97 -4.03,-9 -9,-9 -1.25,0 -2.44,0.26 -3.53,0.72l1.57,1.57zM3.71,2.79c-0.38,-0.38 -1,-0.38 -1.39,0l-0.02,0.03c-0.39,0.39 -0.39,1.01 0,1.39l0.68,0.68 -0.17,0.14c-0.42,0.34 -0.47,0.96 -0.13,1.38l0.03,0.03c0.35,0.42 0.96,0.47 1.38,0.12l0.31,-0.25 0.8,0.8C3.83,8.69 3,10.75 3,13c0,4.97 4.03,9 9,9 2.25,0 4.31,-0.83 5.89,-2.2l1.41,1.41c0.38,0.38 1,0.38 1.39,0l0.03,-0.03c0.38,-0.38 0.38,-1 0,-1.39l-17.01,-17zM12,20c-3.86,0 -7,-3.14 -7,-7 0,-1.7 0.61,-3.26 1.62,-4.47l9.85,9.85C15.26,19.39 13.7,20 12,20zM19.91,6.56c0.42,0.35 1.03,0.29 1.38,-0.12l0.03,-0.03c0.35,-0.42 0.29,-1.03 -0.12,-1.38l-3.1,-2.59c-0.42,-0.35 -1.03,-0.29 -1.38,0.12l-0.03,0.03c-0.35,0.42 -0.29,1.03 0.12,1.38l3.1,2.59zM7.43,3.68c0.18,-0.34 0.15,-0.77 -0.11,-1.09l-0.03,-0.03c-0.3,-0.36 -0.8,-0.43 -1.2,-0.22l1.34,1.34z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/alarm_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/alarm_on.xml
index fceb5e0..08d34bd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/alarm_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/alarm_on.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c4.97,0 9,-4.03 9,-9S16.97,4 12,4zM15.89,12.05l-4.24,4.24c-0.39,0.39 -1.02,0.39 -1.41,0l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41s1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0C16.28,11.03 16.28,11.66 15.89,12.05z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.29,4.46c0.39,-0.39 0.39,-1.02 0,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0L2.05,5.88c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0L6.29,4.46z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.95,5.88l-2.83,-2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0v0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0v0C22.34,6.9 22.34,6.27 21.95,5.88z"/>
+ android:pathData="M14.94,10.11l-4.4,4.42 -1.6,-1.6c-0.29,-0.29 -0.77,-0.29 -1.06,0 -0.29,0.29 -0.29,0.77 0,1.06L10,16.11c0.29,0.29 0.77,0.29 1.06,0L16,11.17c0.29,-0.29 0.29,-0.77 0,-1.06 -0.29,-0.29 -0.77,-0.29 -1.06,0zM21.18,5.01L18.1,2.45c-0.42,-0.35 -1.05,-0.3 -1.41,0.13 -0.35,0.42 -0.29,1.05 0.13,1.41l3.07,2.56c0.42,0.35 1.05,0.3 1.41,-0.13 0.36,-0.42 0.3,-1.05 -0.12,-1.41zM4.1,6.55l3.07,-2.56c0.43,-0.36 0.49,-0.99 0.13,-1.41 -0.35,-0.43 -0.98,-0.48 -1.4,-0.13L2.82,5.01c-0.42,0.36 -0.48,0.99 -0.12,1.41 0.35,0.43 0.98,0.48 1.4,0.13zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/album.xml b/compose/material/material/icons/generator/raw-icons/rounded/album.xml
index 58bfb09..58c0ba6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/album.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/album.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,16.5c-2.49,0 -4.5,-2.01 -4.5,-4.5S9.51,7.5 12,7.5s4.5,2.01 4.5,4.5S14.49,16.5 12,16.5zM12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S12.55,11 12,11z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,16.5c-2.49,0 -4.5,-2.01 -4.5,-4.5S9.51,7.5 12,7.5s4.5,2.01 4.5,4.5 -2.01,4.5 -4.5,4.5zM12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/all_inbox.xml b/compose/material/material/icons/generator/raw-icons/rounded/all_inbox.xml
index b35c92e..0fee612 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/all_inbox.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/all_inbox.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6zM20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM20,11l-3.15,0c-0.42,0 -0.82,0.24 -0.95,0.63C15.63,12.43 14.88,13 14,13s-1.63,-0.57 -1.9,-1.37C11.97,11.24 11.56,11 11.15,11L8,11V4h12V11z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v7c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,9h-3.14c-0.47,0 -0.84,0.33 -0.97,0.78C14.53,11.04 13.35,12 12,12s-2.53,-0.96 -2.89,-2.22c-0.13,-0.45 -0.5,-0.78 -0.97,-0.78L5,9L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v3zM15.87,16L20,16c0.55,0 1,0.45 1,1v2c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-2c0,-0.55 0.45,-1 1,-1h4.13c0.47,0 0.85,0.34 0.98,0.8 0.35,1.27 1.51,2.2 2.89,2.2s2.54,-0.93 2.89,-2.2c0.13,-0.46 0.51,-0.8 0.98,-0.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/all_inclusive.xml b/compose/material/material/icons/generator/raw-icons/rounded/all_inclusive.xml
index 4bdc13b..67cc0a5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/all_inclusive.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/all_inclusive.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.34,10.05c0.38,0.34 0.96,0.34 1.34,0l0,0c0.44,-0.4 0.44,-1.09 0,-1.49C9.12,8.07 7.83,6.5 5.5,6.5C2.47,6.5 0,8.97 0,12s2.47,5.5 5.5,5.5c1.21,0 2.38,-0.45 3.28,-1.26l7.77,-6.99c0.54,-0.48 1.23,-0.75 1.95,-0.75c1.93,0 3.5,1.57 3.5,3.5s-1.57,3.5 -3.5,3.5c-1.25,0 -1.81,-0.62 -2.84,-1.55c-0.38,-0.34 -0.96,-0.34 -1.34,0l0,0c-0.44,0.4 -0.44,1.09 0,1.49c0.55,0.5 1.85,2.07 4.18,2.07c3.03,0 5.5,-2.47 5.5,-5.5s-2.47,-5.5 -5.5,-5.5c-1.21,0 -2.38,0.45 -3.28,1.26l-7.77,6.99C6.91,15.23 6.22,15.5 5.5,15.5C3.57,15.5 2,13.93 2,12s1.57,-3.5 3.5,-3.5C6.75,8.5 7.31,9.12 8.34,10.05z"/>
+ android:pathData="M20.22,6.86c-2,-0.6 -4.06,-0.04 -5.39,1.29L12,10.66 10.48,12h0.01L7.8,14.39c-0.81,0.81 -1.95,1.15 -3.12,0.92 -1.25,-0.25 -2.28,-1.25 -2.57,-2.49 -0.52,-2.23 1.16,-4.2 3.29,-4.2 0.91,0 1.76,0.35 2.44,1.03l0.47,0.41c0.38,0.34 0.95,0.34 1.33,0 0.45,-0.4 0.45,-1.1 0,-1.5l-0.42,-0.36C8.2,7.18 6.84,6.62 5.4,6.62 2.42,6.62 0,9.04 0,12s2.42,5.38 5.4,5.38c1.44,0 2.8,-0.56 3.77,-1.53l2.83,-2.5 0.01,0.01L13.52,12h-0.01l2.69,-2.39c0.81,-0.81 1.95,-1.15 3.12,-0.92 1.25,0.25 2.28,1.25 2.57,2.49 0.52,2.23 -1.16,4.2 -3.29,4.2 -0.9,0 -1.76,-0.35 -2.44,-1.03l-0.48,-0.42c-0.38,-0.34 -0.95,-0.34 -1.33,0 -0.45,0.4 -0.45,1.1 0,1.5l0.42,0.37c1.02,1.01 2.37,1.57 3.82,1.57 3.27,0 5.86,-2.9 5.33,-6.25 -0.3,-1.99 -1.77,-3.69 -3.7,-4.26z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/all_out.xml b/compose/material/material/icons/generator/raw-icons/rounded/all_out.xml
index dd430dd..d0c578e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/all_out.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/all_out.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,16L4,16c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5v-2C5,16.45 4.55,16 4,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5H7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,4L16,4c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1h-3C16.45,3 16,3.45 16,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,19c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2H17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,12c0,-3.87 -3.13,-7 -7,-7s-7,3.13 -7,7s3.13,7 7,7S19,15.87 19,12zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5s5,2.24 5,5S14.76,17 12,17z"/>
+ android:pathData="M4,4.5L4,8l4,-4L4.5,4c-0.28,0 -0.5,0.22 -0.5,0.5zM16,4l4,4L20,4.5c0,-0.28 -0.22,-0.5 -0.5,-0.5L16,4zM20,19.5L20,16l-4,4h3.5c0.28,0 0.5,-0.22 0.5,-0.5zM4.5,20L8,20l-4,-4v3.5c0,0.28 0.22,0.5 0.5,0.5zM19,12c0,-3.87 -3.13,-7 -7,-7s-7,3.13 -7,7 3.13,7 7,7 7,-3.13 7,-7zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/alternate_email.xml b/compose/material/material/icons/generator/raw-icons/rounded/alternate_email.xml
index d0e243b..2668818 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/alternate_email.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/alternate_email.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.72,2.03C6.63,1.6 1.6,6.63 2.03,12.72C2.39,18.01 7.01,22 12.31,22L16,22c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1l-3.67,0c-3.73,0 -7.15,-2.42 -8.08,-6.03c-1.49,-5.8 3.91,-11.21 9.71,-9.71C17.58,5.18 20,8.6 20,12.33l0,1.1c0,0.79 -0.71,1.57 -1.5,1.57S17,14.22 17,13.43v-1.25c0,-2.51 -1.78,-4.77 -4.26,-5.12c-3.4,-0.49 -6.27,2.45 -5.66,5.87c0.34,1.91 1.83,3.49 3.72,3.94c1.84,0.43 3.59,-0.16 4.74,-1.33c0.89,1.22 2.67,1.86 4.3,1.21c1.34,-0.53 2.16,-1.91 2.16,-3.35v-1.08C22,7.01 18.01,2.39 12.72,2.03zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S13.66,15 12,15z"/>
+ android:pathData="M12.72,2.03C6.63,1.6 1.6,6.63 2.03,12.72 2.39,18.01 7.01,22 12.31,22H16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3.67c-3.73,0 -7.15,-2.42 -8.08,-6.03 -1.49,-5.8 3.91,-11.21 9.71,-9.71C17.58,5.18 20,8.6 20,12.33v1.1c0,0.79 -0.71,1.57 -1.5,1.57s-1.5,-0.78 -1.5,-1.57v-1.25c0,-2.51 -1.78,-4.77 -4.26,-5.12 -3.4,-0.49 -6.27,2.45 -5.66,5.87 0.34,1.91 1.83,3.49 3.72,3.94 1.84,0.43 3.59,-0.16 4.74,-1.33 0.89,1.22 2.67,1.86 4.3,1.21 1.34,-0.53 2.16,-1.9 2.16,-3.34v-1.09c0,-5.31 -3.99,-9.93 -9.28,-10.29zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/analytics.xml b/compose/material/material/icons/generator/raw-icons/rounded/analytics.xml
index 0385b611..0366c6b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/analytics.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/analytics.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM8,17L8,17c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3C9,16.55 8.55,17 8,17zM12,17L12,17c-0.55,0 -1,-0.45 -1,-1v-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v1C13,16.55 12.55,17 12,17zM12,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,12 12,12zM16,17L16,17c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1c0.55,0 1,0.45 1,1v8C17,16.55 16.55,17 16,17z"/>
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM8,17L8,17c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3C9,16.55 8.55,17 8,17zM12,17L12,17c-0.55,0 -1,-0.45 -1,-1v-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v1C13,16.55 12.55,17 12,17zM12,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,12 12,12zM16,17L16,17c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8C17,16.55 16.55,17 16,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/announcement.xml b/compose/material/material/icons/generator/raw-icons/rounded/announcement.xml
index abbb132..6af86c9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/announcement.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/announcement.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v15.59c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM12,11c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4C13,10.55 12.55,11 12,11zM12,15L12,15c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,14.55 12.55,15 12,15z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM12,11c-0.55,0 -1,-0.45 -1,-1L11,6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1zM13,15h-2v-2h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/apartment.xml b/compose/material/material/icons/generator/raw-icons/rounded/apartment.xml
index 661eee8..6a4b623 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/apartment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/apartment.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,11V5c0,-1.1 -0.9,-2 -2,-2H9C7.9,3 7,3.9 7,5v2H5C3.9,7 3,7.9 3,9v10c0,1.1 0.9,2 2,2h6v-4h2v4h6c1.1,0 2,-0.9 2,-2v-6c0,-1.1 -0.9,-2 -2,-2H17zM7,19H5v-2h2V19zM7,15H5v-2h2V15zM7,11H5V9h2V11zM11,15H9v-2h2V15zM11,11H9V9h2V11zM11,7H9V5h2V7zM15,15h-2v-2h2V15zM15,11h-2V9h2V11zM15,7h-2V5h2V7zM19,19h-2v-2h2V19zM19,15h-2v-2h2V15z"/>
+ android:pathData="M17,11V5c0,-1.1 -0.9,-2 -2,-2H9C7.9,3 7,3.9 7,5v2H5C3.9,7 3,7.9 3,9v10c0,1.1 0.9,2 2,2h5c0.55,0 1,-0.45 1,-1v-3h2v3c0,0.55 0.45,1 1,1h5c1.1,0 2,-0.9 2,-2v-6c0,-1.1 -0.9,-2 -2,-2H17zM7,19H5v-2h2V19zM7,15H5v-2h2V15zM7,11H5V9h2V11zM11,15H9v-2h2V15zM11,11H9V9h2V11zM11,7H9V5h2V7zM15,15h-2v-2h2V15zM15,11h-2V9h2V11zM15,7h-2V5h2V7zM19,19h-2v-2h2V19zM19,15h-2v-2h2V15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/app_blocking.xml b/compose/material/material/icons/generator/raw-icons/rounded/app_blocking.xml
index a00f368..a415c4c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/app_blocking.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/app_blocking.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,12c0,2.21 1.79,4 4,4c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4C15.79,8 14,9.79 14,12zM18,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-0.42 0.11,-0.8 0.29,-1.15l3.36,3.36C18.8,14.39 18.42,14.5 18,14.5zM20.5,12c0,0.42 -0.11,0.8 -0.29,1.15l-3.36,-3.36C17.2,9.61 17.58,9.5 18,9.5C19.38,9.5 20.5,10.62 20.5,12z"/>
+ android:pathData="M18,8c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C22,9.79 20.21,8 18,8zM15.5,12c0,-1.38 1.12,-2.5 2.5,-2.5c0.42,0 0.8,0.11 1.15,0.29l-3.36,3.36C15.61,12.8 15.5,12.42 15.5,12zM18,14.5c-0.42,0 -0.8,-0.11 -1.15,-0.29l3.36,-3.36c0.18,0.35 0.29,0.73 0.29,1.15C20.5,13.38 19.38,14.5 18,14.5z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M17,18H7V6h10v1h2V6V5V3c0,-1.1 -0.9,-2 -2,-2H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-2v-1v-1h-2V18z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/apps.xml b/compose/material/material/icons/generator/raw-icons/rounded/apps.xml
index e7222fc..374e8f4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/apps.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/apps.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,8L6,8c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0C4.9,4 4,4.9 4,6v0C4,7.1 4.9,8 6,8zM12,20L12,20c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0c-1.1,0 -2,0.9 -2,2v0C10,19.1 10.9,20 12,20zM6,20L6,20c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0c-1.1,0 -2,0.9 -2,2v0C4,19.1 4.9,20 6,20zM6,14L6,14c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0c-1.1,0 -2,0.9 -2,2v0C4,13.1 4.9,14 6,14zM12,14L12,14c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0c-1.1,0 -2,0.9 -2,2v0C10,13.1 10.9,14 12,14zM16,6L16,6c0,1.1 0.9,2 2,2h0c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0C16.9,4 16,4.9 16,6zM12,8L12,8c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0c-1.1,0 -2,0.9 -2,2v0C10,7.1 10.9,8 12,8zM18,14L18,14c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0c-1.1,0 -2,0.9 -2,2v0C16,13.1 16.9,14 18,14zM18,20L18,20c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h0c-1.1,0 -2,0.9 -2,2v0C16,19.1 16.9,20 18,20z"/>
+ android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/apps_outage.xml b/compose/material/material/icons/generator/raw-icons/rounded/apps_outage.xml
new file mode 100644
index 0000000..4ea4921
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/apps_outage.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6,8c1.1,0 2,-0.9 2,-2S7.1,4 6,4S4,4.9 4,6S4.9,8 6,8zM12,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S10.9,20 12,20zM6,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S4.9,20 6,20zM6,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S4.9,14 6,14zM12,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S10.9,14 12,14zM12.07,4C12.05,4 12.02,4 12,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c0.22,0 0.43,-0.04 0.63,-0.1C12.22,7.01 12,6.03 12,5C12,4.66 12.02,4.33 12.07,4zM19,12c-1.03,0 -2.01,-0.22 -2.9,-0.63C16.04,11.57 16,11.78 16,12c0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-0.02 0,-0.05 0,-0.07C19.67,11.98 19.34,12 19,12zM18,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S16.9,20 18,20zM19,0c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S21.76,0 19,0zM19.5,7.5C19.5,7.78 19.28,8 19,8c-0.27,0 -0.5,-0.22 -0.5,-0.5S18.72,7 19,7S19.5,7.22 19.5,7.5zM19,6c-0.28,0 -0.5,-0.22 -0.5,-0.5v-3C18.5,2.22 18.72,2 19,2s0.5,0.22 0.5,0.5v3C19.5,5.78 19.28,6 19,6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/architecture.xml b/compose/material/material/icons/generator/raw-icons/rounded/architecture.xml
index b42ab84..64104a2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/architecture.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/architecture.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.51,18.9L6.64,20c0.05,0.41 0.54,0.59 0.84,0.31l0.81,-0.77c0.06,-0.05 0.1,-0.12 0.13,-0.19l2.7,-7.46c-0.68,-0.16 -1.28,-0.49 -1.78,-0.94l-2.79,7.72C6.51,18.74 6.5,18.82 6.51,18.9z"/>
+ android:pathData="M6.36,18.78L6.61,21l1.62,-1.54l2.77,-7.6c-0.68,-0.17 -1.28,-0.51 -1.77,-0.98L6.36,18.78z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M14.67,10.96c-0.5,0.45 -1.11,0.78 -1.78,0.94l2.71,7.45c0.03,0.07 0.07,0.14 0.13,0.19l0.81,0.77c0.3,0.28 0.8,0.1 0.84,-0.31l0.12,-1.1c0.01,-0.08 0,-0.15 -0.03,-0.23L14.67,10.96z"/>
+ android:pathData="M14.77,10.88c-0.49,0.47 -1.1,0.81 -1.77,0.98l2.77,7.6L17.39,21l0.26,-2.22L14.77,10.88z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M14.98,8.33c0.15,-1.44 -0.73,-2.69 -1.98,-3.15V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1.18C9.84,5.6 9,6.7 9,8c0,1.66 1.35,3.01 3.01,3C13.51,10.99 14.82,9.82 14.98,8.33zM12,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,9 12,9z"/>
+ android:pathData="M14.94,8.6c0.3,-1.56 -0.6,-2.94 -1.94,-3.42V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1.18C9.84,5.6 9,6.7 9,8c0,1.84 1.66,3.3 3.56,2.95C13.74,10.73 14.71,9.78 14.94,8.6zM12,9c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C13,8.55 12.55,9 12,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/archive.xml b/compose/material/material/icons/generator/raw-icons/rounded/archive.xml
index fc43494..7800d10 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/archive.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/archive.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6C5.53,3 5.12,3.21 4.84,3.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5C21,6.02 20.83,5.57 20.54,5.23zM15.15,14.85l-2.79,2.79c-0.2,0.2 -0.51,0.2 -0.71,0l-2.79,-2.79C8.54,14.54 8.76,14 9.21,14H11v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h1.79C15.24,14 15.46,14.54 15.15,14.85zM5.12,5l0.81,-1h12l0.94,1H5.12z"/>
+ android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3L6,3c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5L3,19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM11.65,17.15L6.5,12L10,12v-2h4v2h3.5l-5.15,5.15c-0.19,0.19 -0.51,0.19 -0.7,0zM5.12,5l0.81,-1h12l0.94,1L5.12,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/area_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/area_chart.xml
new file mode 100644
index 0000000..7379f8b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/area_chart.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,17l3.39,-4.66c0.33,-0.46 0.98,-0.55 1.42,-0.2L21,18.5V19c0,0.55 -0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1l0,-5.72c0.22,0 0.44,0.07 0.62,0.22L8,17zM3,11c0.44,0 0.88,0.15 1.25,0.44l3.37,2.69l2.77,-3.81c0.66,-0.91 1.95,-1.1 2.85,-0.4L21,15.97V8c0,-0.55 -0.45,-1 -1,-1h-3l-4.18,-3.34c-0.45,-0.36 -1.1,-0.27 -1.44,0.2L7,10L3.6,7.45C3.42,7.32 3.21,7.25 3,7.25L3,11z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_back.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_back.xml
index e1829d0..36a59be 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_back.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_back.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1l0,0C20,11.45 19.55,11 19,11z"/>
+ android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_back_ios.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_back_ios.xml
index d8e7fa2..182bced 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_back_ios.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_back_ios.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.88,2.88L10.88,2.88C10.4,2.4 9.6,2.4 9.12,2.88l-8.41,8.41c-0.39,0.39 -0.39,1.02 0,1.41l8.41,8.41c0.49,0.49 1.28,0.49 1.77,0l0,0c0.49,-0.49 0.49,-1.28 0,-1.77L3.54,12l7.35,-7.35C11.37,4.16 11.37,3.37 10.88,2.88z"/>
+ android:pathData="M16.62,2.99c-0.49,-0.49 -1.28,-0.49 -1.77,0L6.54,11.3c-0.39,0.39 -0.39,1.02 0,1.41l8.31,8.31c0.49,0.49 1.28,0.49 1.77,0s0.49,-1.28 0,-1.77L9.38,12l7.25,-7.25c0.48,-0.48 0.48,-1.28 -0.01,-1.76z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_downward.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_downward.xml
index 4810bac..5a15de3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_downward.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_downward.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,5v11.17l-4.88,-4.88c-0.39,-0.39 -1.03,-0.39 -1.42,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0l6.59,-6.59c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L13,16.17V5c0,-0.55 -0.45,-1 -1,-1l0,0C11.45,4 11,4.45 11,5z"/>
+ android:pathData="M11,5v11.17l-4.88,-4.88c-0.39,-0.39 -1.03,-0.39 -1.42,0 -0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0l6.59,-6.59c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L13,16.17V5c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down.xml
index 0e5dc94..d6eddfb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.71,11.71l2.59,2.59c0.39,0.39 1.02,0.39 1.41,0l2.59,-2.59c0.63,-0.63 0.18,-1.71 -0.71,-1.71H9.41C8.52,10 8.08,11.08 8.71,11.71z"/>
+ android:pathData="M8.71,11.71l2.59,2.59c0.39,0.39 1.02,0.39 1.41,0l2.59,-2.59c0.63,-0.63 0.18,-1.71 -0.71,-1.71H9.41c-0.89,0 -1.33,1.08 -0.7,1.71z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down_circle.xml
index a69f9e1..d8bd522 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_down_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM11.65,14.65l-2.79,-2.79C8.54,11.54 8.76,11 9.21,11h5.59c0.45,0 0.67,0.54 0.35,0.85l-2.79,2.79C12.16,14.84 11.84,14.84 11.65,14.65z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11.65,14.65l-2.79,-2.79c-0.32,-0.32 -0.1,-0.86 0.35,-0.86h5.59c0.45,0 0.67,0.54 0.35,0.85l-2.79,2.79c-0.2,0.2 -0.52,0.2 -0.71,0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_up.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_up.xml
index b715200..2d03cf5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_up.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_drop_up.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.71,12.29L11.3,9.7c0.39,-0.39 1.02,-0.39 1.41,0l2.59,2.59c0.63,0.63 0.18,1.71 -0.71,1.71H9.41C8.52,14 8.08,12.92 8.71,12.29z"/>
+ android:pathData="M8.71,12.29L11.3,9.7c0.39,-0.39 1.02,-0.39 1.41,0l2.59,2.59c0.63,0.63 0.18,1.71 -0.71,1.71H9.41c-0.89,0 -1.33,-1.08 -0.7,-1.71z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward.xml
index 5f68a9b..ec39c0c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,13h11.17l-4.88,4.88c-0.39,0.39 -0.39,1.03 0,1.42l0,0c0.39,0.39 1.02,0.39 1.41,0l6.59,-6.59c0.39,-0.39 0.39,-1.02 0,-1.41l-6.58,-6.6c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L16.17,11H5c-0.55,0 -1,0.45 -1,1l0,0C4,12.55 4.45,13 5,13z"/>
+ android:pathData="M5,13h11.17l-4.88,4.88c-0.39,0.39 -0.39,1.03 0,1.42 0.39,0.39 1.02,0.39 1.41,0l6.59,-6.59c0.39,-0.39 0.39,-1.02 0,-1.41l-6.58,-6.6c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L16.17,11H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward_ios.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward_ios.xml
index 26b95a8..a0f01f5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward_ios.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_forward_ios.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.12,21.12L7.12,21.12c0.49,0.49 1.28,0.49 1.77,0l8.41,-8.41c0.39,-0.39 0.39,-1.02 0,-1.41L8.88,2.88C8.4,2.4 7.6,2.4 7.12,2.88l0,0c-0.49,0.49 -0.49,1.28 0,1.77L14.46,12l-7.35,7.35C6.63,19.84 6.63,20.63 7.12,21.12z"/>
+ android:pathData="M7.38,21.01c0.49,0.49 1.28,0.49 1.77,0l8.31,-8.31c0.39,-0.39 0.39,-1.02 0,-1.41L9.15,2.98c-0.49,-0.49 -1.28,-0.49 -1.77,0s-0.49,1.28 0,1.77L14.62,12l-7.25,7.25c-0.48,0.48 -0.48,1.28 0.01,1.76z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_left.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_left.xml
index efba959..c6bd8c4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_left.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_left.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.29,8.71L9.7,11.3c-0.39,0.39 -0.39,1.02 0,1.41l2.59,2.59c0.63,0.63 1.71,0.18 1.71,-0.71V9.41C14,8.52 12.92,8.08 12.29,8.71z"/>
+ android:pathData="M12.29,8.71L9.7,11.3c-0.39,0.39 -0.39,1.02 0,1.41l2.59,2.59c0.63,0.63 1.71,0.18 1.71,-0.71V9.41c0,-0.89 -1.08,-1.33 -1.71,-0.7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_right.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_right.xml
index a3f6c8e..8ca41e3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_right.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_right.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.71,15.29l2.59,-2.59c0.39,-0.39 0.39,-1.02 0,-1.41L11.71,8.7C11.08,8.08 10,8.52 10,9.41v5.17C10,15.48 11.08,15.92 11.71,15.29z"/>
+ android:pathData="M11.71,15.29l2.59,-2.59c0.39,-0.39 0.39,-1.02 0,-1.41L11.71,8.7c-0.63,-0.62 -1.71,-0.18 -1.71,0.71v5.17c0,0.9 1.08,1.34 1.71,0.71z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/arrow_upward.xml b/compose/material/material/icons/generator/raw-icons/rounded/arrow_upward.xml
index 73d234f..c40a902 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/arrow_upward.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/arrow_upward.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,19V7.83l4.88,4.88c0.39,0.39 1.03,0.39 1.42,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-6.59,-6.59c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.6,6.58c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L11,7.83V19c0,0.55 0.45,1 1,1l0,0C12.55,20 13,19.55 13,19z"/>
+ android:pathData="M13,19V7.83l4.88,4.88c0.39,0.39 1.03,0.39 1.42,0 0.39,-0.39 0.39,-1.02 0,-1.41l-6.59,-6.59c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.6,6.58c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L11,7.83V19c0,0.55 0.45,1 1,1s1,-0.45 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/art_track.xml b/compose/material/material/icons/generator/raw-icons/rounded/art_track.xml
index 312235b..66353a4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/art_track.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/art_track.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,19L18,19c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v12C17,18.55 17.45,19 18,19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,6v12c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h0C21.45,5 21,5.45 21,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,5H3C1.9,5 1,5.9 1,7v10c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V7C15,5.9 14.1,5 13,5zM4,15l2.12,-2.83L7.5,14l1.88,-2.5L12,15H4z"/>
+ android:pathData="M21,13h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM21,7h-6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM15,17h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM12,9v6c0,1.1 -0.9,2 -2,2L4,17c-1.1,0 -2,-0.9 -2,-2L2,9c0,-1.1 0.9,-2 2,-2h6c1.1,0 2,0.9 2,2zM9.9,14.2l-1.26,-1.68c-0.2,-0.26 -0.59,-0.27 -0.8,-0.01L6.5,14.26l-0.85,-1.03c-0.2,-0.25 -0.58,-0.24 -0.78,0.01l-0.74,0.95c-0.26,0.33 -0.02,0.81 0.39,0.81L9.5,15c0.41,0 0.65,-0.47 0.4,-0.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/article.xml b/compose/material/material/icons/generator/raw-icons/rounded/article.xml
index eeffece3..3f83b6c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/article.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/article.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM13,17H8c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1C14,16.55 13.55,17 13,17zM16,13H8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1S16.55,13 16,13zM16,9H8C7.45,9 7,8.55 7,8s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1S16.55,9 16,9z"/>
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM13,17H8c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1C14,16.55 13.55,17 13,17zM16,13H8c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1C17,12.55 16.55,13 16,13zM16,9H8C7.45,9 7,8.55 7,8c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1C17,8.55 16.55,9 16,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/aspect_ratio.xml b/compose/material/material/icons/generator/raw-icons/rounded/aspect_ratio.xml
index c6800ff..aed6621 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/aspect_ratio.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/aspect_ratio.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,18H4V6h16V18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,12c0.55,0 1,-0.45 1,-1V9h2c0.55,0 1,-0.45 1,-1S9.55,7 9,7H6C5.45,7 5,7.45 5,8v3C5,11.55 5.45,12 6,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,17h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1S14.45,17 15,17z"/>
+ android:pathData="M18,12c-0.55,0 -1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1zM7,9h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,7c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L7,9zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM20,19.01L4,19.01c-0.55,0 -1,-0.45 -1,-1L3,5.99c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12.02c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assessment.xml b/compose/material/material/icons/generator/raw-icons/rounded/assessment.xml
index e5612aa..6899ce1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assessment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assessment.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM8,17c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5C9,16.55 8.55,17 8,17zM12,17c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8C13,16.55 12.55,17 12,17zM16,17c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1c0.55,0 1,0.45 1,1v2C17,16.55 16.55,17 16,17z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM8,17c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5c0,0.55 -0.45,1 -1,1zM12,17c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8c0,0.55 -0.45,1 -1,1zM16,17c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assignment.xml b/compose/material/material/icons/generator/raw-icons/rounded/assignment.xml
index 2e4cfa5..54fb9d7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assignment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assignment.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,2.75c0.41,0 0.75,0.34 0.75,0.75c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75C11.25,3.09 11.59,2.75 12,2.75zM13,17H8c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1v0C14,16.55 13.55,17 13,17zM16,13H8c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v0C17,12.55 16.55,13 16,13zM16,9H8C7.45,9 7,8.55 7,8v0c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v0C17,8.55 16.55,9 16,9z"/>
+ android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1s-2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM13,17L8,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h5c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM16,13L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM16,9L8,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assignment_ind.xml b/compose/material/material/icons/generator/raw-icons/rounded/assignment_ind.xml
index 627604a..ef381eb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assignment_ind.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assignment_ind.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,2.75c0.41,0 0.75,0.34 0.75,0.75c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75C11.25,3.09 11.59,2.75 12,2.75zM12,6c1.93,0 3.5,1.57 3.5,3.5S13.93,13 12,13s-3.5,-1.57 -3.5,-3.5S10.07,6 12,6zM19,19H5v-0.23c0,-0.62 0.28,-1.2 0.76,-1.58C7.47,15.82 9.64,15 12,15s4.53,0.82 6.24,2.19c0.48,0.38 0.76,0.97 0.76,1.58V19z"/>
+ android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1s-2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM12,7c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM18,19L6,19v-1.4c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1L18,19z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assignment_return.xml b/compose/material/material/icons/generator/raw-icons/rounded/assignment_return.xml
index 7ec91c1..e3c8cf1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assignment_return.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assignment_return.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,2.75c0.41,0 0.75,0.34 0.75,0.75c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75C11.25,3.09 11.59,2.75 12,2.75zM15,13h-3v1.79c0,0.45 -0.54,0.67 -0.85,0.35l-2.79,-2.79c-0.2,-0.2 -0.2,-0.51 0,-0.71l2.79,-2.79C11.46,8.54 12,8.76 12,9.21V11h3c0.55,0 1,0.45 1,1C16,12.55 15.55,13 15,13z"/>
+ android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1s-2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM16,15h-4v3l-4.65,-4.65c-0.2,-0.2 -0.2,-0.51 0,-0.71L12,8v3h4v4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assignment_returned.xml b/compose/material/material/icons/generator/raw-icons/rounded/assignment_returned.xml
index 34f59e0..c45f838 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assignment_returned.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assignment_returned.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,2.75c0.41,0 0.75,0.34 0.75,0.75c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75C11.25,3.09 11.59,2.75 12,2.75zM11.65,15.65l-2.79,-2.79C8.54,12.54 8.76,12 9.21,12H11V9c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3h1.79c0.45,0 0.67,0.54 0.35,0.85l-2.79,2.79C12.16,15.84 11.84,15.84 11.65,15.65z"/>
+ android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1s-2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM11.65,17.65L7,13h3L10,9h4v4h3l-4.65,4.65c-0.19,0.19 -0.51,0.19 -0.7,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assignment_turned_in.xml b/compose/material/material/icons/generator/raw-icons/rounded/assignment_turned_in.xml
index 7c97f20..cacad9c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assignment_turned_in.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assignment_turned_in.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,2.75c0.41,0 0.75,0.34 0.75,0.75c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75C11.25,3.09 11.59,2.75 12,2.75zM16.95,9.63l-5.66,5.66c-0.39,0.39 -1.02,0.39 -1.41,0l-2.83,-2.83c-0.39,-0.39 -0.39,-1.02 0,-1.41v0c0.39,-0.39 1.02,-0.39 1.41,0l2.12,2.12l4.95,-4.95c0.39,-0.39 1.02,-0.39 1.41,0C17.34,8.61 17.34,9.24 16.95,9.63z"/>
+ android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1s-2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM9.29,16.29L6.7,13.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L10,14.17l5.88,-5.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-6.59,6.59c-0.38,0.39 -1.02,0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assistant.xml b/compose/material/material/icons/generator/raw-icons/rounded/assistant.xml
index 221e4ce..158f705 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assistant.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assistant.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,2H5C3.9,2 3,2.9 3,4v14c0,1.1 0.9,2 2,2h4l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0L15,20h4c1.1,0 2,-0.9 2,-2V4C21,2.9 20.1,2 19,2zM13.57,12.57l-1.12,2.44c-0.18,0.39 -0.73,0.39 -0.91,0l-1.12,-2.44l-2.44,-1.12c-0.39,-0.18 -0.39,-0.73 0,-0.91l2.44,-1.12l1.12,-2.44c0.18,-0.39 0.73,-0.39 0.91,0l1.12,2.44l2.44,1.12c0.39,0.18 0.39,0.73 0,0.91L13.57,12.57z"/>
+ android:pathData="M19,2L5,2c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h4l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0L15,20h4c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM13.88,12.88L12,17l-1.88,-4.12L6,11l4.12,-1.88L12,5l1.88,4.12L18,11l-4.12,1.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/assistant_photo.xml b/compose/material/material/icons/generator/raw-icons/rounded/assistant_photo.xml
index dabb708..863a757 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/assistant_photo.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/assistant_photo.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.4,6l-0.24,-1.2C14.07,4.34 13.66,4 13.18,4H6C5.45,4 5,4.45 5,5v15c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-6h5.6l0.24,1.2c0.09,0.47 0.5,0.8 0.98,0.8H19c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1H14.4z"/>
+ android:pathData="M14.4,6l-0.24,-1.2c-0.09,-0.46 -0.5,-0.8 -0.98,-0.8H6c-0.55,0 -1,0.45 -1,1v15c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-6h5.6l0.24,1.2c0.09,0.47 0.5,0.8 0.98,0.8H19c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1h-4.6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/atm.xml b/compose/material/material/icons/generator/raw-icons/rounded/atm.xml
index 2cc1f08..616e937 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/atm.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/atm.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,9.75L8,9.75c0,0.41 0.34,0.75 0.75,0.75h1.5v3.75c0,0.41 0.34,0.75 0.75,0.75l0,0c0.41,0 0.75,-0.34 0.75,-0.75V10.5h1.5c0.41,0 0.75,-0.34 0.75,-0.75l0,0C14,9.34 13.66,9 13.25,9h-4.5C8.34,9 8,9.34 8,9.75zM6,9H3c-0.55,0 -1,0.45 -1,1v4.25C2,14.66 2.34,15 2.75,15l0,0c0.41,0 0.75,-0.34 0.75,-0.75V13.5h2v0.75C5.5,14.66 5.84,15 6.25,15l0,0C6.66,15 7,14.66 7,14.25V10C7,9.45 6.55,9 6,9zM5.5,12h-2v-1.5h2V12zM21,9h-4.5c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75l0,0c0.41,0 0.75,-0.34 0.75,-0.75V10.5h1v2.75c0,0.41 0.34,0.75 0.75,0.75l0,0c0.41,0 0.75,-0.34 0.75,-0.75v-2.76h1v3.76c0,0.41 0.34,0.75 0.75,0.75l0,0c0.41,0 0.75,-0.34 0.75,-0.75V10C22,9.45 21.55,9 21,9z"/>
+ android:pathData="M8,9.75c0,0.41 0.34,0.75 0.75,0.75h1.5v3.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L11.75,10.5h1.5c0.41,0 0.75,-0.34 0.75,-0.75S13.66,9 13.25,9h-4.5c-0.41,0 -0.75,0.34 -0.75,0.75zM6,9L3,9c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75v-0.75h2v0.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L7,10c0,-0.55 -0.45,-1 -1,-1zM5.5,12h-2v-1.5h2L5.5,12zM21,9h-4.5c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L17,10.5h1v2.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75v-2.76h1v3.76c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L22,10c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/attach_file.xml b/compose/material/material/icons/generator/raw-icons/rounded/attach_file.xml
index 81781a7..e2e2a54 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/attach_file.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/attach_file.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.5,6.75l0,9.58c0,2.09 -1.53,3.95 -3.61,4.15C9.51,20.71 7.5,18.84 7.5,16.5l0,-10.36c0,-1.31 0.94,-2.5 2.24,-2.63C11.24,3.36 12.5,4.53 12.5,6v9.5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6.75C10.5,6.34 10.16,6 9.75,6h0C9.34,6 9,6.34 9,6.75l0,8.61c0,1.31 0.94,2.5 2.24,2.63c1.5,0.15 2.76,-1.02 2.76,-2.49l0,-9.33c0,-2.09 -1.53,-3.95 -3.61,-4.15C8.01,1.79 6,3.66 6,6l0,10.27c0,2.87 2.1,5.44 4.96,5.71C14.25,22.28 17,19.72 17,16.5V6.75C17,6.34 16.66,6 16.25,6h0C15.84,6 15.5,6.34 15.5,6.75z"/>
+ android:pathData="M16.5,6.75v10.58c0,2.09 -1.53,3.95 -3.61,4.15 -2.39,0.23 -4.39,-1.64 -4.39,-3.98V5.14c0,-1.31 0.94,-2.5 2.24,-2.63 1.5,-0.15 2.76,1.02 2.76,2.49v10.5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6.75c0,-0.41 -0.34,-0.75 -0.75,-0.75s-0.75,0.34 -0.75,0.75v8.61c0,1.31 0.94,2.5 2.24,2.63 1.5,0.15 2.76,-1.02 2.76,-2.49V5.17c0,-2.09 -1.53,-3.95 -3.61,-4.15C9.01,0.79 7,2.66 7,5v12.27c0,2.87 2.1,5.44 4.96,5.71 3.29,0.3 6.04,-2.26 6.04,-5.48V6.75c0,-0.41 -0.34,-0.75 -0.75,-0.75s-0.75,0.34 -0.75,0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/attach_money.xml b/compose/material/material/icons/generator/raw-icons/rounded/attach_money.xml
index a8c561a..4fc6c63 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/attach_money.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/attach_money.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.06,10.92C11.44,10.38 9.9,9.94 9.9,8.63c0,-1.23 1.34,-1.67 2.17,-1.67c0.97,0 1.57,0.46 1.91,0.9c0.29,0.38 0.79,0.53 1.23,0.35l0,0c0.62,-0.26 0.83,-1.04 0.41,-1.58C15.14,5.99 14.32,5.3 13,5.08V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1.11C9.63,5.38 7.81,6.5 7.81,8.67c0,2.57 2.31,3.36 4.02,3.97c1.89,0.67 2.73,1.29 2.73,2.44c0,1.36 -1.25,1.92 -2.37,1.92c-1.41,0 -2.17,-0.93 -2.56,-1.66c-0.24,-0.47 -0.82,-0.65 -1.3,-0.45l-0.06,0.03c-0.56,0.23 -0.81,0.88 -0.54,1.42c0.49,0.95 1.43,2.11 3.27,2.53V20c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-1.08c0.06,-0.01 3.67,-0.41 3.67,-3.87C16.69,12.82 15.22,11.67 13.06,10.92z"/>
+ android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.42,0 2.13,0.54 2.39,1.4 0.12,0.4 0.45,0.7 0.87,0.7h0.3c0.66,0 1.13,-0.65 0.9,-1.27 -0.42,-1.18 -1.4,-2.16 -2.96,-2.54V4.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,3.67 10,4.5v0.66c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -1.65,0 -2.5,-0.59 -2.83,-1.43 -0.15,-0.39 -0.49,-0.67 -0.9,-0.67h-0.28c-0.67,0 -1.14,0.68 -0.89,1.3 0.57,1.39 1.9,2.21 3.4,2.53v0.67c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-0.65c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/attachment.xml b/compose/material/material/icons/generator/raw-icons/rounded/attachment.xml
index 863dd70..015cdcc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/attachment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/attachment.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.25,16l-9.58,0c-2.09,0 -3.95,-1.53 -4.15,-3.61C3.29,10.01 5.16,8 7.5,8l10.36,0c1.31,0 2.5,0.94 2.63,2.24C20.64,11.74 19.47,13 18,13H8.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8.75c0.41,0 0.75,-0.34 0.75,-0.75v0c0,-0.41 -0.34,-0.75 -0.75,-0.75l-8.61,0c-1.31,0 -2.5,0.94 -2.63,2.24c-0.15,1.5 1.02,2.76 2.49,2.76l9.33,0c2.09,0 3.95,-1.53 4.15,-3.61C22.21,8.51 20.34,6.5 18,6.5l-10.27,0c-2.87,0 -5.44,2.1 -5.71,4.96C1.72,14.75 4.28,17.5 7.5,17.5h9.75c0.41,0 0.75,-0.34 0.75,-0.75v0C18,16.34 17.66,16 17.25,16z"/>
+ android:pathData="M17.75,16H7.17c-2.09,0 -3.95,-1.53 -4.15,-3.61C2.79,10.01 4.66,8 7,8h12.36c1.31,0 2.5,0.94 2.63,2.24 0.15,1.5 -1.02,2.76 -2.49,2.76H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8.75c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75H9.14c-1.31,0 -2.5,0.94 -2.63,2.24 -0.15,1.5 1.02,2.76 2.49,2.76h10.33c2.09,0 3.95,-1.53 4.15,-3.61 0.23,-2.39 -1.64,-4.39 -3.98,-4.39H7.23c-2.87,0 -5.44,2.1 -5.71,4.96 -0.3,3.29 2.26,6.04 5.48,6.04h10.75c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/attribution.xml b/compose/material/material/icons/generator/raw-icons/rounded/attribution.xml
index 556a80c..2386aaa 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/attribution.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/attribution.xml
@@ -6,10 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8.5c-0.91,0 -2.75,0.46 -2.75,1.38V14c0,0.28 0.22,0.5 0.5,0.5h1v3.25c0,0.69 0.56,1.25 1.25,1.25s1.25,-0.56 1.25,-1.25V14.5h1c0.28,0 0.5,-0.22 0.5,-0.5V9.88C14.75,8.97 12.91,8.5 12,8.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20z"/>
+ android:pathData="M12,8.5c-0.91,0 -2.75,0.46 -2.75,1.38L9.25,14c0,0.28 0.22,0.5 0.5,0.5h1v3.25c0,0.69 0.56,1.25 1.25,1.25s1.25,-0.56 1.25,-1.25L13.25,14.5h1c0.28,0 0.5,-0.22 0.5,-0.5L14.75,9.88c0,-0.91 -1.84,-1.38 -2.75,-1.38zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,6.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/audiotrack.xml b/compose/material/material/icons/generator/raw-icons/rounded/audiotrack.xml
index a3ed653..20ed3cc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/audiotrack.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/audiotrack.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,5v8.55c-0.94,-0.54 -2.1,-0.75 -3.33,-0.32C7.33,13.71 6.3,14.9 6.06,16.3c-0.46,2.74 1.86,5.08 4.59,4.65c1.96,-0.31 3.35,-2.11 3.35,-4.1V7h2c1.1,0 2,-0.9 2,-2l0,0c0,-1.1 -0.9,-2 -2,-2h-2C12.9,3 12,3.9 12,5z"/>
+ android:pathData="M12,5v8.55c-0.94,-0.54 -2.1,-0.75 -3.33,-0.32 -1.34,0.48 -2.37,1.67 -2.61,3.07 -0.46,2.74 1.86,5.08 4.59,4.65 1.96,-0.31 3.35,-2.11 3.35,-4.1V7h2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-2c-1.1,0 -2,0.9 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/auto_delete.xml b/compose/material/material/icons/generator/raw-icons/rounded/auto_delete.xml
index a07e9e4..18d0789 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/auto_delete.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/auto_delete.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,12c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S19.76,12 17,12zM18.65,19.35L18.65,19.35c-0.2,0.2 -0.51,0.2 -0.71,0l-1.65,-1.65C16.11,17.52 16,17.27 16,17v-2.5c0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5V17l1.65,1.65C18.84,18.84 18.84,19.16 18.65,19.35z"/>
+ android:pathData="M16,9c-0.7,0 -1.37,0.1 -2,0.29V7c0,-1.1 -0.9,-2 -2,-2H4C2.9,5 2,5.9 2,7v10c0,1.1 0.9,2 2,2h5.68c1.12,2.36 3.53,4 6.32,4c3.87,0 7,-3.13 7,-7C23,12.13 19.87,9 16,9zM16,21c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5s5,2.24 5,5S18.76,21 16,21z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M18,6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2.5l-0.71,-0.71C14.61,3.11 14.35,3 14.09,3H9.91c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4H6C5.45,4 5,4.45 5,5s0.45,1 1,1H18z"/>
+ android:pathData="M14,4c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-2.5l-0.71,-0.71C10.61,1.11 10.35,1 10.09,1H5.91C5.65,1 5.39,1.11 5.21,1.29L4.5,2H2C1.45,2 1,2.45 1,3c0,0.55 0.45,1 1,1H14z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17,10c0.34,0 0.67,0.03 1,0.08V7H6v12c0,1.1 0.9,2 2,2h3.26C10.47,19.87 10,18.49 10,17C10,13.13 13.13,10 17,10z"/>
+ android:pathData="M15.75,12L15.75,12C15.34,12 15,12.34 15,12.75v3.68c0,0.36 0.19,0.68 0.5,0.86l2.52,1.47c0.33,0.19 0.75,0.09 0.96,-0.22v0c0.23,-0.34 0.12,-0.81 -0.24,-1.02L16.5,16.2v-3.45C16.5,12.34 16.16,12 15.75,12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/autorenew.xml b/compose/material/material/icons/generator/raw-icons/rounded/autorenew.xml
index 953af82..33dad0e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/autorenew.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/autorenew.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.35,13.99C5.01,10.29 7.71,6 12,6v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C12.54,1.54 12,1.76 12,2.21V4C6.24,4 2.61,9.78 4.52,14.79c0.24,0.63 1.08,0.78 1.56,0.3l0.08,-0.08C6.42,14.75 6.48,14.35 6.35,13.99z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.64,10.02C19.01,13.86 16.17,18 12,18v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.35V20c5.76,0 9.39,-5.78 7.48,-10.79c-0.24,-0.63 -1.08,-0.78 -1.56,-0.3l-0.07,0.07C17.58,9.25 17.52,9.65 17.64,10.02z"/>
+ android:pathData="M12,6v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L12,4c-4.42,0 -8,3.58 -8,8 0,1.04 0.2,2.04 0.57,2.95 0.27,0.67 1.13,0.85 1.64,0.34 0.27,-0.27 0.38,-0.68 0.23,-1.04C6.15,13.56 6,12.79 6,12c0,-3.31 2.69,-6 6,-6zM17.79,8.71c-0.27,0.27 -0.38,0.69 -0.23,1.04 0.28,0.7 0.44,1.46 0.44,2.25 0,3.31 -2.69,6 -6,6v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.35L12,20c4.42,0 8,-3.58 8,-8 0,-1.04 -0.2,-2.04 -0.57,-2.95 -0.27,-0.67 -1.13,-0.85 -1.64,-0.34z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/av_timer.xml b/compose/material/material/icons/generator/raw-icons/rounded/av_timer.xml
index f26a458..a0d655b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/av_timer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/av_timer.xml
@@ -6,14 +6,14 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M12,17m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M7,11m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M7,12m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17,11m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M17,12m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4.08c3.31,0.48 5.87,3.25 6,6.66c0.14,3.85 -3.03,7.2 -6.88,7.26C8.19,18.06 5,14.91 5,11c0,-1.68 0.59,-3.22 1.58,-4.42l4.71,4.72c0.39,0.39 1.02,0.39 1.41,0s0.39,-1.02 0,-1.41L7.26,4.46c-0.38,-0.38 -1,-0.39 -1.4,-0.02C4.1,6.07 3,8.4 3,11c0,5.04 4.14,9.12 9.21,9c4.7,-0.11 8.63,-4.01 8.78,-8.71C21.16,6.19 17.07,2 12,2z"/>
+ android:pathData="M12,3c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-0.92c3.31,0.48 5.87,3.25 6,6.66 0.14,3.85 -3.03,7.2 -6.88,7.26C8.19,19.06 5,15.91 5,12c0,-1.68 0.59,-3.22 1.58,-4.42l4.71,4.72c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.26,5.46c-0.38,-0.38 -1,-0.39 -1.4,-0.02C4.1,7.07 3,9.4 3,12c0,5.04 4.14,9.12 9.21,9 4.7,-0.11 8.63,-4.01 8.78,-8.71C21.16,7.19 17.07,3 12,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/back_hand.xml b/compose/material/material/icons/generator/raw-icons/rounded/back_hand.xml
new file mode 100644
index 0000000..14fc8d0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/back_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,16c0,4.42 -3.58,8 -8,8c-3.26,0 -6.19,-1.99 -7.4,-5.02l-3.03,-7.61C2.26,10.58 3,9.79 3.81,10.05l0.79,0.26c0.56,0.18 1.02,0.61 1.24,1.16l1.28,3.21C7.2,14.88 7.38,15 7.58,15H8V3.25C8,2.56 8.56,2 9.25,2s1.25,0.56 1.25,1.25v8.25c0,0.28 0.22,0.5 0.5,0.5l0,0c0.28,0 0.5,-0.22 0.5,-0.5V1.25C11.5,0.56 12.06,0 12.75,0S14,0.56 14,1.25V11.5c0,0.28 0.22,0.5 0.5,0.5l0,0c0.28,0 0.5,-0.22 0.5,-0.5V2.75c0,-0.69 0.56,-1.25 1.25,-1.25c0.69,0 1.25,0.56 1.25,1.25v8.75c0,0.28 0.22,0.5 0.5,0.5l0,0c0.28,0 0.5,-0.22 0.5,-0.5V5.75c0,-0.69 0.56,-1.25 1.25,-1.25S21,5.06 21,5.75V16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/backspace.xml b/compose/material/material/icons/generator/raw-icons/rounded/backspace.xml
index c2e5cb4..0982c6b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/backspace.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/backspace.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,5H9C8.35,5 7.75,5.31 7.37,5.84l-3.55,5c-0.49,0.69 -0.49,1.62 0,2.32l3.55,5C7.75,18.69 8.35,19 9,19h10c1.1,0 2,-0.9 2,-2V7C21,5.9 20.1,5 19,5zM17.29,15.29L17.29,15.29c-0.39,0.39 -1.02,0.39 -1.41,0L14,13.41l-1.88,1.88c-0.39,0.39 -1.02,0.39 -1.41,0l0,0c-0.39,-0.39 -0.39,-1.02 0,-1.41L12.59,12l-1.88,-1.88c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0L14,10.59l1.88,-1.88c0.39,-0.39 1.02,-0.39 1.41,0v0c0.39,0.39 0.39,1.02 0,1.41L15.41,12l1.88,1.88C17.68,14.27 17.68,14.9 17.29,15.29z"/>
+ android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0.37,11.45c-0.22,0.34 -0.22,0.77 0,1.11l5.04,7.56c0.36,0.52 0.9,0.88 1.59,0.88h15c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM18.3,16.3c-0.39,0.39 -1.02,0.39 -1.41,0L14,13.41l-2.89,2.89c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41L12.59,12 9.7,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L14,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41L15.41,12l2.89,2.89c0.38,0.38 0.38,1.02 0,1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/ballot.xml b/compose/material/material/icons/generator/raw-icons/rounded/ballot.xml
index 357d1e6..ddd16c3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/ballot.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/ballot.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM11,16c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1V16zM11,10c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1V10zM16,16h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3c0.55,0 1,0.45 1,1S16.55,16 16,16zM16,10h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3c0.55,0 1,0.45 1,1S16.55,10 16,10z"/>
+ android:pathData="M14,9.5h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM14,16.5h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM19,21L5,21c-1.1,0 -2,-0.9 -2,-2L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2v14c0,1.1 -0.9,2 -2,2zM7,11h3c0.55,0 1,-0.45 1,-1L11,7c0,-0.55 -0.45,-1 -1,-1L7,6c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1zM7,7h3v3L7,10L7,7zM7,18h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1L7,13c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1zM7,14h3v3L7,17v-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bar_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/bar_chart.xml
index 9732e41..772577b2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bar_chart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bar_chart.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.4,9.2h0.2C7.37,9.2 8,9.83 8,10.6v7C8,18.37 7.37,19 6.6,19H6.4C5.63,19 5,18.37 5,17.6v-7C5,9.83 5.63,9.2 6.4,9.2zM12,5L12,5c0.77,0 1.4,0.63 1.4,1.4v11.2c0,0.77 -0.63,1.4 -1.4,1.4l0,0c-0.77,0 -1.4,-0.63 -1.4,-1.4V6.4C10.6,5.63 11.23,5 12,5zM17.6,13L17.6,13c0.77,0 1.4,0.63 1.4,1.4v3.2c0,0.77 -0.63,1.4 -1.4,1.4l0,0c-0.77,0 -1.4,-0.63 -1.4,-1.4v-3.2C16.2,13.63 16.83,13 17.6,13z"/>
+ android:pathData="M6.4,9.2h0.2c0.77,0 1.4,0.63 1.4,1.4v7c0,0.77 -0.63,1.4 -1.4,1.4h-0.2c-0.77,0 -1.4,-0.63 -1.4,-1.4v-7c0,-0.77 0.63,-1.4 1.4,-1.4zM12,5c0.77,0 1.4,0.63 1.4,1.4v11.2c0,0.77 -0.63,1.4 -1.4,1.4 -0.77,0 -1.4,-0.63 -1.4,-1.4L10.6,6.4c0,-0.77 0.63,-1.4 1.4,-1.4zM17.6,13c0.77,0 1.4,0.63 1.4,1.4v3.2c0,0.77 -0.63,1.4 -1.4,1.4 -0.77,0 -1.4,-0.63 -1.4,-1.4v-3.2c0,-0.77 0.63,-1.4 1.4,-1.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/battery_alert.xml b/compose/material/material/icons/generator/raw-icons/rounded/battery_alert.xml
index 6161788..66fc981 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/battery_alert.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/battery_alert.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,4h-2V3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1H8C7.45,4 7,4.45 7,5v16c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1V5C17,4.45 16.55,4 16,4zM12,14L12,14c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3C13,13.55 12.55,14 12,14zM13,17c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1s0.45,-1 1,-1S13,16.45 13,17z"/>
+ android:pathData="M15.67,4L14,4L14,3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1L8.33,4C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.34,22h7.32c0.74,0 1.34,-0.6 1.34,-1.33L17,5.33C17,4.6 16.4,4 15.67,4zM13,18h-2v-2h2v2zM13,13c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/battery_charging_full.xml b/compose/material/material/icons/generator/raw-icons/rounded/battery_charging_full.xml
index 4949d1b..94acced 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/battery_charging_full.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/battery_charging_full.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,4h-2V3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1H8C7.45,4 7,4.45 7,5v16c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1V5C17,4.45 16.55,4 16,4zM14.61,13.24l-2.67,5C11.7,18.69 11,18.52 11,18v-3.5H9.83c-0.38,0 -0.62,-0.4 -0.44,-0.74l2.67,-5C12.3,8.31 13,8.48 13,9v3.5h1.17C14.54,12.5 14.79,12.9 14.61,13.24z"/>
+ android:pathData="M15.67,4L14,4L14,3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1L8.33,4C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.34,22h7.32c0.74,0 1.34,-0.6 1.34,-1.33L17,5.33C17,4.6 16.4,4 15.67,4zM14.61,13.24l-2.67,5c-0.24,0.45 -0.94,0.28 -0.94,-0.24v-3.5L9.83,14.5c-0.38,0 -0.62,-0.4 -0.44,-0.74l2.67,-5c0.24,-0.45 0.94,-0.28 0.94,0.24v3.5h1.17c0.37,0 0.62,0.4 0.44,0.74z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/battery_full.xml b/compose/material/material/icons/generator/raw-icons/rounded/battery_full.xml
index 3281b5a..059f8a5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/battery_full.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/battery_full.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,4h-3V2h-4v2H7v18h10V4z"/>
+ android:pathData="M15.67,4H14V3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.34,22h7.32c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/battery_std.xml b/compose/material/material/icons/generator/raw-icons/rounded/battery_std.xml
index 174396a..059f8a5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/battery_std.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/battery_std.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,4h-2V3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1H8C7.45,4 7,4.45 7,5v16c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1V5C17,4.45 16.55,4 16,4z"/>
+ android:pathData="M15.67,4H14V3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.34,22h7.32c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/battery_unknown.xml b/compose/material/material/icons/generator/raw-icons/rounded/battery_unknown.xml
index ca7fa2c..cada270 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/battery_unknown.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/battery_unknown.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,4V3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1H8C7.45,4 7,4.45 7,5v16c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1H14zM12.01,18c-0.59,0 -1.05,-0.47 -1.05,-1.05c0,-0.59 0.47,-1.04 1.05,-1.04c0.59,0 1.04,0.45 1.04,1.04C13.04,17.53 12.6,18 12.01,18zM14.51,11.83c-0.63,0.93 -1.23,1.21 -1.56,1.81c-0.08,0.14 -0.13,0.26 -0.16,0.49c-0.05,0.39 -0.36,0.68 -0.75,0.68h-0.03c-0.44,0 -0.79,-0.38 -0.75,-0.82c0.03,-0.28 0.09,-0.57 0.25,-0.84c0.41,-0.73 1.18,-1.16 1.63,-1.8c0.48,-0.68 0.21,-1.94 -1.14,-1.94c-0.61,0 -1.01,0.32 -1.26,0.7c-0.19,0.29 -0.57,0.39 -0.89,0.25l0,0c-0.42,-0.18 -0.6,-0.7 -0.34,-1.07C10.02,8.55 10.87,8 11.99,8c1.23,0 2.08,0.56 2.51,1.26C14.87,9.87 15.08,10.99 14.51,11.83z"/>
+ android:pathData="M15.67,4L14,4L14,3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1L8.33,4C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.34,22h7.32c0.74,0 1.34,-0.6 1.34,-1.33L17,5.33C17,4.6 16.4,4 15.67,4zM13,18h-2v-2h2v2zM14.3,12.69s-0.38,0.42 -0.67,0.71c-0.14,0.14 -0.27,0.31 -0.39,0.47l-0.09,0.15c-0.08,0.12 -0.14,0.25 -0.19,0.37 -0.09,0.22 -0.16,0.43 -0.16,0.61h-1.6c0,-0.42 0.12,-0.8 0.29,-1.13 0.06,-0.11 0.13,-0.21 0.2,-0.31 0.03,-0.05 0.06,-0.11 0.1,-0.16 0.11,-0.14 0.23,-0.28 0.34,-0.4l0.93,-0.94c0.27,-0.27 0.44,-0.65 0.44,-1.06 0,-0.83 -0.67,-1.5 -1.5,-1.5 -0.65,0 -1.21,0.41 -1.41,0.99 -0.11,0.31 -0.39,0.51 -0.71,0.51 -0.52,0 -0.88,-0.52 -0.71,-1.01C9.59,8.83 10.69,8 12,8c1.66,0 3,1.34 3,3 0,0.66 -0.27,1.26 -0.7,1.69z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/beach_access.xml b/compose/material/material/icons/generator/raw-icons/rounded/beach_access.xml
index 1b79c64..9103624 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/beach_access.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/beach_access.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.65,13.24l-0.02,-0.02l-1.41,1.41l0.02,0.02l5.64,5.64c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L14.65,13.24z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.66,6.66C5.53,7.79 6.55,12.32 10.24,16L16,10.24C12.32,6.55 7.79,5.53 6.66,6.66z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7.55,18.69l1.27,-1.27c-2.73,-2.73 -4.53,-6.36 -4.6,-9.13c-1.71,3.15 -1.64,7 0.23,10.08C5.12,19.46 6.65,19.59 7.55,18.69z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.37,4.46c-3.08,-1.87 -6.94,-1.94 -10.08,-0.23c2.77,0.07 6.4,1.87 9.13,4.6l1.27,-1.27C19.59,6.65 19.46,5.12 18.37,4.46z"/>
+ android:pathData="M13.13,14.56l1.43,-1.43 5.73,5.73c0.39,0.39 0.39,1.03 0,1.43 -0.39,0.39 -1.03,0.39 -1.43,0l-5.73,-5.73zM17.42,8.83l1.27,-1.27c0.89,-0.89 0.77,-2.43 -0.31,-3.08 -3.89,-2.38 -9.03,-1.89 -12.4,1.47 3.93,-1.3 8.31,-0.25 11.44,2.88zM5.95,5.98c-3.36,3.37 -3.85,8.51 -1.48,12.4 0.66,1.08 2.19,1.21 3.08,0.31l1.27,-1.27C5.7,14.29 4.65,9.91 5.95,5.98zM5.97,5.96l-0.01,0.01c-0.38,3.01 1.17,6.88 4.3,10.02l5.73,-5.73c-3.13,-3.13 -7.01,-4.68 -10.02,-4.3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/beenhere.xml b/compose/material/material/icons/generator/raw-icons/rounded/beenhere.xml
index e620316..7a74217 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/beenhere.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/beenhere.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2H6C4.9,2 4,2.9 4,4v12c0,0.63 0.3,1.22 0.8,1.6l6,4.5c0.71,0.53 1.69,0.53 2.4,0l6,-4.5c0.5,-0.38 0.8,-0.97 0.8,-1.6V4C20,2.9 19.1,2 18,2zM10.23,14.29l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-4.24,4.24C11.26,14.68 10.62,14.68 10.23,14.29z"/>
+ android:pathData="M19,1L5,1c-1.1,0 -1.99,0.9 -1.99,2L3,15.93c0,0.69 0.35,1.3 0.88,1.66l7.57,5.04c0.34,0.22 0.77,0.22 1.11,0l7.56,-5.04c0.53,-0.36 0.88,-0.97 0.88,-1.66L21,3c0,-1.1 -0.9,-2 -2,-2zM18.3,7.7l-7.59,7.59c-0.39,0.39 -1.02,0.39 -1.41,0L5.71,11.7c-0.39,-0.39 -0.39,-1.02 0,-1.41s1.02,-0.39 1.41,0L10,13.17l6.88,-6.88c0.39,-0.39 1.02,-0.39 1.41,0s0.4,1.02 0.01,1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bike_scooter.xml b/compose/material/material/icons/generator/raw-icons/rounded/bike_scooter.xml
index 97a0f85..3d157b5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bike_scooter.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bike_scooter.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,14h0.74L8.82,5.56C8.61,4.65 7.8,4 6.87,4H4C3.45,4 3,4.45 3,5l0,0c0,0.55 0.45,1 1,1h2.87l1.42,6.25H8.28C6.12,12.9 4.47,14.73 4.09,17H0v2h6v-1C6,15.79 7.79,14 10,14z"/>
+ android:pathData="M10,14h0.74L8.82,5.56C8.61,4.65 7.8,4 6.87,4H4C3.45,4 3,4.45 3,5v0c0,0.55 0.45,1 1,1h2.87l1.42,6.25c0,0 -0.01,0 -0.01,0C6.12,12.9 4.47,14.73 4.09,17H0v2h6v-1C6,15.79 7.79,14 10,14z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M18.75,8h-0.56l-1.35,-3.69C16.55,3.52 15.8,3 14.96,3H12c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h2.96l1.1,3H10.4l0.46,2H15c-0.43,0.58 -0.75,1.25 -0.9,2h-2.79l0.46,2h2.33c0.44,2.23 2.31,3.88 4.65,3.99c3.16,0.15 5.88,-2.83 5.12,-6.1C23.34,9.57 21.13,8 18.75,8zM18.88,16c-1.54,-0.06 -2.84,-1.37 -2.88,-2.92c-0.02,-0.96 0.39,-1.8 1.05,-2.36l0.62,1.7c0.19,0.52 0.76,0.79 1.28,0.6l0,0c0.52,-0.19 0.79,-0.76 0.6,-1.28l-0.63,-1.73c0,0 0,0 0.01,-0.01C20.64,9.96 22,11.29 22,13C22,14.72 20.62,16.06 18.88,16z"/>
+ android:pathData="M18.75,8l-0.56,0l-1.35,-3.69C16.55,3.52 15.8,3 14.96,3H12c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2.96l1.1,3H10.4l0.46,2H15c-0.43,0.58 -0.75,1.25 -0.9,2h-2.79l0.46,2h2.33c0.44,2.23 2.31,3.88 4.65,3.99c3.16,0.15 5.88,-2.83 5.12,-6.1C23.34,9.57 21.13,8 18.75,8zM18.88,16c-1.54,-0.06 -2.84,-1.37 -2.88,-2.92c-0.02,-0.96 0.39,-1.8 1.05,-2.36l0.62,1.7c0.19,0.52 0.76,0.79 1.28,0.6l0,0c0.52,-0.19 0.79,-0.76 0.6,-1.28l-0.63,-1.73c0,0 0,0 0.01,-0.01C20.64,9.96 22,11.29 22,13C22,14.72 20.62,16.06 18.88,16z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M10,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S11.66,15 10,15zM10,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S10.55,19 10,19z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/biotech.xml b/compose/material/material/icons/generator/raw-icons/rounded/biotech.xml
index b553611..a3bc9f8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/biotech.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/biotech.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,20L5,20c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-5v-2h4c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1l-6.88,0c-1.44,0 -2.76,-0.96 -3.05,-2.37c-0.28,-1.35 0.36,-2.58 1.39,-3.19C8.17,9.03 8,8.54 8,8c0,-0.21 0.04,-0.42 0.09,-0.62C6.28,8.13 5,9.92 5,12c0,2.76 2.24,5 5,5v2H6C5.45,19 5,19.45 5,20z"/>
+ android:pathData="M7,19c-1.1,0 -2,0.9 -2,2h14c0,-1.1 -0.9,-2 -2,-2h-4v-2h3c1.1,0 2,-0.9 2,-2h-8c-1.66,0 -3,-1.34 -3,-3c0,-1.09 0.59,-2.04 1.46,-2.56C8.17,9.03 8,8.54 8,8c0,-0.21 0.04,-0.42 0.09,-0.62C6.28,8.13 5,9.92 5,12c0,2.76 2.24,5 5,5v2H7z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M10.56,5.51C11.91,5.54 13,6.64 13,8c0,0.75 -0.33,1.41 -0.85,1.87l0.25,0.68c0.19,0.52 0.76,0.79 1.28,0.6c0.19,0.52 0.76,0.79 1.28,0.6c0.52,-0.19 0.79,-0.76 0.6,-1.28c0.52,-0.19 0.79,-0.76 0.6,-1.28L14.1,3.54c-0.19,-0.52 -0.76,-0.79 -1.28,-0.6c-0.19,-0.52 -0.76,-0.79 -1.28,-0.6c-0.52,0.19 -0.79,0.76 -0.6,1.28c-0.52,0.19 -0.79,0.76 -0.6,1.28L10.56,5.51z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/block.xml b/compose/material/material/icons/generator/raw-icons/rounded/block.xml
index 9f2216a..9fefeec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/block.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/block.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8c1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12C20,16.42 16.42,20 12,20z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8 1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12c0,4.42 -3.58,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth.xml b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth.xml
index 7e92b26..d5b8010 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,7l-4.29,-4.29C12.08,2.08 11,2.52 11,3.41v6.18L7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L10.59,12L5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L11,14.41v6.18c0,0.89 1.08,1.34 1.71,0.71L17,17c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12L17,8.42C17.39,8.03 17.39,7.39 17,7zM13,5.83l1.88,1.88L13,9.59V5.83zM14.88,16.29L13,18.17v-3.76L14.88,16.29z"/>
+ android:pathData="M17,7l-4.29,-4.29c-0.63,-0.63 -1.71,-0.19 -1.71,0.7v6.18L7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L11,14.41v6.18c0,0.89 1.08,1.34 1.71,0.71L17,17c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12 17,8.42c0.39,-0.39 0.39,-1.03 0,-1.42zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_audio.xml b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_audio.xml
index b41af5d..9a434a3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_audio.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_audio.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.58,12.36l1.38,1.38c0.28,0.28 0.75,0.14 0.84,-0.24c0.12,-0.48 0.18,-0.99 0.18,-1.5c0,-0.51 -0.06,-1.01 -0.18,-1.48c-0.09,-0.38 -0.56,-0.52 -0.84,-0.24l-1.39,1.38C14.39,11.85 14.39,12.17 14.58,12.36zM18.72,7.51l-0.05,0.05c-0.25,0.25 -0.3,0.62 -0.16,0.94c0.47,1.07 0.73,2.25 0.73,3.49c0,1.24 -0.26,2.42 -0.73,3.49c-0.14,0.32 -0.09,0.69 0.16,0.94l0,0c0.41,0.41 1.1,0.29 1.35,-0.23c0.63,-1.3 0.98,-2.76 0.98,-4.3c-0.01,-1.48 -0.34,-2.89 -0.93,-4.16C19.83,7.22 19.13,7.1 18.72,7.51zM15,7l-4.79,-4.79C10.07,2.07 9.89,2 9.71,2h0C9.32,2 9,2.32 9,2.71v6.88L5.12,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L8.59,12l-4.89,4.89c-0.39,0.39 -0.39,1.02 0,1.41h0c0.39,0.39 1.02,0.39 1.41,0L9,14.41v6.88C9,21.68 9.32,22 9.71,22h0c0.19,0 0.37,-0.07 0.5,-0.21L15,17c0.39,-0.39 0.39,-1.02 0,-1.42L11.41,12L15,8.42C15.39,8.03 15.39,7.39 15,7zM11,5.83l1.88,1.88L11,9.59V5.83zM12.88,16.29L11,18.17v-3.76L12.88,16.29z"/>
+ android:pathData="M15.98,10.28l-1.38,1.38c-0.2,0.2 -0.2,0.51 0,0.71l1.38,1.38c0.28,0.28 0.75,0.15 0.85,-0.23 0.11,-0.5 0.17,-1 0.17,-1.52 0,-0.51 -0.06,-1.01 -0.18,-1.48 -0.09,-0.38 -0.56,-0.52 -0.84,-0.24zM20.1,7.78c-0.25,-0.55 -0.98,-0.67 -1.4,-0.24 -0.26,0.26 -0.31,0.64 -0.17,0.98 0.46,1.07 0.72,2.24 0.72,3.47 0,1.24 -0.26,2.42 -0.73,3.49 -0.14,0.32 -0.09,0.69 0.16,0.94 0.41,0.41 1.1,0.29 1.35,-0.23 0.63,-1.3 0.98,-2.76 0.98,-4.3 -0.01,-1.45 -0.33,-2.85 -0.91,-4.11zM11.39,12l3.59,-3.58c0.39,-0.39 0.39,-1.02 0,-1.42l-4.29,-4.29c-0.63,-0.63 -1.71,-0.18 -1.71,0.71L8.98,9.6L5.09,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L8.57,12l-4.89,4.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l3.89,-3.89v6.18c0,0.89 1.08,1.34 1.71,0.71l4.3,-4.3c0.39,-0.39 0.39,-1.02 0,-1.42L11.39,12zM10.98,5.83l1.88,1.88 -1.88,1.88L10.98,5.83zM10.98,18.17v-3.76l1.88,1.88 -1.88,1.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_connected.xml b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_connected.xml
index e1bb2ff..ff3e9b5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_connected.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_connected.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,13c0.55,-0.55 0.55,-1.44 0,-1.99V11c-0.55,-0.55 -1.45,-0.55 -2,0l0,0c-0.55,0.55 -0.55,1.45 0,2l0,0C4.55,13.55 5.45,13.55 6,13L6,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,11L20,11c-0.56,-0.56 -1.45,-0.56 -2,-0.01V11c-0.55,0.55 -0.55,1.44 0,1.99V13c0.55,0.55 1.44,0.55 1.99,0H20C20.55,12.45 20.55,11.55 20,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,7l-4.29,-4.29C12.08,2.08 11,2.52 11,3.41v6.18L7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0s-0.39,1.02 0,1.41L10.59,12L5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41s1.02,0.39 1.41,0L11,14.41v6.18c0,0.89 1.08,1.34 1.71,0.71L17,17c0.39,-0.39 0.39,-1.02 0,-1.42L13.41,12L17,8.42C17.39,8.03 17.39,7.39 17,7zM14.88,16.29L13,18.17v-3.76L14.88,16.29zM13,9.59V5.83l1.88,1.88L13,9.59z"/>
+ android:pathData="M6,13c0.55,-0.55 0.55,-1.44 0,-1.99L6,11c-0.55,-0.55 -1.45,-0.55 -2,0s-0.55,1.45 0,2 1.45,0.55 2,0zM20,11c-0.56,-0.56 -1.45,-0.56 -2,-0.01L18,11c-0.55,0.55 -0.55,1.44 0,1.99L18,13c0.55,0.55 1.44,0.55 1.99,0L20,13c0.55,-0.55 0.55,-1.45 0,-2zM17,7l-4.29,-4.29c-0.63,-0.63 -1.71,-0.19 -1.71,0.7v6.18L7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L11,14.41v6.18c0,0.89 1.08,1.34 1.71,0.71L17,17c0.39,-0.39 0.39,-1.02 0,-1.42L13.41,12 17,8.42c0.39,-0.39 0.39,-1.03 0,-1.42zM14.88,16.29L13,18.17v-3.76l1.88,1.88zM13,9.59L13,5.83l1.88,1.88L13,9.59z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_disabled.xml
index db92ab0..d23b696 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_disabled.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,8.42c0.39,-0.39 0.39,-1.03 0,-1.42l-4.29,-4.29C12.08,2.08 11,2.52 11,3.41v4.76l3.12,3.12L17,8.42zM13,5.83l1.88,1.88L13,9.59V5.83z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.49,20.49L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l7.78,7.78L5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41s1.02,0.39 1.41,0L11,14.41v6.18c0,0.89 1.08,1.34 1.71,0.71l2.88,-2.88l3.48,3.48c0.39,0.39 1.02,0.39 1.41,0C20.88,21.51 20.88,20.88 20.49,20.49zM13,18.17v-2.34L14.17,17L13,18.17z"/>
+ android:pathData="M19.29,17.89L6.11,4.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L11,14.41v6.18c0,0.89 1.08,1.34 1.71,0.71l3.59,-3.59 1.59,1.59c0.39,0.39 1.02,0.39 1.41,0 0.38,-0.39 0.38,-1.03 -0.01,-1.41zM13,18.17v-3.76l1.88,1.88L13,18.17zM13,5.83l1.88,1.88 -1.47,1.47 1.41,1.41L17,8.42c0.39,-0.39 0.39,-1.02 0,-1.42l-4.29,-4.29c-0.63,-0.63 -1.71,-0.19 -1.71,0.7v3.36l2,2L13,5.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_searching.xml b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_searching.xml
index c2e01f5..bec11dc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_searching.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bluetooth_searching.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.58,12.36l1.38,1.38c0.28,0.28 0.75,0.14 0.84,-0.24c0.12,-0.48 0.18,-0.99 0.18,-1.5c0,-0.51 -0.06,-1.01 -0.18,-1.48c-0.09,-0.38 -0.56,-0.52 -0.84,-0.24l-1.39,1.38C14.39,11.85 14.39,12.17 14.58,12.36zM18.72,7.51l-0.05,0.05c-0.25,0.25 -0.3,0.62 -0.16,0.94c0.47,1.07 0.73,2.25 0.73,3.49c0,1.24 -0.26,2.42 -0.73,3.49c-0.14,0.32 -0.09,0.69 0.16,0.94l0,0c0.41,0.41 1.1,0.29 1.35,-0.23c0.63,-1.3 0.98,-2.76 0.98,-4.3c-0.01,-1.48 -0.34,-2.89 -0.93,-4.16C19.83,7.22 19.13,7.1 18.72,7.51zM15,7l-4.79,-4.79C10.07,2.07 9.89,2 9.71,2h0C9.32,2 9,2.32 9,2.71v6.88L5.12,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L8.59,12l-4.89,4.89c-0.39,0.39 -0.39,1.02 0,1.41h0c0.39,0.39 1.02,0.39 1.41,0L9,14.41v6.88C9,21.68 9.32,22 9.71,22h0c0.19,0 0.37,-0.07 0.5,-0.21L15,17c0.39,-0.39 0.39,-1.02 0,-1.42L11.41,12L15,8.42C15.39,8.03 15.39,7.39 15,7zM11,5.83l1.88,1.88L11,9.59V5.83zM12.88,16.29L11,18.17v-3.76L12.88,16.29z"/>
+ android:pathData="M15.98,10.28l-1.38,1.38c-0.2,0.2 -0.2,0.51 0,0.71l1.38,1.38c0.28,0.28 0.75,0.15 0.85,-0.23 0.11,-0.5 0.17,-1 0.17,-1.52 0,-0.51 -0.06,-1.01 -0.18,-1.48 -0.09,-0.38 -0.56,-0.52 -0.84,-0.24zM20.1,7.78c-0.25,-0.55 -0.98,-0.67 -1.4,-0.24 -0.26,0.26 -0.31,0.64 -0.17,0.98 0.46,1.07 0.72,2.24 0.72,3.47 0,1.24 -0.26,2.42 -0.73,3.49 -0.14,0.32 -0.09,0.69 0.16,0.94 0.41,0.41 1.1,0.29 1.35,-0.23 0.63,-1.3 0.98,-2.76 0.98,-4.3 -0.01,-1.45 -0.33,-2.85 -0.91,-4.11zM11.41,12L15,8.42c0.39,-0.39 0.39,-1.02 0,-1.42l-4.29,-4.29c-0.63,-0.63 -1.71,-0.19 -1.71,0.7v6.18L5.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L8.59,12 3.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L9,14.41v6.18c0,0.89 1.08,1.34 1.71,0.71L15,17c0.39,-0.39 0.39,-1.02 0,-1.42L11.41,12zM11,5.83l1.88,1.88L11,9.59L11,5.83zM11,18.17v-3.76l1.88,1.88L11,18.17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/blur_circular.xml b/compose/material/material/icons/generator/raw-icons/rounded/blur_circular.xml
index d084cad..4945404 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/blur_circular.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/blur_circular.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S10.55,9 10,9zM10,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S10.55,13 10,13zM7,9.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S7.28,9.5 7,9.5zM10,16.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S10.28,16.5 10,16.5zM7,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S7.28,13.5 7,13.5zM10,7.5c0.28,0 0.5,-0.22 0.5,-0.5S10.28,6.5 10,6.5S9.5,6.72 9.5,7S9.72,7.5 10,7.5zM14,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S14.55,9 14,9zM14,7.5c0.28,0 0.5,-0.22 0.5,-0.5S14.28,6.5 14,6.5S13.5,6.72 13.5,7S13.72,7.5 14,7.5zM17,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S17.28,13.5 17,13.5zM17,9.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S17.28,9.5 17,9.5zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20zM14,16.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S14.28,16.5 14,16.5zM14,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S14.55,13 14,13z"/>
+ android:pathData="M10,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM10,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM7,9.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM10,16.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM7,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM10,7.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM14,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM14,7.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM17,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM17,9.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM14,16.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM14,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/blur_linear.xml b/compose/material/material/icons/generator/raw-icons/rounded/blur_linear.xml
index e53d7a1..7081431 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/blur_linear.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/blur_linear.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,17.5c0.83,0 1.5,-0.67 1.5,-1.5S5.83,14.5 5,14.5S3.5,15.17 3.5,16S4.17,17.5 5,17.5zM9,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S8.45,13 9,13zM9,9c0.55,0 1,-0.45 1,-1S9.55,7 9,7S8,7.45 8,8S8.45,9 9,9zM4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM5,9.5c0.83,0 1.5,-0.67 1.5,-1.5S5.83,6.5 5,6.5S3.5,7.17 3.5,8S4.17,9.5 5,9.5zM5,13.5c0.83,0 1.5,-0.67 1.5,-1.5S5.83,10.5 5,10.5S3.5,11.17 3.5,12S4.17,13.5 5,13.5zM9,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1C8,16.55 8.45,17 9,17zM17,16.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5C16.5,16.28 16.72,16.5 17,16.5zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4zM17,8.5c0.28,0 0.5,-0.22 0.5,-0.5S17.28,7.5 17,7.5S16.5,7.72 16.5,8C16.5,8.28 16.72,8.5 17,8.5zM17,12.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5S16.72,12.5 17,12.5zM13,9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S12.45,9 13,9zM13,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S12.45,13 13,13zM13,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1C12,16.55 12.45,17 13,17z"/>
+ android:pathData="M5,17.5c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5 -1.5,0.67 -1.5,1.5 0.67,1.5 1.5,1.5zM9,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM9,9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM5,9.5c0.83,0 1.5,-0.67 1.5,-1.5S5.83,6.5 5,6.5 3.5,7.17 3.5,8 4.17,9.5 5,9.5zM5,13.5c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5 -1.5,0.67 -1.5,1.5 0.67,1.5 1.5,1.5zM9,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM17,16.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1zM17,8.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM17,12.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM13,9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM13,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM13,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/blur_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/blur_off.xml
index dcb9fe9..96d3bc4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/blur_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/blur_off.xml
@@ -6,5 +6,41 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,17c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1s1,-0.45 1,-1C7,17.45 6.55,17 6,17zM18,11c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1C17,10.55 17.45,11 18,11zM14,7c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1C13,6.55 13.45,7 14,7zM6,13c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1s1,-0.45 1,-1C7,13.45 6.55,13 6,13zM14,3.5c0.28,0 0.5,-0.22 0.5,-0.5c0,-0.28 -0.22,-0.5 -0.5,-0.5S13.5,2.72 13.5,3C13.5,3.28 13.72,3.5 14,3.5zM21,13.5c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5C21.5,13.72 21.28,13.5 21,13.5zM21,10.5c0.28,0 0.5,-0.22 0.5,-0.5c0,-0.28 -0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5C20.5,10.28 20.72,10.5 21,10.5zM3,9.5c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5C3.5,9.72 3.28,9.5 3,9.5zM3,13.5c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5C3.5,13.72 3.28,13.5 3,13.5zM18,7c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1C17,6.55 17.45,7 18,7zM14,20.5c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5C14.5,20.72 14.28,20.5 14,20.5zM10,17c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1s1,-0.45 1,-1C11,17.45 10.55,17 10,17zM10,20.5c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5C10.5,20.72 10.28,20.5 10,20.5zM17.78,14.96C17.86,14.97 17.92,15 18,15c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1c0,0.08 0.03,0.14 0.04,0.22L17.78,14.96zM9.78,6.96C9.86,6.97 9.92,7 10,7c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1S9,5.45 9,6c0,0.08 0.03,0.14 0.04,0.22L9.78,6.96zM15.5,10c0,-0.83 -0.67,-1.5 -1.5,-1.5c-0.73,0 -1.33,0.52 -1.47,1.2l1.77,1.77C14.98,11.33 15.5,10.73 15.5,10zM10,3.5c0.28,0 0.5,-0.22 0.5,-0.5c0,-0.28 -0.22,-0.5 -0.5,-0.5S9.5,2.72 9.5,3C9.5,3.28 9.72,3.5 10,3.5zM3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l4.11,4.11C6.14,9.03 6.08,9 6,9c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1s1,-0.45 1,-1c0,-0.08 -0.03,-0.14 -0.04,-0.22l2.75,2.75C9.02,12.67 8.5,13.27 8.5,14c0,0.83 0.67,1.5 1.5,1.5c0.73,0 1.33,-0.52 1.47,-1.2l2.75,2.75C14.14,17.03 14.08,17 14,17c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1s1,-0.45 1,-1c0,-0.08 -0.03,-0.14 -0.04,-0.22l4.11,4.11c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51z"/>
+ android:pathData="M14,6m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13.8,11.48l0.2,0.02c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5 -1.5,0.67 -1.5,1.5l0.02,0.2c0.09,0.67 0.61,1.19 1.28,1.28zM14,3.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM10,3.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18,10m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18,6m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,10.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10,6m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18,14m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6,18m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,20.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM21,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM3,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10,18m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,9.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM10,20.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6,14m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3.21,4.56c-0.39,0.39 -0.39,1.02 0,1.41l3.07,3.07L6,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1c0,-0.1 -0.03,-0.19 -0.06,-0.28l2.81,2.81c-0.71,0.11 -1.25,0.73 -1.25,1.47 0,0.83 0.67,1.5 1.5,1.5 0.74,0 1.36,-0.54 1.47,-1.25l2.81,2.81c-0.09,-0.03 -0.18,-0.06 -0.28,-0.06 -0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1c0,-0.1 -0.03,-0.19 -0.06,-0.28l3.08,3.07c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.42L4.62,4.56c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/blur_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/blur_on.xml
index cb8a385..121ad7d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/blur_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/blur_on.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S6.55,13 6,13zM6,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S6.55,17 6,17zM6,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S6.55,9 6,9zM3,9.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S3.28,9.5 3,9.5zM6,5C5.45,5 5,5.45 5,6s0.45,1 1,1s1,-0.45 1,-1S6.55,5 6,5zM21,10.5c0.28,0 0.5,-0.22 0.5,-0.5S21.28,9.5 21,9.5s-0.5,0.22 -0.5,0.5S20.72,10.5 21,10.5zM14,7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S13.45,7 14,7zM14,3.5c0.28,0 0.5,-0.22 0.5,-0.5S14.28,2.5 14,2.5S13.5,2.72 13.5,3S13.72,3.5 14,3.5zM3,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S3.28,13.5 3,13.5zM10,20.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S10.28,20.5 10,20.5zM10,3.5c0.28,0 0.5,-0.22 0.5,-0.5S10.28,2.5 10,2.5S9.5,2.72 9.5,3S9.72,3.5 10,3.5zM10,7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1S9,5.45 9,6S9.45,7 10,7zM10,12.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5S10.83,12.5 10,12.5zM18,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S18.55,13 18,13zM18,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S18.55,17 18,17zM18,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S18.55,9 18,9zM18,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S18.55,5 18,5zM21,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S21.28,13.5 21,13.5zM14,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S14.55,17 14,17zM14,20.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5S14.28,20.5 14,20.5zM10,8.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5S10.83,8.5 10,8.5zM10,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S10.55,17 10,17zM14,12.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5S14.83,12.5 14,12.5zM14,8.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5S14.83,8.5 14,8.5z"/>
+ android:pathData="M6,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM6,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM6,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM3,9.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM6,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM21,10.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM14,7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM14,3.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM3,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM10,20.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM10,3.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5 -0.5,0.22 -0.5,0.5 0.22,0.5 0.5,0.5zM10,7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM10,12.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM18,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM18,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM18,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM18,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM21,13.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM14,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM14,20.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5 0.5,-0.22 0.5,-0.5 -0.22,-0.5 -0.5,-0.5zM10,8.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM10,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1zM14,12.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM14,8.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/book.xml b/compose/material/material/icons/generator/raw-icons/rounded/book.xml
index a2787ee..4a4cbea 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/book.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/book.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2H6C4.9,2 4,2.9 4,4zM11,4h5v6.12c0,0.39 -0.42,0.63 -0.76,0.43L13.5,9.5l-1.74,1.05c-0.33,0.2 -0.76,-0.04 -0.76,-0.43V4z"/>
+ android:pathData="M18,2H6c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zM6,4h5v8l-2.5,-1.5L6,12V4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bookmark.xml b/compose/material/material/icons/generator/raw-icons/rounded/bookmark.xml
index b62cfba..3e5fea3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bookmark.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bookmark.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,3H7C5.9,3 5,3.9 5,5v14.48c0,0.72 0.73,1.2 1.39,0.92L12,18l5.61,2.4c0.66,0.28 1.39,-0.2 1.39,-0.92V5C19,3.9 18.1,3 17,3z"/>
+ android:pathData="M17,3H7c-1.1,0 -2,0.9 -2,2v16l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bookmarks.xml b/compose/material/material/icons/generator/raw-icons/rounded/bookmarks.xml
index f1f56b5..bcb76cd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bookmarks.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bookmarks.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,5H5C3.9,5 3,5.9 3,7v14.48c0,0.72 0.73,1.2 1.39,0.92L10,20l5.61,2.4c0.66,0.28 1.39,-0.2 1.39,-0.92V7C17,5.9 16.1,5 15,5zM20,20L20,20c0.55,0 1,-0.45 1,-1V3c0,-1.1 -0.9,-2 -2,-2H7C6.45,1 6,1.45 6,2v0c0,0.55 0.45,1 1,1h12v16C19,19.55 19.45,20 20,20z"/>
+ android:pathData="M19,18l2,1V3c0,-1.1 -0.9,-2 -2,-2H8.99C7.89,1 7,1.9 7,3h10c1.1,0 2,0.9 2,2v13zM15,5H5c-1.1,0 -2,0.9 -2,2v16l7,-3 7,3V7c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_all.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_all.xml
index 3e6718c..0130508 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_all.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_all.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2H5C3.9,3 3,3.9 3,5zM11,19H5v-6h6V19zM11,11H5V5h6V11zM19,19h-6v-6h6V19zM19,11h-6V5h6V11z"/>
+ android:pathData="M3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2L5,3c-1.1,0 -2,0.9 -2,2zM11,19L6,19c-0.55,0 -1,-0.45 -1,-1v-5h5c0.55,0 1,0.45 1,1v5zM10,11L5,11L5,6c0,-0.55 0.45,-1 1,-1h5v5c0,0.55 -0.45,1 -1,1zM18,19h-5v-5c0,-0.55 0.45,-1 1,-1h5v5c0,0.55 -0.45,1 -1,1zM19,11h-5c-0.55,0 -1,-0.45 -1,-1L13,5h5c0.55,0 1,0.45 1,1v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_bottom.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_bottom.xml
index 41a20c9..a2cc458 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_bottom.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_bottom.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,11H7v2h2V11zM13,15h-2v2h2V15zM9,3H7v2h2V3zM13,11h-2v2h2V11zM5,3H3v2h2V3zM13,7h-2v2h2V7zM17,11h-2v2h2V11zM13,3h-2v2h2V3zM17,3h-2v2h2V3zM19,13h2v-2h-2V13zM19,17h2v-2h-2V17zM5,7H3v2h2V7zM19,3v2h2V3H19zM19,9h2V7h-2V9zM5,11H3v2h2V11zM4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM5,15H3v2h2V15z"/>
+ android:pathData="M9,11L7,11v2h2v-2zM13,15h-2v2h2v-2zM9,3L7,3v2h2L9,3zM13,11h-2v2h2v-2zM5,3L3,3v2h2L5,3zM13,7h-2v2h2L13,7zM17,11h-2v2h2v-2zM13,3h-2v2h2L13,3zM17,3h-2v2h2L17,3zM19,13h2v-2h-2v2zM19,17h2v-2h-2v2zM5,7L3,7v2h2L5,7zM19,3v2h2L21,3h-2zM19,9h2L21,7h-2v2zM5,11L3,11v2h2v-2zM4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM5,15L3,15v2h2v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_clear.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_clear.xml
index 6b90387..0c48776 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_clear.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_clear.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,5h2V3H7V5zM7,13h2v-2H7V13zM7,21h2v-2H7V21zM11,17h2v-2h-2V17zM11,21h2v-2h-2V21zM3,21h2v-2H3V21zM3,17h2v-2H3V17zM3,13h2v-2H3V13zM3,9h2V7H3V9zM3,5h2V3H3V5zM11,13h2v-2h-2V13zM19,17h2v-2h-2V17zM19,13h2v-2h-2V13zM19,21h2v-2h-2V21zM19,9h2V7h-2V9zM11,9h2V7h-2V9zM19,3v2h2V3H19zM11,5h2V3h-2V5zM15,21h2v-2h-2V21zM15,13h2v-2h-2V13zM15,5h2V3h-2V5z"/>
+ android:pathData="M7,5h2L9,3L7,3v2zM7,13h2v-2L7,11v2zM7,21h2v-2L7,19v2zM11,17h2v-2h-2v2zM11,21h2v-2h-2v2zM3,21h2v-2L3,19v2zM3,17h2v-2L3,15v2zM3,13h2v-2L3,11v2zM3,9h2L5,7L3,7v2zM3,5h2L5,3L3,3v2zM11,13h2v-2h-2v2zM19,17h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21h2v-2h-2v2zM19,9h2L21,7h-2v2zM11,9h2L13,7h-2v2zM19,3v2h2L21,3h-2zM11,5h2L13,3h-2v2zM15,21h2v-2h-2v2zM15,13h2v-2h-2v2zM15,5h2L17,3h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_horizontal.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_horizontal.xml
index ca104d8..258b7dd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_horizontal.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_horizontal.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,21h2v-2H3V21zM5,7H3v2h2V7zM3,17h2v-2H3V17zM7,21h2v-2H7V21zM5,3H3v2h2V3zM9,3H7v2h2V3zM17,3h-2v2h2V3zM13,7h-2v2h2V7zM13,3h-2v2h2V3zM19,17h2v-2h-2V17zM11,21h2v-2h-2V21zM4,13h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13zM19,3v2h2V3H19zM19,9h2V7h-2V9zM11,17h2v-2h-2V17zM15,21h2v-2h-2V21zM19,21h2v-2h-2V21z"/>
+ android:pathData="M3,21h2v-2L3,19v2zM5,7L3,7v2h2L5,7zM3,17h2v-2L3,15v2zM7,21h2v-2L7,19v2zM5,3L3,3v2h2L5,3zM9,3L7,3v2h2L9,3zM17,3h-2v2h2L17,3zM13,7h-2v2h2L13,7zM13,3h-2v2h2L13,3zM19,17h2v-2h-2v2zM11,21h2v-2h-2v2zM4,13h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM19,3v2h2L21,3h-2zM19,9h2L21,7h-2v2zM11,17h2v-2h-2v2zM15,21h2v-2h-2v2zM19,21h2v-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_inner.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_inner.xml
index 520c562..83a7bec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_inner.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_inner.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,21h2v-2H3V21zM7,21h2v-2H7V21zM5,7H3v2h2V7zM3,17h2v-2H3V17zM9,3H7v2h2V3zM5,3H3v2h2V3zM17,3h-2v2h2V3zM19,9h2V7h-2V9zM19,3v2h2V3H19zM15,21h2v-2h-2V21zM12,3L12,3c-0.55,0 -1,0.45 -1,1v7H4c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h7v7c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-7h7c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-7V4C13,3.45 12.55,3 12,3zM19,21h2v-2h-2V21zM19,17h2v-2h-2V17z"/>
+ android:pathData="M3,21h2v-2L3,19v2zM7,21h2v-2L7,19v2zM5,7L3,7v2h2L5,7zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM5,3L3,3v2h2L5,3zM17,3h-2v2h2L17,3zM19,9h2L21,7h-2v2zM19,3v2h2L21,3h-2zM15,21h2v-2h-2v2zM12,3c-0.55,0 -1,0.45 -1,1v7L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h7v7c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-7h7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-7L13,4c0,-0.55 -0.45,-1 -1,-1zM19,21h2v-2h-2v2zM19,17h2v-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_left.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_left.xml
index bad276d..29711c9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_left.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_left.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,21h2v-2h-2V21zM11,17h2v-2h-2V17zM11,5h2V3h-2V5zM11,9h2V7h-2V9zM11,13h2v-2h-2V13zM7,21h2v-2H7V21zM7,5h2V3H7V5zM7,13h2v-2H7V13zM4,21L4,21c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1l0,0C3.45,3 3,3.45 3,4v16C3,20.55 3.45,21 4,21zM19,9h2V7h-2V9zM15,21h2v-2h-2V21zM19,17h2v-2h-2V17zM19,3v2h2V3H19zM19,13h2v-2h-2V13zM19,21h2v-2h-2V21zM15,13h2v-2h-2V13zM15,5h2V3h-2V5z"/>
+ android:pathData="M11,21h2v-2h-2v2zM11,17h2v-2h-2v2zM11,5h2L13,3h-2v2zM11,9h2L13,7h-2v2zM11,13h2v-2h-2v2zM7,21h2v-2L7,19v2zM7,5h2L9,3L7,3v2zM7,13h2v-2L7,11v2zM4,21c0.55,0 1,-0.45 1,-1L5,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v16c0,0.55 0.45,1 1,1zM19,9h2L21,7h-2v2zM15,21h2v-2h-2v2zM19,17h2v-2h-2v2zM19,3v2h2L21,3h-2zM19,13h2v-2h-2v2zM19,21h2v-2h-2v2zM15,13h2v-2h-2v2zM15,5h2L17,3h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_outer.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_outer.xml
index 6cad66e..e5d6687 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_outer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_outer.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,7h-2v2h2V7zM13,11h-2v2h2V11zM17,11h-2v2h2V11zM3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2H5C3.9,3 3,3.9 3,5zM19,19H5V5h14V19zM13,15h-2v2h2V15zM9,11H7v2h2V11z"/>
+ android:pathData="M13,7h-2v2h2L13,7zM13,11h-2v2h2v-2zM17,11h-2v2h2v-2zM3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2L5,3c-1.1,0 -2,0.9 -2,2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM13,15h-2v2h2v-2zM9,11L7,11v2h2v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_right.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_right.xml
index eb7c0ec..586ed28 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_right.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_right.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,21h2v-2H7V21zM3,5h2V3H3V5zM7,5h2V3H7V5zM7,13h2v-2H7V13zM3,21h2v-2H3V21zM11,21h2v-2h-2V21zM3,13h2v-2H3V13zM3,17h2v-2H3V17zM3,9h2V7H3V9zM11,17h2v-2h-2V17zM15,13h2v-2h-2V13zM19,4v16c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1l0,0C19.45,3 19,3.45 19,4zM15,21h2v-2h-2V21zM15,5h2V3h-2V5zM11,13h2v-2h-2V13zM11,5h2V3h-2V5zM11,9h2V7h-2V9z"/>
+ android:pathData="M7,21h2v-2L7,19v2zM3,5h2L5,3L3,3v2zM7,5h2L9,3L7,3v2zM7,13h2v-2L7,11v2zM3,21h2v-2L3,19v2zM11,21h2v-2h-2v2zM3,13h2v-2L3,11v2zM3,17h2v-2L3,15v2zM3,9h2L5,7L3,7v2zM11,17h2v-2h-2v2zM15,13h2v-2h-2v2zM19,4v16c0,0.55 0.45,1 1,1s1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM11,13h2v-2h-2v2zM11,5h2L13,3h-2v2zM11,9h2L13,7h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_style.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_style.xml
index 45b2435..40ef0d7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_style.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_style.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,21h2v-2h-2V21zM19,21h2v-2h-2V21zM7,21h2v-2H7V21zM11,21h2v-2h-2V21zM19,17h2v-2h-2V17zM19,13h2v-2h-2V13zM3,5v15c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5h15c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5zM19,9h2V7h-2V9z"/>
+ android:pathData="M15,21h2v-2h-2v2zM19,21h2v-2h-2v2zM7,21h2v-2L7,19v2zM11,21h2v-2h-2v2zM19,17h2v-2h-2v2zM19,13h2v-2h-2v2zM3,5v15c0,0.55 0.45,1 1,1s1,-0.45 1,-1L5,6c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,3c-1.1,0 -2,0.9 -2,2zM19,9h2L21,7h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_top.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_top.xml
index 6916f4d..90159c0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_top.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_top.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,21h2v-2H7V21zM7,13h2v-2H7V13zM11,13h2v-2h-2V13zM11,21h2v-2h-2V21zM3,17h2v-2H3V17zM3,21h2v-2H3V21zM3,13h2v-2H3V13zM3,9h2V7H3V9zM11,17h2v-2h-2V17zM19,9h2V7h-2V9zM19,13h2v-2h-2V13zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4zM19,17h2v-2h-2V17zM15,21h2v-2h-2V21zM11,9h2V7h-2V9zM19,21h2v-2h-2V21zM15,13h2v-2h-2V13z"/>
+ android:pathData="M7,21h2v-2L7,19v2zM7,13h2v-2L7,11v2zM11,13h2v-2h-2v2zM11,21h2v-2h-2v2zM3,17h2v-2L3,15v2zM3,21h2v-2L3,19v2zM3,13h2v-2L3,11v2zM3,9h2L5,7L3,7v2zM11,17h2v-2h-2v2zM19,9h2L21,7h-2v2zM19,13h2v-2h-2v2zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM11,9h2L13,7h-2v2zM19,21h2v-2h-2v2zM15,13h2v-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/border_vertical.xml b/compose/material/material/icons/generator/raw-icons/rounded/border_vertical.xml
index adf30b6..7760718 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/border_vertical.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/border_vertical.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,9h2V7H3V9zM3,5h2V3H3V5zM7,21h2v-2H7V21zM7,13h2v-2H7V13zM3,13h2v-2H3V13zM3,21h2v-2H3V21zM3,17h2v-2H3V17zM7,5h2V3H7V5zM19,17h2v-2h-2V17zM12,21L12,21c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v16C11,20.55 11.45,21 12,21zM19,21h2v-2h-2V21zM19,13h2v-2h-2V13zM19,3v2h2V3H19zM19,9h2V7h-2V9zM15,5h2V3h-2V5zM15,21h2v-2h-2V21zM15,13h2v-2h-2V13z"/>
+ android:pathData="M3,9h2L5,7L3,7v2zM3,5h2L5,3L3,3v2zM7,21h2v-2L7,19v2zM7,13h2v-2L7,11v2zM3,13h2v-2L3,11v2zM3,21h2v-2L3,19v2zM3,17h2v-2L3,15v2zM7,5h2L9,3L7,3v2zM19,17h2v-2h-2v2zM12,21c0.55,0 1,-0.45 1,-1L13,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v16c0,0.55 0.45,1 1,1zM19,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,3v2h2L21,3h-2zM19,9h2L21,7h-2v2zM15,5h2L17,3h-2v2zM15,21h2v-2h-2v2zM15,13h2v-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/branding_watermark.xml b/compose/material/material/icons/generator/raw-icons/rounded/branding_watermark.xml
index 732cf0f..294dc6b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/branding_watermark.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/branding_watermark.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM19,16c0,0.55 -0.45,1 -1,1h-7c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,0.45 1,1V16z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM20,19h-7c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_2.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_2.xml
index ce56b3d2..e12ab94 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_2.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_2.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.93,2.3C9.89,1.8 7.91,1.95 6.16,2.58C5.44,2.84 5.25,3.8 5.85,4.29C8.08,6.12 9.5,8.89 9.5,12c0,3.11 -1.42,5.88 -3.65,7.71c-0.59,0.49 -0.42,1.45 0.31,1.7C7.2,21.79 8.33,22 9.5,22c6.05,0 10.85,-5.38 9.87,-11.6C18.76,6.48 15.78,3.24 11.93,2.3z"/>
+ android:pathData="M12.43,2.3c-2.38,-0.59 -4.68,-0.27 -6.63,0.64 -0.35,0.16 -0.41,0.64 -0.1,0.86C8.3,5.6 10,8.6 10,12c0,3.4 -1.7,6.4 -4.3,8.2 -0.32,0.22 -0.26,0.7 0.09,0.86 1.28,0.6 2.71,0.94 4.21,0.94 6.05,0 10.85,-5.38 9.87,-11.6 -0.61,-3.92 -3.59,-7.16 -7.44,-8.1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_5.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_5.xml
index 68f78f2..fe31e91 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_5.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_5.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15.31l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6C4.9,4 4,4.9 4,6v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2V15.31zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6s6,2.69 6,6S15.31,18 12,18z"/>
+ android:pathData="M20,15.31l2.6,-2.6c0.39,-0.39 0.39,-1.02 0,-1.41L20,8.69V5c0,-0.55 -0.45,-1 -1,-1h-3.69l-2.6,-2.6c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.69,4H5c-0.55,0 -1,0.45 -1,1v3.69l-2.6,2.6c-0.39,0.39 -0.39,1.02 0,1.41L4,15.3V19c0,0.55 0.45,1 1,1h3.69l2.6,2.6c0.39,0.39 1.02,0.39 1.41,0l2.6,-2.6H19c0.55,0 1,-0.45 1,-1v-3.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_6.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_6.xml
index c329828..bb8cf50 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_6.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_6.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15.31l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6C4.9,4 4,4.9 4,6v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2V15.31zM12,18V6c3.31,0.01 6,2.69 6,6S15.31,18 12,18z"/>
+ android:pathData="M20,15.31l2.6,-2.6c0.39,-0.39 0.39,-1.02 0,-1.41L20,8.69L20,5c0,-0.55 -0.45,-1 -1,-1h-3.69l-2.6,-2.6c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.69,4L5,4c-0.55,0 -1,0.45 -1,1v3.69l-2.6,2.6c-0.39,0.39 -0.39,1.02 0,1.41L4,15.3L4,19c0,0.55 0.45,1 1,1h3.69l2.6,2.6c0.39,0.39 1.02,0.39 1.41,0l2.6,-2.6L19,20c0.55,0 1,-0.45 1,-1v-3.69zM12,16.9L12,7.1c0,-0.61 0.55,-1.11 1.15,-0.99C15.91,6.65 18,9.08 18,12s-2.09,5.35 -4.85,5.89c-0.6,0.12 -1.15,-0.38 -1.15,-0.99z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_7.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_7.xml
index fc35e01..93bb4ef 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_7.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_7.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6C4.9,4 4,4.9 4,6v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2v-2.69l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6s6,2.69 6,6S15.31,18 12,18zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S14.21,8 12,8z"/>
+ android:pathData="M20,8.69L20,5c0,-0.55 -0.45,-1 -1,-1h-3.69l-2.6,-2.6c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.69,4L5,4c-0.55,0 -1,0.45 -1,1v3.69l-2.6,2.6c-0.39,0.39 -0.39,1.02 0,1.41L4,15.3L4,19c0,0.55 0.45,1 1,1h3.69l2.6,2.6c0.39,0.39 1.02,0.39 1.41,0l2.6,-2.6L19,20c0.55,0 1,-0.45 1,-1v-3.69l2.6,-2.6c0.39,-0.39 0.39,-1.02 0,-1.41L20,8.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_auto.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_auto.xml
index b314a89..af59282 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_auto.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_auto.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.04,8.67l-0.08,0l-1.3,3.72l2.68,0z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.9,10.59L20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6C4.9,4 4,4.9 4,6v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2v-2.69l1.9,-1.9C22.68,12.63 22.68,11.37 21.9,10.59zM15.14,16c-0.31,0 -0.58,-0.19 -0.68,-0.48l-0.64,-1.82h-3.63l-0.65,1.82C9.44,15.81 9.17,16 8.86,16h0C8.35,16 8,15.49 8.18,15.02l2.73,-7.27C11.08,7.3 11.52,7 12,7s0.92,0.3 1.09,0.75l2.73,7.27C16,15.49 15.65,16 15.14,16z"/>
+ android:pathData="M10.85,12.65h2.3L12,9l-1.15,3.65zM20,8.69L20,6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4L6,4c-1.1,0 -2,0.9 -2,2v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9L4,18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9L18,20c1.1,0 2,-0.9 2,-2v-2.69l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69zM14.09,15.4L13.6,14h-3.2l-0.49,1.4c-0.13,0.36 -0.46,0.6 -0.84,0.6 -0.62,0 -1.05,-0.61 -0.84,-1.19l2.44,-6.86c0.2,-0.57 0.73,-0.95 1.33,-0.95 0.6,0 1.13,0.38 1.34,0.94l2.44,6.86c0.21,0.58 -0.22,1.19 -0.84,1.19 -0.39,0.01 -0.72,-0.23 -0.85,-0.59z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_high.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_high.xml
index fc35e01..00d4350 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_high.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_high.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6C4.9,4 4,4.9 4,6v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2v-2.69l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6s6,2.69 6,6S15.31,18 12,18zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S14.21,8 12,8z"/>
+ android:pathData="M20,8.69L20,6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4L6,4c-1.1,0 -2,0.9 -2,2v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9L4,18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9L18,20c1.1,0 2,-0.9 2,-2v-2.69l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_low.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_low.xml
index 68f78f2..1c1ebb0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_low.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_low.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15.31l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6C4.9,4 4,4.9 4,6v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2V15.31zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6s6,2.69 6,6S15.31,18 12,18z"/>
+ android:pathData="M20,15.31l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6c-1.1,0 -2,0.9 -2,2v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2v-2.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brightness_medium.xml b/compose/material/material/icons/generator/raw-icons/rounded/brightness_medium.xml
index c329828..bc63ef1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brightness_medium.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brightness_medium.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15.31l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69V6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4H6C4.9,4 4,4.9 4,6v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9V18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9H18c1.1,0 2,-0.9 2,-2V15.31zM12,18V6c3.31,0.01 6,2.69 6,6S15.31,18 12,18z"/>
+ android:pathData="M20,15.31l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L20,8.69L20,6c0,-1.1 -0.9,-2 -2,-2h-2.69l-1.9,-1.9c-0.78,-0.78 -2.05,-0.78 -2.83,0L8.69,4L6,4c-1.1,0 -2,0.9 -2,2v2.69l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l1.9,1.9L4,18c0,1.1 0.9,2 2,2h2.69l1.9,1.9c0.78,0.78 2.05,0.78 2.83,0l1.9,-1.9L18,20c1.1,0 2,-0.9 2,-2v-2.69zM12,16.9L12,7.1c0,-0.61 0.55,-1.11 1.15,-0.99C15.91,6.65 18,9.08 18,12s-2.09,5.35 -4.85,5.89c-0.6,0.12 -1.15,-0.38 -1.15,-0.99z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/broken_image.xml b/compose/material/material/icons/generator/raw-icons/rounded/broken_image.xml
index 7373416..e4c8ed4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/broken_image.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/broken_image.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,5v6.59l-2.29,-2.3c-0.39,-0.39 -1.03,-0.39 -1.42,0L14,12.59L10.71,9.3c-0.39,-0.39 -1.02,-0.39 -1.41,0L6,12.59L3,9.58V5c0,-1.1 0.9,-2 2,-2h14C20.1,3 21,3.9 21,5zM18,11.42l3,3.01V19c0,1.1 -0.9,2 -2,2H5c-1.1,0 -2,-0.9 -2,-2v-6.58l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.3l3.29,3.29c0.39,0.39 1.02,0.39 1.41,0L18,11.42z"/>
+ android:pathData="M21,5v6.59l-2.29,-2.3c-0.39,-0.39 -1.03,-0.39 -1.42,0L14,12.59 10.71,9.3c-0.39,-0.39 -1.02,-0.39 -1.41,0L6,12.59 3,9.58L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.3 3.29,3.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.28z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/browser_updated.xml b/compose/material/material/icons/generator/raw-icons/rounded/browser_updated.xml
new file mode 100644
index 0000000..a64cc8a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/browser_updated.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,3c0.55,0 1,0.45 1,1v6h1.59c0.89,0 1.34,1.08 0.71,1.71l-2.59,2.59c-0.39,0.39 -1.02,0.39 -1.41,0l-2.59,-2.59C11.08,11.08 11.52,10 12.41,10H14V4C14,3.45 14.45,3 15,3zM6,19.59C6,20.37 6.63,21 7.41,21h9.17c0.78,0 1.41,-0.63 1.41,-1.41c0,-0.72 -0.44,-1.03 -1,-1.59h3c1.1,0 2,-0.9 2,-2v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2H4V5l7,0c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1L4,3C2.9,3 2,3.9 2,5v11c0,1.1 0.9,2 2,2h3C6.45,18.55 6,18.87 6,19.59z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/brush.xml b/compose/material/material/icons/generator/raw-icons/rounded/brush.xml
index 8bbf0e8..4f14c93 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/brush.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/brush.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,14c-1.66,0 -3,1.34 -3,3c0,1.31 -1.16,2 -2,2c0.92,1.22 2.49,2 4,2c2.21,0 4,-1.79 4,-4C10,15.34 8.66,14 7,14z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.71,4.63l-1.34,-1.34c-0.39,-0.39 -1.02,-0.39 -1.41,0L9,12.25L11.75,15l8.96,-8.96C21.1,5.65 21.1,5.02 20.71,4.63z"/>
+ android:pathData="M7,14c-1.66,0 -3,1.34 -3,3 0,1.31 -1.16,2 -2,2 0.92,1.22 2.49,2 4,2 2.21,0 4,-1.79 4,-4 0,-1.66 -1.34,-3 -3,-3zM20.71,4.63l-1.34,-1.34c-0.39,-0.39 -1.02,-0.39 -1.41,0L9,12.25 11.75,15l8.96,-8.96c0.39,-0.39 0.39,-1.02 0,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bubble_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/bubble_chart.xml
index 2982966..db1a432 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bubble_chart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bubble_chart.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.5,3C13.47,3 11,5.47 11,8.5s2.47,5.5 5.5,5.5c3.03,0 5.5,-2.47 5.5,-5.5S19.53,3 16.5,3zM7,10c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.21,10 7,10zM14.5,15c-1.65,0 -3,1.35 -3,3s1.35,3 3,3s3,-1.35 3,-3S16.15,15 14.5,15z"/>
+ android:pathData="M7.2,14.4m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.8,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.2,8.8m-4.8,0a4.8,4.8 0,1 1,9.6 0a4.8,4.8 0,1 1,-9.6 0"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/bug_report.xml b/compose/material/material/icons/generator/raw-icons/rounded/bug_report.xml
index e720d0c..c0ee001 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/bug_report.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/bug_report.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,8h-1.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96l0.93,-0.93c0.39,-0.39 0.39,-1.02 0,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.47,1.47c-0.56,-0.13 -1.58,-0.3 -2.83,0L9.11,3.7c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l0.92,0.93C7.88,6.55 7.26,7.22 6.81,8H5C4.45,8 4,8.45 4,9s0.45,1 1,1h1.09C5.98,10.73 6,10.87 6,12H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1c0,1.14 -0.02,1.27 0.09,2H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.09c0.11,-0.73 0.09,-0.87 0.09,-2h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1c0,-1.14 0.02,-1.27 -0.09,-2H19c0.55,0 1,-0.45 1,-1S19.55,8 19,8zM13,16h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1S13.55,16 13,16zM13,12h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1S13.55,12 13,12z"/>
+ android:pathData="M19,8h-1.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96l0.93,-0.93c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0l-1.47,1.47C12.96,5.06 12.49,5 12,5s-0.96,0.06 -1.41,0.17L9.11,3.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l0.92,0.93C7.88,6.55 7.26,7.22 6.81,8L5,8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L5,12c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v1c0,0.34 0.04,0.67 0.09,1L5,16c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L19,18c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-1c0,-0.34 -0.04,-0.67 -0.09,-1L19,10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM13,16h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM13,12h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/build.xml b/compose/material/material/icons/generator/raw-icons/rounded/build.xml
index 5926b5f..ad63c65 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/build.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/build.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.65,16.11l-5.03,-5.03c0.42,-1.14 0.53,-2.43 0.13,-3.78c-0.61,-2.08 -2.34,-3.72 -4.45,-4.17C8.61,2.78 7.01,3.14 5.74,3.97l3.64,3.64L7.61,9.38L3.97,5.74C3.14,7.01 2.78,8.61 3.14,10.3c0.45,2.12 2.09,3.85 4.16,4.45c1.36,0.4 2.65,0.29 3.78,-0.13l5.03,5.03c0.98,0.98 2.56,0.98 3.54,0l0,0C20.62,18.67 20.62,17.09 19.65,16.11z"/>
+ android:pathData="M12.09,2.91C10.08,0.9 7.07,0.49 4.65,1.67L8.28,5.3c0.39,0.39 0.39,1.02 0,1.41L6.69,8.3c-0.39,0.4 -1.02,0.4 -1.41,0L1.65,4.67C0.48,7.1 0.89,10.09 2.9,12.1c1.86,1.86 4.58,2.35 6.89,1.48l7.96,7.96c1.03,1.03 2.69,1.03 3.71,0 1.03,-1.03 1.03,-2.69 0,-3.71L13.54,9.9c0.92,-2.34 0.44,-5.1 -1.45,-6.99z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/burst_mode.xml b/compose/material/material/icons/generator/raw-icons/rounded/burst_mode.xml
index 71a90bb..f5e45f1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/burst_mode.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/burst_mode.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,5C1.45,5 1,5.45 1,6v12c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6C3,5.45 2.55,5 2,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,5C5.45,5 5,5.45 5,6v12c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6C7,5.45 6.55,5 6,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,5H11C9.9,5 9,5.9 9,7v10c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V7C23,5.9 22.1,5 21,5zM12,15l2.12,-2.83L15.5,14l1.88,-2.5L20,15H12z"/>
+ android:pathData="M2,5c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L1,6c0,-0.55 0.45,-1 1,-1zM6,5c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1zM22,5L10,5c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1L23,6c0,-0.55 -0.45,-1 -1,-1zM11.64,16.19l1.47,-1.86c0.2,-0.25 0.57,-0.25 0.78,-0.01l1.4,1.68 2.1,-2.71c0.2,-0.26 0.59,-0.26 0.79,0l2.21,2.9c0.25,0.33 0.02,0.8 -0.4,0.8h-7.96c-0.41,0.01 -0.65,-0.47 -0.39,-0.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/business.xml b/compose/material/material/icons/generator/raw-icons/rounded/business.xml
index 4ccc403..e54a454 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/business.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/business.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7V4c0,-0.55 -0.45,-1 -1,-1H3C2.45,3 2,3.45 2,4v16c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1H12zM6,19H4v-2h2V19zM6,15H4v-2h2V15zM6,11H4V9h2V11zM6,7H4V5h2V7zM10,19H8v-2h2V19zM10,15H8v-2h2V15zM10,11H8V9h2V11zM10,7H8V5h2V7zM20,19h-8v-2h2v-2h-2v-2h2v-2h-2V9h8V19zM18,11h-2v2h2V11zM18,15h-2v2h2V15z"/>
+ android:pathData="M12,7L12,5c0,-1.1 -0.9,-2 -2,-2L4,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,9c0,-1.1 -0.9,-2 -2,-2h-8zM6,19L4,19v-2h2v2zM6,15L4,15v-2h2v2zM6,11L4,11L4,9h2v2zM6,7L4,7L4,5h2v2zM10,19L8,19v-2h2v2zM10,15L8,15v-2h2v2zM10,11L8,11L8,9h2v2zM10,7L8,7L8,5h2v2zM19,19h-7v-2h2v-2h-2v-2h2v-2h-2L12,9h7c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1zM18,11h-2v2h2v-2zM18,15h-2v2h2v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/business_center.xml b/compose/material/material/icons/generator/raw-icons/rounded/business_center.xml
index cca1aee..4f86944 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/business_center.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/business_center.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,17h-4c-0.55,0 -1,-0.45 -1,-1v-1H2.01L2,19c0,1.11 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2v-4h-7v1C15,16.55 14.55,17 14,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,6h-3V4c0,-1.1 -0.9,-2 -2,-2H9C7.9,2 7,2.9 7,4v2H4C2.9,6 2,6.9 2,8v5h7v-1c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1v1h7V8C22,6.9 21.1,6 20,6zM15,6H9V4h6V6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,13h2v2h-2z"/>
+ android:pathData="M13,16h-2c-0.55,0 -1,-0.45 -1,-1L3.01,15v4c0,1.1 0.9,2 2,2L19,21c1.1,0 2,-0.9 2,-2v-4h-7c0,0.55 -0.45,1 -1,1zM20,7h-4c0,-2.21 -1.79,-4 -4,-4S8,4.79 8,7L4,7c-1.1,0 -2,0.9 -2,2v3c0,1.11 0.89,2 2,2h6v-1c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1v1h6c1.1,0 2,-0.9 2,-2L22,9c0,-1.1 -0.9,-2 -2,-2zM10,7c0,-1.1 0.9,-2 2,-2s2,0.9 2,2L9.99,7 10,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cached.xml b/compose/material/material/icons/generator/raw-icons/rounded/cached.xml
index 028783e..f096a7b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cached.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cached.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.01,6.35C13.71,5.01 18,7.71 18,12h-1.79c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85H20c0,-5.76 -5.78,-9.39 -10.79,-7.48C8.57,4.76 8.42,5.6 8.9,6.07l0.08,0.08C9.25,6.42 9.65,6.48 10.01,6.35z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.98,17.64C10.14,19.01 6,16.17 6,12h1.79c0.45,0 0.67,-0.54 0.35,-0.85L5.35,8.35c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.79,2.79C1.54,11.46 1.76,12 2.21,12H4c0,5.76 5.78,9.39 10.79,7.48c0.63,-0.24 0.78,-1.08 0.3,-1.56l-0.07,-0.07C14.75,17.58 14.35,17.52 13.98,17.64z"/>
+ android:pathData="M18.65,8.35l-2.79,2.79c-0.32,0.32 -0.1,0.86 0.35,0.86H18c0,3.31 -2.69,6 -6,6 -0.79,0 -1.56,-0.15 -2.25,-0.44 -0.36,-0.15 -0.77,-0.04 -1.04,0.23 -0.51,0.51 -0.33,1.37 0.34,1.64 0.91,0.37 1.91,0.57 2.95,0.57 4.42,0 8,-3.58 8,-8h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79c-0.19,-0.2 -0.51,-0.2 -0.7,-0.01zM6,12c0,-3.31 2.69,-6 6,-6 0.79,0 1.56,0.15 2.25,0.44 0.36,0.15 0.77,0.04 1.04,-0.23 0.51,-0.51 0.33,-1.37 -0.34,-1.64C14.04,4.2 13.04,4 12,4c-4.42,0 -8,3.58 -8,8H2.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.36,-0.85H6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cake.xml b/compose/material/material/icons/generator/raw-icons/rounded/cake.xml
index e90745d..5ac9501 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cake.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cake.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,10c0,-1.1 -0.9,-2 -2,-2h-4V6.55c0.15,-0.09 0.29,-0.18 0.41,-0.31C13.8,5.85 14,5.32 14,4.82s-0.2,-1.02 -0.59,-1.41l-1.06,-1.06c-0.2,-0.2 -0.51,-0.2 -0.71,0l-1.06,1.06C10.2,3.8 10,4.32 10,4.82s0.2,1.03 0.59,1.42c0.13,0.13 0.27,0.22 0.41,0.31V8H7c-1.1,0 -2,0.9 -2,2v3h14V10zM19,15H5c-1.1,0 -2,0.9 -2,2v4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-4C21,15.9 20.1,15 19,15z"/>
+ android:pathData="M12.68,5.88c0.7,-0.24 1.22,-0.9 1.3,-1.64 0.05,-0.47 -0.05,-0.91 -0.28,-1.27L12.42,0.75c-0.19,-0.33 -0.67,-0.33 -0.87,0l-1.28,2.22c-0.17,0.3 -0.27,0.65 -0.27,1.03 0,1.32 1.3,2.35 2.68,1.88zM16.53,15.92l-1,-1 -1.08,1.07c-1.3,1.3 -3.58,1.31 -4.89,0l-1.07,-1.07 -1.09,1.07C6.75,16.64 5.88,17 4.96,17c-0.73,0 -1.4,-0.23 -1.96,-0.61L3,20c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-3.61c-0.75,0.51 -1.71,0.75 -2.74,0.52 -0.66,-0.14 -1.25,-0.51 -1.73,-0.99zM18,9h-5L13,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L6,9c-1.66,0 -3,1.34 -3,3v1.46c0,0.85 0.5,1.67 1.31,1.94 0.73,0.24 1.52,0.06 2.03,-0.46l2.14,-2.13 2.13,2.13c0.76,0.76 2.01,0.76 2.77,0l2.14,-2.13 2.13,2.13c0.43,0.43 1.03,0.63 1.65,0.55 0.99,-0.13 1.69,-1.06 1.69,-2.06v-1.42C21,10.34 19.66,9 18,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/calculate.xml b/compose/material/material/icons/generator/raw-icons/rounded/calculate.xml
index 98a8aa0..8165aa8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/calculate.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/calculate.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM13.56,6.53L13.56,6.53c0.29,-0.29 0.77,-0.29 1.06,0l0.88,0.88l0.88,-0.88c0.29,-0.29 0.77,-0.29 1.06,0l0,0c0.29,0.29 0.29,0.77 0,1.06l-0.88,0.88l0.88,0.88c0.29,0.29 0.29,0.77 0,1.06l0,0c-0.29,0.29 -0.77,0.29 -1.06,0L15.5,9.54l-0.88,0.88c-0.29,0.29 -0.77,0.29 -1.06,0l0,0c-0.29,-0.29 -0.29,-0.77 0,-1.06l0.88,-0.88L13.56,7.6C13.26,7.3 13.26,6.82 13.56,6.53zM7,7.72h3.5c0.41,0 0.75,0.34 0.75,0.75l0,0c0,0.41 -0.34,0.75 -0.75,0.75H7c-0.41,0 -0.75,-0.34 -0.75,-0.75l0,0C6.25,8.06 6.59,7.72 7,7.72zM10.75,16H9.5v1.25C9.5,17.66 9.16,18 8.75,18l0,0C8.34,18 8,17.66 8,17.25V16H6.75C6.34,16 6,15.66 6,15.25l0,0c0,-0.41 0.34,-0.75 0.75,-0.75H8v-1.25c0,-0.41 0.34,-0.75 0.75,-0.75l0,0c0.41,0 0.75,0.34 0.75,0.75v1.25h1.25c0.41,0 0.75,0.34 0.75,0.75l0,0C11.5,15.66 11.16,16 10.75,16zM17.25,17.25h-3.5c-0.41,0 -0.75,-0.34 -0.75,-0.75l0,0c0,-0.41 0.34,-0.75 0.75,-0.75h3.5c0.41,0 0.75,0.34 0.75,0.75l0,0C18,16.91 17.66,17.25 17.25,17.25zM17.25,14.75h-3.5C13.34,14.75 13,14.41 13,14l0,0c0,-0.41 0.34,-0.75 0.75,-0.75h3.5c0.41,0 0.75,0.34 0.75,0.75l0,0C18,14.41 17.66,14.75 17.25,14.75z"/>
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM13.56,6.53L13.56,6.53c0.29,-0.29 0.77,-0.29 1.06,0l0.88,0.88l0.88,-0.88c0.29,-0.29 0.77,-0.29 1.06,0l0,0c0.29,0.29 0.29,0.77 0,1.06l-0.88,0.88l0.88,0.88c0.29,0.29 0.29,0.77 0,1.06v0c-0.29,0.29 -0.77,0.29 -1.06,0L15.5,9.54l-0.88,0.88c-0.29,0.29 -0.77,0.29 -1.06,0l0,0c-0.29,-0.29 -0.29,-0.77 0,-1.06l0.88,-0.88l-0.88,-0.88C13.26,7.3 13.26,6.82 13.56,6.53zM7,7.72h3.5c0.41,0 0.75,0.34 0.75,0.75v0c0,0.41 -0.34,0.75 -0.75,0.75H7c-0.41,0 -0.75,-0.34 -0.75,-0.75v0C6.25,8.06 6.59,7.72 7,7.72zM10.75,16H9.5v1.25C9.5,17.66 9.16,18 8.75,18h0C8.34,18 8,17.66 8,17.25V16H6.75C6.34,16 6,15.66 6,15.25v0c0,-0.41 0.34,-0.75 0.75,-0.75H8v-1.25c0,-0.41 0.34,-0.75 0.75,-0.75h0c0.41,0 0.75,0.34 0.75,0.75v1.25h1.25c0.41,0 0.75,0.34 0.75,0.75v0C11.5,15.66 11.16,16 10.75,16zM17.25,17.25h-3.5c-0.41,0 -0.75,-0.34 -0.75,-0.75l0,0c0,-0.41 0.34,-0.75 0.75,-0.75h3.5c0.41,0 0.75,0.34 0.75,0.75l0,0C18,16.91 17.66,17.25 17.25,17.25zM17.25,14.75h-3.5C13.34,14.75 13,14.41 13,14v0c0,-0.41 0.34,-0.75 0.75,-0.75h3.5c0.41,0 0.75,0.34 0.75,0.75v0C18,14.41 17.66,14.75 17.25,14.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/calendar_today.xml b/compose/material/material/icons/generator/raw-icons/rounded/calendar_today.xml
index a832d33..5e299fb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/calendar_today.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/calendar_today.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4h-1V3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1h0C6.45,2 6,2.45 6,3v1H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V10h14V20z"/>
+ android:pathData="M20,3h-1L19,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L7,3L7,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L4,3c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,5c0,-1.1 -0.9,-2 -2,-2zM19,21L5,21c-0.55,0 -1,-0.45 -1,-1L4,8h16v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call.xml b/compose/material/material/icons/generator/raw-icons/rounded/call.xml
index 324cfc7..0c2d257 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77H5.03c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_end.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_end.xml
index aa0d825..808698c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_end.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_end.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8c-1.09,0 -6.58,0.1 -10.91,4.71c-0.38,0.4 -0.38,1.02 0.01,1.41l2.29,2.27c0.35,0.35 0.91,0.39 1.3,0.09L7.6,14.3C7.85,14.11 8,13.81 8,13.5v-2.87C9.26,10.23 10.6,10 12,10s2.74,0.23 4,0.63v2.87c0,0.31 0.15,0.61 0.4,0.8l2.91,2.18c0.4,0.3 0.95,0.26 1.3,-0.09l2.29,-2.27c0.39,-0.39 0.39,-1.01 0.01,-1.41C18.58,8.1 13.09,8 12,8z"/>
+ android:pathData="M4.51,15.48l2,-1.59c0.48,-0.38 0.76,-0.96 0.76,-1.57v-2.6c3.02,-0.98 6.29,-0.99 9.32,0v2.61c0,0.61 0.28,1.19 0.76,1.57l1.99,1.58c0.8,0.63 1.94,0.57 2.66,-0.15l1.22,-1.22c0.8,-0.8 0.8,-2.13 -0.05,-2.88 -6.41,-5.66 -16.07,-5.66 -22.48,0 -0.85,0.75 -0.85,2.08 -0.05,2.88l1.22,1.22c0.71,0.72 1.85,0.78 2.65,0.15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_made.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_made.xml
index a48aba8..144ea2f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_made.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_made.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,5h-6.59c-0.89,0 -1.34,1.08 -0.71,1.71l2.59,2.59L4.7,17.89c-0.39,0.39 -0.39,1.02 0,1.41h0c0.39,0.39 1.02,0.39 1.41,0l8.59,-8.59l2.59,2.59c0.63,0.63 1.71,0.18 1.71,-0.71V6C19,5.45 18.55,5 18,5z"/>
+ android:pathData="M9,6c0,0.56 0.45,1 1,1h5.59L4.7,17.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L17,8.41V14c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_merge.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_merge.xml
index 10b70ec..f21a7f9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_merge.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_merge.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,15.59L13.59,17l2.3,2.3c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L15,15.59z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.65,3.35L7.85,7.15C7.54,7.46 7.76,8 8.21,8H11v5.59l-4.3,4.3c-0.39,0.39 -0.39,1.02 0,1.41h0c0.39,0.39 1.02,0.39 1.41,0L13,14.41V8h2.79c0.45,0 0.67,-0.54 0.35,-0.85l-3.79,-3.79C12.16,3.16 11.84,3.16 11.65,3.35z"/>
+ android:pathData="M17.7,19.7c0.39,-0.39 0.39,-1.02 0,-1.41l-2.7,-2.7L13.59,17l2.7,2.7c0.39,0.39 1.03,0.39 1.41,0zM8.71,8H11v5.59l-4.71,4.7c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l5.3,-5.3V8h2.29c0.45,0 0.67,-0.54 0.35,-0.85l-3.29,-3.29c-0.2,-0.2 -0.51,-0.2 -0.71,0L8.35,7.15c-0.31,0.31 -0.09,0.85 0.36,0.85z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_missed.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_missed.xml
index 12b4d87..a77d5ed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_missed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_missed.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.3,7.7L20.3,7.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,14.59l-4.29,-4.3l1.59,-1.59C9.92,8.08 9.48,7 8.59,7H4C3.45,7 3,7.45 3,8v4.59c0,0.89 1.08,1.34 1.71,0.71l1.59,-1.59l5,5c0.39,0.39 1.02,0.39 1.41,0l7.59,-7.59C20.68,8.73 20.68,8.09 20.3,7.7z"/>
+ android:pathData="M18.89,7.7L12,14.59 6.41,9H10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3.59l6.29,6.29c0.39,0.39 1.02,0.39 1.41,0l7.59,-7.59c0.39,-0.39 0.39,-1.02 0,-1.41 -0.38,-0.38 -1.02,-0.38 -1.4,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_missed_outgoing.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_missed_outgoing.xml
index c8e75e2..7b77fae 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_missed_outgoing.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_missed_outgoing.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M3.7,7.7L3.7,7.7c0.39,-0.39 1.02,-0.39 1.41,0L12,14.59l4.29,-4.3l-1.59,-1.59C14.08,8.08 14.52,7 15.41,7H20c0.55,0 1,0.45 1,1v4.59c0,0.89 -1.08,1.34 -1.71,0.71l-1.59,-1.59l-5,5c-0.39,0.39 -1.02,0.39 -1.41,0L3.7,9.11C3.32,8.73 3.32,8.09 3.7,7.7z"/>
+ android:pathData="M3.7,9.11l7.59,7.59c0.39,0.39 1.02,0.39 1.41,0l6.3,-6.3V14c0,0.55 0.45,1 1,1s1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3.59L12,14.59 5.11,7.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.38,0.39 -0.38,1.03 0,1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_received.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_received.xml
index aa086f0..76e8126 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_received.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_received.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,19h6.59c0.89,0 1.34,-1.08 0.71,-1.71l-2.59,-2.59l8.59,-8.59c0.39,-0.39 0.39,-1.02 0,-1.41v0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-8.59,8.59l-2.59,-2.59C6.08,10.08 5,10.52 5,11.41V18C5,18.55 5.45,19 6,19z"/>
+ android:pathData="M19.3,4.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L7,15.59V10c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8.41L19.3,6.11c0.38,-0.38 0.38,-1.02 0,-1.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_split.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_split.xml
index 3625e74..3a87eb7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_split.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_split.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.85,4.85l1.44,1.44l-2.88,2.88l1.42,1.42l2.88,-2.88l1.44,1.44C19.46,9.46 20,9.24 20,8.79V4.5C20,4.22 19.78,4 19.5,4h-4.29C14.76,4 14.54,4.54 14.85,4.85zM8.79,4H4.5C4.22,4 4,4.22 4,4.5v4.29c0,0.45 0.54,0.67 0.85,0.35L6.29,7.7L11,12.4V19c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-7c0,-0.26 -0.11,-0.52 -0.29,-0.71l-5,-5.01l1.44,-1.44C9.46,4.54 9.24,4 8.79,4z"/>
+ android:pathData="M14.85,4.85l1.44,1.44 -2.88,2.88 1.42,1.42 2.88,-2.88 1.44,1.44c0.31,0.31 0.85,0.09 0.85,-0.36V4.5c0,-0.28 -0.22,-0.5 -0.5,-0.5h-4.29c-0.45,0 -0.67,0.54 -0.36,0.85zM8.79,4H4.5c-0.28,0 -0.5,0.22 -0.5,0.5v4.29c0,0.45 0.54,0.67 0.85,0.35L6.29,7.7 11,12.4V19c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-7c0,-0.26 -0.11,-0.52 -0.29,-0.71l-5,-5.01 1.44,-1.44c0.31,-0.3 0.09,-0.84 -0.36,-0.84z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/call_to_action.xml b/compose/material/material/icons/generator/raw-icons/rounded/call_to_action.xml
index 05afc24..9b94e1e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/call_to_action.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/call_to_action.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM16.5,17h-9C6.67,17 6,16.33 6,15.5v0C6,14.67 6.67,14 7.5,14h9c0.83,0 1.5,0.67 1.5,1.5v0C18,16.33 17.33,17 16.5,17z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM20,19L4,19c-0.55,0 -1,-0.45 -1,-1v-1c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v1c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/camera.xml b/compose/material/material/icons/generator/raw-icons/rounded/camera.xml
index 1e3a77b..7889220 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/camera.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/camera.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.81,2.86c0.17,-0.3 0,-0.7 -0.35,-0.74c-2.62,-0.37 -5.3,0.28 -7.44,1.86C5.83,4.13 5.77,4.41 5.9,4.63l3.01,5.22c0.19,0.33 0.67,0.33 0.87,0L13.81,2.86z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.3,8.33c-0.98,-2.47 -2.92,-4.46 -5.35,-5.5c-0.23,-0.1 -0.5,0 -0.63,0.22l-3.01,5.21C12.12,8.58 12.36,9 12.75,9h8.08C21.18,9 21.43,8.65 21.3,8.33z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.37,10h-6.2c-0.38,0 -0.63,0.42 -0.43,0.75L19,18.14c0.17,0.3 0.6,0.35 0.82,0.08c1.74,-2.18 2.48,-5.03 2.05,-7.79C21.84,10.18 21.62,10 21.37,10z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4.18,5.79c-1.73,2.19 -2.48,5.02 -2.05,7.79C2.16,13.82 2.38,14 2.63,14h6.2c0.38,0 0.63,-0.42 0.43,-0.75L5,5.87C4.82,5.57 4.39,5.52 4.18,5.79z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.7,15.67c0.98,2.47 2.92,4.46 5.35,5.5c0.23,0.1 0.5,0 0.63,-0.22l3.01,-5.21c0.19,-0.33 -0.05,-0.75 -0.43,-0.75H3.17C2.82,15 2.57,15.35 2.7,15.67z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10.53,21.89c2.62,0.37 5.3,-0.28 7.44,-1.86c0.2,-0.15 0.26,-0.44 0.13,-0.66l-3.01,-5.22c-0.19,-0.33 -0.67,-0.33 -0.87,0l-4.04,6.99C10.01,21.44 10.19,21.84 10.53,21.89z"/>
+ android:pathData="M13.81,2.86c0.17,-0.3 0,-0.7 -0.35,-0.74 -2.62,-0.37 -5.3,0.28 -7.44,1.86 -0.19,0.15 -0.25,0.43 -0.12,0.65l3.01,5.22c0.19,0.33 0.67,0.33 0.87,0l4.03,-6.99zM21.3,8.33c-0.98,-2.47 -2.92,-4.46 -5.35,-5.5 -0.23,-0.1 -0.5,0 -0.63,0.22l-3.01,5.21c-0.19,0.32 0.05,0.74 0.44,0.74h8.08c0.35,0 0.6,-0.35 0.47,-0.67zM21.37,10h-6.2c-0.38,0 -0.63,0.42 -0.43,0.75L19,18.14c0.17,0.3 0.6,0.35 0.82,0.08 1.74,-2.18 2.48,-5.03 2.05,-7.79 -0.03,-0.25 -0.25,-0.43 -0.5,-0.43zM4.18,5.79c-1.73,2.19 -2.48,5.02 -2.05,7.79 0.03,0.24 0.25,0.42 0.5,0.42h6.2c0.38,0 0.63,-0.42 0.43,-0.75L5,5.87c-0.18,-0.3 -0.61,-0.35 -0.82,-0.08zM2.7,15.67c0.98,2.47 2.92,4.46 5.35,5.5 0.23,0.1 0.5,0 0.63,-0.22l3.01,-5.21c0.19,-0.33 -0.05,-0.75 -0.43,-0.75L3.17,14.99c-0.35,0.01 -0.6,0.36 -0.47,0.68zM10.53,21.89c2.62,0.37 5.3,-0.28 7.44,-1.86 0.2,-0.15 0.26,-0.44 0.13,-0.66l-3.01,-5.22c-0.19,-0.33 -0.67,-0.33 -0.87,0l-4.04,6.99c-0.17,0.3 0.01,0.7 0.35,0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/camera_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/camera_alt.xml
index 9969066..ddeb49b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/camera_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/camera_alt.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,13m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+ android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-3.17l-1.24,-1.35C15.22,3.24 14.68,3 14.12,3H9.88c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM12,17.5c-2.48,0 -4.5,-2.02 -4.5,-4.5S9.52,8.5 12,8.5s4.5,2.02 4.5,4.5S14.48,17.5 12,17.5z"/>
+ android:pathData="M20,4h-3.17l-1.24,-1.35c-0.37,-0.41 -0.91,-0.65 -1.47,-0.65L9.88,2c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/camera_enhance.xml b/compose/material/material/icons/generator/raw-icons/rounded/camera_enhance.xml
index b281e97..a86642d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/camera_enhance.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/camera_enhance.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-3.17l-1.24,-1.35C15.22,3.24 14.68,3 14.12,3H9.88c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM12,17.5c-2.48,0 -4.5,-2.02 -4.5,-4.5S9.52,8.5 12,8.5s4.5,2.02 4.5,4.5S14.48,17.5 12,17.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.54,10.5l-0.64,1.4l-1.4,0.64c-0.39,0.18 -0.39,0.73 0,0.91l1.4,0.64l0.64,1.4c0.18,0.39 0.73,0.39 0.91,0l0.64,-1.4l1.4,-0.64c0.39,-0.18 0.39,-0.73 0,-0.91l-1.4,-0.64l-0.64,-1.4C12.28,10.11 11.72,10.11 11.54,10.5z"/>
+ android:pathData="M20,5h-3.17l-1.24,-1.35c-0.37,-0.41 -0.91,-0.65 -1.47,-0.65L9.88,3c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5L4,5c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM12,18c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9l-1.25,2.75L8,13l2.75,1.25L12,17l1.25,-2.75L16,13l-2.75,-1.25z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/camera_front.xml b/compose/material/material/icons/generator/raw-icons/rounded/camera_front.xml
index f9ce2b6..11898839 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/camera_front.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/camera_front.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.94,17l1.5,-1.5c0.78,-0.78 2.05,-0.78 2.83,0l1.5,1.5h4.3c1.07,0 1.94,-0.87 1.94,-1.94V4c0,-1.1 -0.9,-2 -2,-2L7,2C5.9,2 5,2.9 5,4v11.06C5,16.13 5.87,17 6.94,17L6.94,17zM7,4h10v9.13C15.12,12.24 12.89,12 12,12s-3.12,0.24 -5,1.13V4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,8m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.64,18.29l-2.09,-2.09c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L9.53,18H6c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h3.53l-0.38,0.38c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l2.09,-2.09C13.03,19.32 13.03,18.68 12.64,18.29z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,20h3c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v0C14,19.55 14.45,20 15,20z"/>
+ android:pathData="M17,0L7,0C5.9,0 5,0.9 5,2v14c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,2c0,-1.1 -0.9,-2 -2,-2zM17,12.5c0,-1.67 -3.33,-2.5 -5,-2.5s-5,0.83 -5,2.5L7,3c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v9.5zM10.85,18.85c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L10,20L6,20c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4v0.79c0,0.45 0.54,0.67 0.85,0.35l1.79,-1.79c0.2,-0.2 0.2,-0.51 0,-0.71l-1.79,-1.79zM18,20h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -1.99,0.9 -1.99,2S10.9,8 12,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/camera_rear.xml b/compose/material/material/icons/generator/raw-icons/rounded/camera_rear.xml
index 52fadbd..75ba0bd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/camera_rear.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/camera_rear.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.26,15.5l1.5,1.5h4.3c1.07,0 1.94,-0.87 1.94,-1.94V4c0,-1.1 -0.9,-1.99 -2,-1.99L7,2C5.9,2 5,2.9 5,4v11.06C5,16.13 5.87,17 6.94,17h0l1.5,-1.5C9.22,14.72 10.48,14.72 11.26,15.5zM12,6c1.1,0 2,0.9 2,2c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2C10,6.9 10.9,6 12,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.64,18.29l-2.09,-2.09c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L9.53,18H6c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h3.53l-0.38,0.38c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l2.09,-2.09C13.03,19.32 13.03,18.68 12.64,18.29z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,20h3c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v0C14,19.55 14.45,20 15,20z"/>
+ android:pathData="M10.85,18.85c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L10,20L6,20c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4v0.79c0,0.45 0.54,0.67 0.85,0.35l1.79,-1.79c0.2,-0.2 0.2,-0.51 0,-0.71l-1.79,-1.79zM18,20h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM17,0L7,0C5.9,0 5,0.9 5,2v14c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,2c0,-1.1 -0.9,-2 -2,-2zM12,6c-1.11,0 -2,-0.9 -2,-2s0.89,-2 1.99,-2 2,0.9 2,2C14,5.1 13.1,6 12,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/camera_roll.xml b/compose/material/material/icons/generator/raw-icons/rounded/camera_roll.xml
index d92b4ba..75d7917 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/camera_roll.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/camera_roll.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,5c0,-1.1 -0.9,-2 -2,-2h-1V2c0,-0.55 -0.45,-1 -1,-1H6C5.45,1 5,1.45 5,2v1H4C2.9,3 2,3.9 2,5v15c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2h6c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H14zM11,17H9v-2h2V17zM11,10H9V8h2V10zM15,17h-2v-2h2V17zM15,10h-2V8h2V10zM19,17h-2v-2h2V17zM19,10h-2V8h2V10z"/>
+ android:pathData="M14,5c0,-1.1 -0.9,-2 -2,-2h-1L11,2c0,-0.55 -0.45,-1 -1,-1L6,1c-0.55,0 -1,0.45 -1,1v1L4,3c-1.1,0 -2,0.9 -2,2v15c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2h6c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2h-6zM12,18h-2v-2h2v2zM12,9h-2L10,7h2v2zM16,18h-2v-2h2v2zM16,9h-2L14,7h2v2zM20,18h-2v-2h2v2zM20,9h-2L18,7h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/campaign.xml b/compose/material/material/icons/generator/raw-icons/rounded/campaign.xml
index ff12634..2bde321 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/campaign.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/campaign.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,12L18,12c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-2C18.45,11 18,11.45 18,12z"/>
+ android:pathData="M18,12L18,12c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-2C18.45,11 18,11.45 18,12z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M16.59,16.82c-0.33,0.44 -0.24,1.05 0.2,1.37c0.53,0.39 1.09,0.81 1.62,1.21c0.44,0.33 1.06,0.24 1.38,-0.2c0,-0.01 0.01,-0.01 0.01,-0.02c0.33,-0.44 0.24,-1.06 -0.2,-1.38c-0.53,-0.4 -1.09,-0.82 -1.61,-1.21c-0.44,-0.33 -1.06,-0.23 -1.39,0.21C16.6,16.81 16.59,16.82 16.59,16.82z"/>
@@ -15,7 +15,7 @@
android:pathData="M19.81,4.81c0,-0.01 -0.01,-0.01 -0.01,-0.02c-0.33,-0.44 -0.95,-0.53 -1.38,-0.2c-0.53,0.4 -1.1,0.82 -1.62,1.22c-0.44,0.33 -0.52,0.95 -0.19,1.38c0,0.01 0.01,0.01 0.01,0.02c0.33,0.44 0.94,0.53 1.38,0.2c0.53,-0.39 1.09,-0.82 1.62,-1.22C20.05,5.87 20.13,5.25 19.81,4.81z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M8,9H4c-1.1,0 -2,0.9 -2,2v2c0,1.1 0.9,2 2,2h1v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-3h1l4.24,2.55c0.33,0.2 0.76,-0.04 0.76,-0.43V6.88c0,-0.39 -0.42,-0.63 -0.76,-0.43L8,9z"/>
+ android:pathData="M8,9H4c-1.1,0 -2,0.9 -2,2v2c0,1.1 0.9,2 2,2h1v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-3h1l5,3V6L8,9z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M15.5,12c0,-1.33 -0.58,-2.53 -1.5,-3.35v6.69C14.92,14.53 15.5,13.33 15.5,12z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cancel.xml b/compose/material/material/icons/generator/raw-icons/rounded/cancel.xml
index a672d5c..ce93e71 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cancel.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cancel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.47,2 2,6.47 2,12c0,5.53 4.47,10 10,10s10,-4.47 10,-10C22,6.47 17.53,2 12,2zM16.29,14.89c0.39,0.39 0.39,1.02 0,1.41c-0.39,0.39 -1.02,0.39 -1.41,0L12,13.41l-2.89,2.89c-0.39,0.39 -1.02,0.39 -1.41,0c-0.39,-0.39 -0.39,-1.02 0,-1.41L10.59,12L7.71,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41c0.39,-0.39 1.02,-0.39 1.41,0L12,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0c0.39,0.39 0.39,1.02 0,1.41L13.41,12L16.29,14.89z"/>
+ android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM16.3,16.3c-0.39,0.39 -1.02,0.39 -1.41,0L12,13.41 9.11,16.3c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41L10.59,12 7.7,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L12,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41L13.41,12l2.89,2.89c0.38,0.38 0.38,1.02 0,1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cancel_presentation.xml b/compose/material/material/icons/generator/raw-icons/rounded/cancel_presentation.xml
index 9675033..5df715c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cancel_presentation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cancel_presentation.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,18H4V6h16V18zM10.11,15.3L12,13.41l1.89,1.89c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l1.89,-1.89c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59L10.11,8.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L10.59,12L8.7,13.89c-0.39,0.39 -0.39,1.02 0,1.41l0,0C9.09,15.68 9.73,15.68 10.11,15.3z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,18c0,0.55 -0.45,1 -1,1L4,19c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12zM15.29,8.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 10.11,8.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 8.7,13.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l1.89,1.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l1.89,-1.89c0.38,-0.38 0.38,-1.02 -0.01,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cancel_schedule_send.xml b/compose/material/material/icons/generator/raw-icons/rounded/cancel_schedule_send.xml
index 2a51fb3..ca12d0e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cancel_schedule_send.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cancel_schedule_send.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,10c0.1,0 0.19,0.01 0.28,0.01L4.39,4.58C3.73,4.31 3,4.79 3,5.51v3.71c0,0.46 0.31,0.86 0.76,0.97L11,12l-7.24,1.81C3.31,13.92 3,14.32 3,14.78v3.71c0,0.72 0.73,1.2 1.39,0.92L10,17.05c0,-0.02 0,-0.03 0,-0.05C10,13.14 13.14,10 17,10zM17,12c-2.76,0 -5,2.24 -5,5s2.24,5 5,5c2.76,0 5,-2.24 5,-5S19.76,12 17,12zM19.12,19.12L19.12,19.12c-0.2,0.2 -0.51,0.2 -0.71,0L17,17.71l-1.41,1.41c-0.2,0.2 -0.51,0.2 -0.71,0l0,0c-0.2,-0.2 -0.2,-0.51 0,-0.71L16.29,17l-1.41,-1.41c-0.2,-0.2 -0.2,-0.51 0,-0.71l0,0c0.2,-0.2 0.51,-0.2 0.71,0L17,16.29l1.41,-1.41c0.2,-0.2 0.51,-0.2 0.71,0l0,0c0.2,0.2 0.2,0.51 0,0.71L17.71,17l1.41,1.41C19.32,18.61 19.32,18.93 19.12,19.12z"/>
+ android:pathData="M16.5,9c-0.42,0 -0.83,0.04 -1.24,0.11L2.4,3.6C1.74,3.31 1.01,3.8 1.01,4.51L1,9.2c0,0.47 0.33,0.88 0.78,0.98L10,12l-8.22,1.83C1.33,13.93 1,14.33 1,14.8l0.01,4.68c0,0.72 0.73,1.2 1.39,0.92l6.68,-2.86C9.59,21.19 12.71,24 16.5,24c4.14,0 7.5,-3.36 7.5,-7.5S20.64,9 16.5,9zM16.5,22c-3.03,0 -5.5,-2.47 -5.5,-5.5s2.47,-5.5 5.5,-5.5s5.5,2.47 5.5,5.5S19.53,22 16.5,22z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.62,14.38c-0.2,-0.2 -0.51,-0.2 -0.71,0l-1.41,1.41l-1.41,-1.41c-0.2,-0.2 -0.51,-0.2 -0.71,0s-0.2,0.51 0,0.71l1.41,1.41l-1.41,1.41c-0.2,0.2 -0.2,0.51 0,0.71c0.2,0.2 0.51,0.2 0.71,0l1.41,-1.41l1.41,1.41c0.2,0.2 0.51,0.2 0.71,0c0.2,-0.2 0.2,-0.51 0,-0.71l-1.41,-1.41l1.41,-1.41C18.82,14.89 18.82,14.57 18.62,14.38z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/card_giftcard.xml b/compose/material/material/icons/generator/raw-icons/rounded/card_giftcard.xml
index 43db4ab..fe06dea 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/card_giftcard.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/card_giftcard.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-2.18C17.93,5.69 18,5.35 18,5c0,-1.66 -1.34,-3 -3,-3c-1.05,0 -1.96,0.54 -2.5,1.35L12,4.02l-0.5,-0.68C10.96,2.54 10.05,2 9,2C7.34,2 6,3.34 6,5c0,0.35 0.07,0.69 0.18,1H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM15,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S14.45,4 15,4zM9,4c0.55,0 1,0.45 1,1S9.55,6 9,6S8,5.55 8,5S8.45,4 9,4zM20,19H4v-2h16V19zM20,14H4V8h5.08L7.6,10.02c-0.33,0.45 -0.23,1.08 0.22,1.4c0.44,0.32 1.07,0.22 1.39,-0.22L12,7.4l2.79,3.8c0.32,0.44 0.95,0.54 1.39,0.22c0.45,-0.32 0.55,-0.95 0.22,-1.4L14.92,8H20V14z"/>
+ android:pathData="M20,6h-2.18c0.11,-0.31 0.18,-0.65 0.18,-1 0,-1.66 -1.34,-3 -3,-3 -1.05,0 -1.96,0.54 -2.5,1.35l-0.5,0.67 -0.5,-0.68C10.96,2.54 10.05,2 9,2 7.34,2 6,3.34 6,5c0,0.35 0.07,0.69 0.18,1L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM15,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM9,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM20,19L4,19v-2h16v2zM20,14L4,14L4,9c0,-0.55 0.45,-1 1,-1h4.08L7.6,10.02c-0.33,0.45 -0.23,1.08 0.22,1.4 0.44,0.32 1.07,0.22 1.39,-0.22L12,7.4l2.79,3.8c0.32,0.44 0.95,0.54 1.39,0.22 0.45,-0.32 0.55,-0.95 0.22,-1.4L14.92,8L19,8c0.55,0 1,0.45 1,1v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/card_membership.xml b/compose/material/material/icons/generator/raw-icons/rounded/card_membership.xml
index 0fc8b0b..13d7199 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/card_membership.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/card_membership.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v11c0,1.1 0.9,2 2,2h4v3.38c0,0.74 0.78,1.23 1.45,0.89L12,20l2.55,1.28c0.66,0.33 1.45,-0.15 1.45,-0.89V17h4c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM20,15H4v-2h16V15zM20,10H4V4h16V10z"/>
+ android:pathData="M20,2L4,2c-1.11,0 -2,0.89 -2,2v11c0,1.11 0.89,2 2,2h4v5l4,-2 4,2v-5h4c1.11,0 2,-0.89 2,-2L22,4c0,-1.11 -0.89,-2 -2,-2zM20,15L4,15v-2h16v2zM20,10L4,10L4,5c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/card_travel.xml b/compose/material/material/icons/generator/raw-icons/rounded/card_travel.xml
index 333d284..02950aa 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/card_travel.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/card_travel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-3V4c0,-1.11 -0.89,-2 -2,-2H9C7.89,2 7,2.89 7,4v2H4C2.89,6 2,6.89 2,8v11c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM9,4h6v2H9V4zM20,19H4v-2h16V19zM20,14H4V8h3v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1V8h6v1c0,0.55 0.45,1 1,1c0.55,0 1,-0.45 1,-1V8h3V14z"/>
+ android:pathData="M20,6h-3L17,4c0,-1.11 -0.89,-2 -2,-2L9,2c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -2,0.89 -2,2v11c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM9,4h6v2L9,6L9,4zM20,19L4,19v-2h16v2zM20,14L4,14L4,9c0,-0.55 0.45,-1 1,-1h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1L9,8h6v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1L17,8h2c0.55,0 1,0.45 1,1v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/casino.xml b/compose/material/material/icons/generator/raw-icons/rounded/casino.xml
index 1ef86f4..cd14a3a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/casino.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/casino.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM7.5,18C6.67,18 6,17.33 6,16.5S6.67,15 7.5,15S9,15.67 9,16.5S8.33,18 7.5,18zM7.5,9C6.67,9 6,8.33 6,7.5S6.67,6 7.5,6S9,6.67 9,7.5S8.33,9 7.5,9zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S12.83,13.5 12,13.5zM16.5,18c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S17.33,18 16.5,18zM16.5,9C15.67,9 15,8.33 15,7.5S15.67,6 16.5,6S18,6.67 18,7.5S17.33,9 16.5,9z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM7.5,18c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,15 7.5,15s1.5,0.67 1.5,1.5S8.33,18 7.5,18zM7.5,9C6.67,9 6,8.33 6,7.5S6.67,6 7.5,6 9,6.67 9,7.5 8.33,9 7.5,9zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM16.5,18c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM16.5,9c-0.83,0 -1.5,-0.67 -1.5,-1.5S15.67,6 16.5,6s1.5,0.67 1.5,1.5S17.33,9 16.5,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cast.xml b/compose/material/material/icons/generator/raw-icons/rounded/cast.xml
index 304ab43..4f092f8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cast.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cast.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v0c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v0h16v12h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.14,13.09c-0.6,-0.1 -1.14,0.39 -1.14,1c0,0.49 0.36,0.9 0.85,0.98c2.08,0.36 3.72,2 4.08,4.08C7.01,19.64 7.42,20 7.91,20c0.61,0 1.09,-0.54 1,-1.14C8.43,15.9 6.09,13.57 3.14,13.09z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2,17.56v1.94C2,19.78 2.22,20 2.5,20h1.94c0.32,0 0.56,-0.29 0.5,-0.6c-0.24,-1.18 -1.16,-2.1 -2.34,-2.34C2.29,17 2,17.24 2,17.56z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.1,9.05C2.51,9 2,9.46 2,10.05c0,0.51 0.38,0.94 0.88,0.99c4.27,0.41 7.67,3.81 8.08,8.08c0.05,0.5 0.48,0.87 0.99,0.87c0.6,0 1.06,-0.52 1,-1.11C12.42,13.69 8.29,9.57 3.1,9.05z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1h-5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM2.14,14.09c-0.6,-0.1 -1.14,0.39 -1.14,1 0,0.49 0.36,0.9 0.85,0.98 2.08,0.36 3.72,2 4.08,4.08 0.08,0.49 0.49,0.85 0.98,0.85 0.61,0 1.09,-0.54 1,-1.14 -0.48,-2.96 -2.82,-5.29 -5.77,-5.77zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM2.1,10.05c-0.59,-0.05 -1.1,0.41 -1.1,1 0,0.51 0.38,0.94 0.88,0.99 4.27,0.41 7.67,3.81 8.08,8.08 0.05,0.5 0.48,0.87 0.99,0.87 0.6,0 1.06,-0.52 1,-1.11 -0.53,-5.19 -4.66,-9.31 -9.85,-9.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cast_connected.xml b/compose/material/material/icons/generator/raw-icons/rounded/cast_connected.xml
index 65a6e46..d5dbfcd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cast_connected.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cast_connected.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,17.56v1.94C2,19.78 2.22,20 2.5,20h1.94c0.32,0 0.56,-0.29 0.5,-0.6c-0.24,-1.18 -1.16,-2.1 -2.34,-2.34C2.29,17 2,17.24 2,17.56zM3.14,13.09c-0.6,-0.1 -1.14,0.39 -1.14,1c0,0.49 0.36,0.9 0.85,0.98c2.08,0.36 3.72,2 4.08,4.08C7.01,19.64 7.42,20 7.91,20c0.61,0 1.09,-0.54 1,-1.14C8.43,15.9 6.09,13.57 3.14,13.09zM3.1,9.05C2.51,9 2,9.46 2,10.05c0,0.51 0.38,0.94 0.88,0.99c4.27,0.41 7.67,3.81 8.08,8.08c0.05,0.5 0.48,0.87 0.99,0.87c0.6,0 1.06,-0.52 1,-1.11C12.42,13.69 8.29,9.57 3.1,9.05zM20,4H4C2.9,4 2,4.9 2,6c0,0.55 0.45,1 1,1s1,-0.45 1,-1h16v12h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM18,15V9c0,-0.55 -0.45,-1 -1,-1H7c3.48,1.45 6.19,4.38 7.37,8H17C17.55,16 18,15.55 18,15z"/>
+ android:pathData="M19,16L19,8c0,-0.55 -0.45,-1 -1,-1L6,7c-0.55,0 -1,0.45 -1,1v0.63c3.96,1.28 7.09,4.41 8.37,8.37L18,17c0.55,0 1,-0.45 1,-1zM21,3L3,3c-1.1,0 -2,0.9 -2,2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1h-5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-0.62 -0.19,-1.2 -0.51,-1.68C2.95,18.52 2.04,18 1,18zM2.14,14.09c-0.6,-0.1 -1.14,0.39 -1.14,1 0,0.49 0.36,0.9 0.85,0.98 2.08,0.36 3.72,2 4.08,4.08 0.08,0.49 0.49,0.85 0.98,0.85 0.61,0 1.09,-0.54 1,-1.14 -0.48,-2.96 -2.82,-5.29 -5.77,-5.77zM2.1,10.05c-0.59,-0.05 -1.1,0.41 -1.1,1 0,0.51 0.38,0.94 0.88,0.99 4.27,0.41 7.67,3.81 8.08,8.08 0.05,0.5 0.48,0.87 0.99,0.87 0.6,0 1.06,-0.52 1,-1.11 -0.53,-5.19 -4.66,-9.31 -9.85,-9.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cast_for_education.xml b/compose/material/material/icons/generator/raw-icons/rounded/cast_for_education.xml
index 9c60dffc..7a92bd9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cast_for_education.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cast_for_education.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6c0,0.55 0.45,1 1,1s1,-0.45 1,-1h16v12h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.74,9.07l-2.49,-1.42c-0.15,-0.09 -0.34,-0.09 -0.5,0l-2.49,1.42c-0.34,0.19 -0.34,0.68 0,0.87l2.49,1.42c0.15,0.09 0.34,0.09 0.5,0l2.49,-1.42C18.08,9.74 18.08,9.26 17.74,9.07z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.5,11L15,12.43L12.5,11v0.92c0,0.36 0.19,0.69 0.5,0.87l1.5,0.86c0.31,0.18 0.68,0.18 0.99,0l1.5,-0.86c0.31,-0.18 0.5,-0.51 0.5,-0.87V11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.6,17.01C2.29,16.95 2,17.19 2,17.51v1.94c0,0.28 0.22,0.5 0.5,0.5h1.94c0.32,0 0.56,-0.29 0.5,-0.6C4.7,18.18 3.78,17.25 2.6,17.01z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.14,13.04c-0.6,-0.1 -1.14,0.39 -1.14,1c0,0.49 0.36,0.9 0.85,0.98c2.08,0.36 3.72,2 4.08,4.08c0.08,0.49 0.49,0.85 0.98,0.85c0.61,0 1.09,-0.54 1,-1.14C8.43,15.85 6.09,13.52 3.14,13.04z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.1,9C2.51,8.95 2,9.41 2,10c0,0.51 0.38,0.94 0.88,0.99c4.27,0.41 7.67,3.81 8.08,8.08c0.05,0.5 0.48,0.87 0.99,0.87c0.6,0 1.06,-0.52 1,-1.11C12.42,13.64 8.29,9.52 3.1,9z"/>
+ android:pathData="M19.2,8.56l-4.22,-2.3c-0.3,-0.16 -0.66,-0.16 -0.96,0L9.8,8.56c-0.35,0.19 -0.35,0.69 0,0.88l4.22,2.3c0.3,0.16 0.66,0.16 0.96,0l4.22,-2.3c0.34,-0.19 0.34,-0.69 0,-0.88zM21,3L3,3c-1.1,0 -2,0.9 -2,2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1h-5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM14.02,12.74L11,11.09v1.41c0,0.37 0.2,0.7 0.52,0.88l2.5,1.36c0.3,0.16 0.66,0.16 0.96,0l2.5,-1.36c0.32,-0.18 0.52,-0.52 0.52,-0.88v-1.41l-3.02,1.65c-0.3,0.16 -0.66,0.16 -0.96,0zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM2.14,14.09c-0.6,-0.1 -1.14,0.39 -1.14,1 0,0.49 0.36,0.9 0.85,0.98 2.08,0.36 3.72,2 4.08,4.08 0.08,0.49 0.49,0.85 0.98,0.85 0.61,0 1.09,-0.54 1,-1.14 -0.48,-2.96 -2.82,-5.29 -5.77,-5.77zM2.1,10.05c-0.59,-0.05 -1.1,0.41 -1.1,1 0,0.51 0.38,0.94 0.88,0.99 4.27,0.41 7.67,3.81 8.08,8.08 0.05,0.5 0.48,0.87 0.99,0.87 0.6,0 1.06,-0.52 1,-1.11 -0.53,-5.19 -4.66,-9.31 -9.85,-9.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/category.xml b/compose/material/material/icons/generator/raw-icons/rounded/category.xml
index 41f05e3..d866e32 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/category.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/category.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.15,3.4L7.43,9.48C7.02,10.14 7.5,11 8.28,11h7.43c0.78,0 1.26,-0.86 0.85,-1.52l-3.71,-6.07C12.46,2.77 11.54,2.77 11.15,3.4z"/>
+ android:pathData="M11.15,3.4L7.43,9.48c-0.41,0.66 0.07,1.52 0.85,1.52h7.43c0.78,0 1.26,-0.86 0.85,-1.52L12.85,3.4c-0.39,-0.64 -1.31,-0.64 -1.7,0z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M17.5,17.5m-4.5,0a4.5,4.5 0,1 1,9 0a4.5,4.5 0,1 1,-9 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M4,21.5h6c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v6C3,21.05 3.45,21.5 4,21.5z"/>
+ android:pathData="M4,21.5h6c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/center_focus_strong.xml b/compose/material/material/icons/generator/raw-icons/rounded/center_focus_strong.xml
index a1c10bc..b315e0c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/center_focus_strong.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/center_focus_strong.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,12c0,-2.76 -2.24,-5 -5,-5s-5,2.24 -5,5s2.24,5 5,5S17,14.76 17,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,15L4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5v-3C5,15.45 4.55,15 4,15z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5,5h3c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,3h-3c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5C21,3.9 20.1,3 19,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,19h-3c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1V19z"/>
+ android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,19c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 -0.45,-1 -1,-1zM5,6c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,3c-1.1,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L5,6zM19,3h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2c0.55,0 1,0.45 1,1v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L21,5c0,-1.1 -0.9,-2 -2,-2zM19,18c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/center_focus_weak.xml b/compose/material/material/icons/generator/raw-icons/rounded/center_focus_weak.xml
index fd1f8a7..caea996 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/center_focus_weak.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/center_focus_weak.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,15L4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5v-3C5,15.45 4.55,15 4,15zM5,5h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5zM19,3h-3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5C21,3.9 20.1,3 19,3zM19,19h-3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1V19zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S14.21,8 12,8z"/>
+ android:pathData="M4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,19c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 -0.45,-1 -1,-1zM5,6c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,3c-1.1,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L5,6zM19,3h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2c0.55,0 1,0.45 1,1v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L21,5c0,-1.1 -0.9,-2 -2,-2zM19,18c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/change_history.xml b/compose/material/material/icons/generator/raw-icons/rounded/change_history.xml
index 508aec6..4c38459 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/change_history.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/change_history.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7.77L18.39,18H5.61L12,7.77M11.15,5.36l-8.2,13.11C2.54,19.14 3.02,20 3.8,20h16.4c0.79,0 1.26,-0.86 0.85,-1.53l-8.2,-13.11C12.46,4.73 11.54,4.73 11.15,5.36z"/>
+ android:pathData="M12,7.77L18.39,18H5.61L12,7.77m-0.85,-2.41l-8.2,13.11c-0.41,0.67 0.07,1.53 0.85,1.53h16.4c0.79,0 1.26,-0.86 0.85,-1.53l-8.2,-13.11c-0.39,-0.63 -1.31,-0.63 -1.7,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/chat.xml b/compose/material/material/icons/generator/raw-icons/rounded/chat.xml
index 756466d..6e863bc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/chat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/chat.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4.01c-1.1,0 -2,0.89 -2,2L2,19.58c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM7,9h10c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1v0C6,9.45 6.45,9 7,9zM13,14H7c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v0C14,13.55 13.55,14 13,14zM17,8H7C6.45,8 6,7.55 6,7v0c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1v0C18,7.55 17.55,8 17,8z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM7,9h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1L7,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM13,14L7,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,8L7,8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/chat_bubble.xml b/compose/material/material/icons/generator/raw-icons/rounded/chat_bubble.xml
index b19d051..c91a7ec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/chat_bubble.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/chat_bubble.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v15.59c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2z"/>
+ android:pathData="M20,2H4c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/check.xml b/compose/material/material/icons/generator/raw-icons/rounded/check.xml
index 8f3250d..d8372f6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/check.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/check.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,6.7l-8.48,8.48l-3.54,-3.54c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l4.24,4.24c0.39,0.39 1.02,0.39 1.41,0l9.18,-9.18c0.39,-0.39 0.39,-1.03 -0.01,-1.42l0,0C19.02,6.31 18.39,6.31 18,6.7z"/>
+ android:pathData="M9,16.17L5.53,12.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L20.29,7.71c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L9,16.17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/check_box.xml b/compose/material/material/icons/generator/raw-icons/rounded/check_box.xml
index 52e476b..d1e7de1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/check_box.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/check_box.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM9.88,15.54l-2.83,-2.83c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l2.12,2.12l4.95,-4.95c0.39,-0.39 1.02,-0.39 1.41,0v0c0.39,0.39 0.39,1.02 0,1.41l-5.66,5.66C10.9,15.93 10.27,15.93 9.88,15.54z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM10.71,16.29c-0.39,0.39 -1.02,0.39 -1.41,0L5.71,12.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L10,14.17l6.88,-6.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-7.58,7.59z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/check_box_outline_blank.xml b/compose/material/material/icons/generator/raw-icons/rounded/check_box_outline_blank.xml
index 00c45d8..66a0af0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/check_box_outline_blank.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/check_box_outline_blank.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,19H5V5h14V19zM19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3L19,3z"/>
+ android:pathData="M18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/check_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/check_circle.xml
index 011169b..1f3ee6e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/check_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/check_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM16.95,10.23l-5.66,5.66c-0.39,0.39 -1.02,0.39 -1.41,0l-2.83,-2.83c-0.39,-0.39 -0.39,-1.02 0,-1.41c0.39,-0.39 1.02,-0.39 1.41,0l2.12,2.12l4.95,-4.95c0.39,-0.39 1.02,-0.39 1.41,0C17.34,9.21 17.34,9.84 16.95,10.23z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM9.29,16.29L5.7,12.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L10,14.17l6.88,-6.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-7.59,7.59c-0.38,0.39 -1.02,0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/check_circle_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/check_circle_outline.xml
index 70c3429..750def4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/check_circle_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/check_circle_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8c4.41,0 8,3.59 8,8S16.41,20 12,20zM15.54,8.82l-4.95,4.95l-2.12,-2.12c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l5.66,-5.66c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C16.56,8.43 15.93,8.43 15.54,8.82z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15.88,8.29L10,14.17l-1.88,-1.88c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.59,2.59c0.39,0.39 1.02,0.39 1.41,0L17.3,9.7c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.03,-0.39 -1.42,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/checklist.xml b/compose/material/material/icons/generator/raw-icons/rounded/checklist.xml
new file mode 100644
index 0000000..7e6900e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/checklist.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,8c0,-0.55 -0.45,-1 -1,-1h-7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h7C21.55,9 22,8.55 22,8zM13,16c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-7C13.45,15 13,15.45 13,16zM10.47,4.63c0.39,0.39 0.39,1.02 0,1.41l-4.23,4.25c-0.39,0.39 -1.02,0.39 -1.42,0L2.7,8.16c-0.39,-0.39 -0.39,-1.02 0,-1.41c0.39,-0.39 1.02,-0.39 1.41,0l1.42,1.42l3.54,-3.54C9.45,4.25 10.09,4.25 10.47,4.63zM10.48,12.64c0.39,0.39 0.39,1.02 0,1.41l-4.23,4.25c-0.39,0.39 -1.02,0.39 -1.42,0L2.7,16.16c-0.39,-0.39 -0.39,-1.02 0,-1.41s1.02,-0.39 1.41,0l1.42,1.42l3.54,-3.54C9.45,12.25 10.09,12.25 10.48,12.64L10.48,12.64z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/checklist_rtl.xml b/compose/material/material/icons/generator/raw-icons/rounded/checklist_rtl.xml
new file mode 100644
index 0000000..74735f1
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/checklist_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,8c0,-0.55 -0.45,-1 -1,-1H3C2.45,7 2,7.45 2,8s0.45,1 1,1h7C10.55,9 11,8.55 11,8zM11,16c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h7C10.55,17 11,16.55 11,16zM17.05,10.29c-0.39,0.39 -1.02,0.39 -1.41,0l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41L17.05,10.29zM17.05,18.29c-0.39,0.39 -1.02,0.39 -1.41,0l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41L17.05,18.29z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/chevron_left.xml b/compose/material/material/icons/generator/raw-icons/rounded/chevron_left.xml
index 98fa8dd..19d7e41 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/chevron_left.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/chevron_left.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.29,15.46l-3.88,-3.88l3.88,-3.88c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l0,0C15.67,16.49 15.68,15.85 15.29,15.46z"/>
+ android:pathData="M14.71,6.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.71,11.3c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L10.83,12l3.88,-3.88c0.39,-0.39 0.38,-1.03 0,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/chevron_right.xml b/compose/material/material/icons/generator/raw-icons/rounded/chevron_right.xml
index 87a210f..005a561 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/chevron_right.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/chevron_right.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9.29,15.46l3.88,-3.88L9.29,7.7c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l4.59,4.59c0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0l0,0C8.91,16.49 8.9,15.85 9.29,15.46z"/>
+ android:pathData="M9.29,6.71c-0.39,0.39 -0.39,1.02 0,1.41L13.17,12l-3.88,3.88c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L10.7,6.7c-0.38,-0.38 -1.02,-0.38 -1.41,0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/child_care.xml b/compose/material/material/icons/generator/raw-icons/rounded/child_care.xml
index d94f0fd..f3f1390 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/child_care.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/child_care.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.25,10.5c0,-0.69 0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25s-0.56,1.25 -1.25,1.25S13.25,11.19 13.25,10.5zM9.5,11.75c0.69,0 1.25,-0.56 1.25,-1.25S10.19,9.25 9.5,9.25S8.25,9.81 8.25,10.5S8.81,11.75 9.5,11.75zM12,17c2.01,0 3.74,-1.23 4.5,-3h-9C8.26,15.77 9.99,17 12,17zM21,12c0,4.97 -4.03,9 -9,9s-9,-4.03 -9,-9s4.03,-9 9,-9c0.09,0 0.18,0.01 0.27,0.01C12.31,3.01 12.36,3 12.4,3v0.02C17.19,3.23 21,7.17 21,12zM12.4,8.5c-1.52,0 -2.75,-1.23 -2.75,-2.75c0,-0.12 0.02,-0.23 0.04,-0.35C6.96,6.36 5,8.95 5,12c0,3.86 3.14,7 7,7s7,-3.14 7,-7s-3.14,-7 -7,-7c-0.2,0 -0.4,0.01 -0.59,0.03c-0.15,0.21 -0.26,0.45 -0.26,0.72C11.15,6.44 11.71,7 12.4,7c0.17,0 0.34,-0.03 0.48,-0.1c0.27,-0.12 0.58,-0.08 0.79,0.13l0,0c0.38,0.38 0.28,1.04 -0.21,1.25C13.14,8.42 12.78,8.5 12.4,8.5z"/>
+ android:pathData="M14.5,10.5m-1.25,0a1.25,1.25 0,1 1,2.5 0a1.25,1.25 0,1 1,-2.5 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9.5,10.5m-1.25,0a1.25,1.25 0,1 1,2.5 0a1.25,1.25 0,1 1,-2.5 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.1,14L7.9,14c-0.19,0 -0.32,0.2 -0.23,0.37C8.5,15.94 10.13,17 12,17s3.5,-1.06 4.33,-2.63c0.08,-0.17 -0.05,-0.37 -0.23,-0.37zM22.94,11.34c-0.25,-1.51 -1.36,-2.74 -2.81,-3.17 -0.53,-1.12 -1.28,-2.1 -2.19,-2.91C16.36,3.85 14.28,3 12,3s-4.36,0.85 -5.94,2.26c-0.92,0.81 -1.67,1.8 -2.19,2.91 -1.45,0.43 -2.56,1.65 -2.81,3.17 -0.04,0.21 -0.06,0.43 -0.06,0.66 0,0.23 0.02,0.45 0.06,0.66 0.25,1.51 1.36,2.74 2.81,3.17 0.52,1.11 1.27,2.09 2.17,2.89C7.62,20.14 9.71,21 12,21s4.38,-0.86 5.97,-2.28c0.9,-0.8 1.65,-1.79 2.17,-2.89 1.44,-0.43 2.55,-1.65 2.8,-3.17 0.04,-0.21 0.06,-0.43 0.06,-0.66 0,-0.23 -0.02,-0.45 -0.06,-0.66zM19,14c-0.1,0 -0.19,-0.02 -0.29,-0.03 -0.2,0.67 -0.49,1.29 -0.86,1.86C16.6,17.74 14.45,19 12,19s-4.6,-1.26 -5.85,-3.17c-0.37,-0.57 -0.66,-1.19 -0.86,-1.86 -0.1,0.01 -0.19,0.03 -0.29,0.03 -1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2c0.1,0 0.19,0.02 0.29,0.03 0.2,-0.67 0.49,-1.29 0.86,-1.86C7.4,6.26 9.55,5 12,5s4.6,1.26 5.85,3.17c0.37,0.57 0.66,1.19 0.86,1.86 0.1,-0.01 0.19,-0.03 0.29,-0.03 1.1,0 2,0.9 2,2s-0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/child_friendly.xml b/compose/material/material/icons/generator/raw-icons/rounded/child_friendly.xml
index 8e094bb..81ecfbc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/child_friendly.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/child_friendly.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.5,20.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.5,20.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.98,2.65c-2.85,-1.26 -6.12,-0.36 -7.39,0.26L13.5,7.6l3.74,-3.28C17.79,3.84 17.65,2.94 16.98,2.65z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.77,16.36L8.57,4.03C7.93,3.27 7.05,2 5.39,2C3.98,2 2.76,2.89 2.26,4.15C2,4.79 2.52,5.48 3.21,5.48h0c0.4,0 0.76,-0.23 0.91,-0.6C4.33,4.36 4.82,4 5.39,4C6.07,4 6.42,4.59 7,5.27V13c0,2.75 2.25,5 5,5h6C18.85,18 19.31,17.01 18.77,16.36z"/>
+ android:pathData="M13,3.08L13,10h8c0,-4.03 -2.98,-7.37 -6.86,-7.92 -0.6,-0.09 -1.14,0.39 -1.14,1zM19.32,15.89C20.37,14.54 21,12.84 21,11L6.44,11l-0.68,-1.43C5.6,9.22 5.24,9 4.86,9L3,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.22s1.89,4.07 2.12,4.42c-1.33,0.71 -2.14,2.27 -1.74,3.94 0.3,1.26 1.34,2.27 2.6,2.55 2.1,0.46 3.98,-0.96 4.25,-2.91h2.08c0.27,1.94 2.14,3.36 4.22,2.92 1.27,-0.27 2.31,-1.27 2.63,-2.53 0.35,-1.39 -0.14,-2.68 -1.06,-3.5zM8,20c-0.83,0 -1.5,-0.67 -1.5,-1.5S7.17,17 8,17s1.5,0.67 1.5,1.5S8.83,20 8,20zM17,20c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.17,17 17,17s1.5,0.67 1.5,1.5S17.83,20 17,20z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/chrome_reader_mode.xml b/compose/material/material/icons/generator/raw-icons/rounded/chrome_reader_mode.xml
index ccd0bba..eb50835 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/chrome_reader_mode.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/chrome_reader_mode.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,18h-7V6h7V18zM14.75,8.5h3.5C18.66,8.5 19,8.84 19,9.25v0C19,9.66 18.66,10 18.25,10h-3.5C14.34,10 14,9.66 14,9.25v0C14,8.84 14.34,8.5 14.75,8.5zM14.75,11h3.5c0.41,0 0.75,0.34 0.75,0.75v0c0,0.41 -0.34,0.75 -0.75,0.75h-3.5c-0.41,0 -0.75,-0.34 -0.75,-0.75v0C14,11.34 14.34,11 14.75,11zM14.75,13.5h3.5c0.41,0 0.75,0.34 0.75,0.75v0c0,0.41 -0.34,0.75 -0.75,0.75h-3.5C14.34,15 14,14.66 14,14.25v0C14,13.84 14.34,13.5 14.75,13.5z"/>
+ android:pathData="M21,4L3,4c-1.1,0 -2,0.9 -2,2v13c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,6c0,-1.1 -0.9,-2 -2,-2zM21,18c0,0.55 -0.45,1 -1,1h-8L12,6h8c0.55,0 1,0.45 1,1v11zM19.25,9.5h-5.5c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75h5.5c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75zM19.25,12h-5.5c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75h5.5c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75zM19.25,14.5h-5.5c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75h5.5c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/clear.xml b/compose/material/material/icons/generator/raw-icons/rounded/clear.xml
index a864ec28..57511cc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/clear.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/clear.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.3,5.71L18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59L7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L10.59,12L5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89C18.68,6.73 18.68,6.09 18.3,5.71z"/>
+ android:pathData="M18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/clear_all.xml b/compose/material/material/icons/generator/raw-icons/rounded/clear_all.xml
index 57ad8a2..b107039 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/clear_all.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/clear_all.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,13h12c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1l0,0C5,12.55 5.45,13 6,13zM4,17h12c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,16.55 3.45,17 4,17zM7,8L7,8c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C7.45,7 7,7.45 7,8z"/>
+ android:pathData="M6,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,17h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM7,8c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,7c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/close.xml b/compose/material/material/icons/generator/raw-icons/rounded/close.xml
index a864ec28..57511cc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/close.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/close.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.3,5.71L18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59L7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L10.59,12L5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89C18.68,6.73 18.68,6.09 18.3,5.71z"/>
+ android:pathData="M18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/closed_caption.xml b/compose/material/material/icons/generator/raw-icons/rounded/closed_caption.xml
index 3127efa..0c564e2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/closed_caption.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/closed_caption.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4H5C3.89,4 3,4.9 3,6v12c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM11,10.5c0,0.28 -0.22,0.5 -0.5,0.5H10c-0.28,0 -0.5,-0.22 -0.5,-0.5h-2v3h2c0,-0.28 0.22,-0.5 0.5,-0.5h0.5c0.28,0 0.5,0.22 0.5,0.5V14c0,0.55 -0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1V10.5zM18,10.5c0,0.28 -0.22,0.5 -0.5,0.5H17c-0.28,0 -0.5,-0.22 -0.5,-0.5h-2v3h2c0,-0.28 0.22,-0.5 0.5,-0.5h0.5c0.28,0 0.5,0.22 0.5,0.5V14c0,0.55 -0.45,1 -1,1h-3c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1V10.5z"/>
+ android:pathData="M19,4L5,4c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM11,10.5c0,0.28 -0.22,0.5 -0.5,0.5L10,11c-0.28,0 -0.5,-0.22 -0.5,-0.5h-2v3h2c0,-0.28 0.22,-0.5 0.5,-0.5h0.5c0.28,0 0.5,0.22 0.5,0.5v0.5c0,0.55 -0.45,1 -1,1L7,15c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v0.5zM18,10.5c0,0.28 -0.22,0.5 -0.5,0.5L17,11c-0.28,0 -0.5,-0.22 -0.5,-0.5h-2v3h2c0,-0.28 0.22,-0.5 0.5,-0.5h0.5c0.28,0 0.5,0.22 0.5,0.5v0.5c0,0.55 -0.45,1 -1,1h-3c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cloud.xml b/compose/material/material/icons/generator/raw-icons/rounded/cloud.xml
index fc838b5..6f2f5cf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cloud.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cloud.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7C8.78,4 6.07,6.18 5.26,9.15C2.82,9.71 1,11.89 1,14.5C1,17.54 3.46,20 6.5,20c1.76,0 10.25,0 12,0l0,0c2.49,-0.01 4.5,-2.03 4.5,-4.52C23,13.15 21.25,11.26 19,11z"/>
+ android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cloud_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/cloud_circle.xml
index ef2d3d8..feaa819 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cloud_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cloud_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM16,16c-1.2,0 -6.29,0 -7.5,0C6.57,16 5,14.43 5,12.5c0,-1.86 1.46,-3.37 3.29,-3.48C8.88,7.55 10.31,6.5 12,6.5c2.04,0 3.75,1.53 4,3.5c1.66,0 3,1.34 3,3S17.66,16 16,16z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM16.5,16L8,16c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3h0.14c0.44,-1.73 1.99,-3 3.86,-3 2.21,0 4,1.79 4,4h0.5c1.38,0 2.5,1.12 2.5,2.5S17.88,16 16.5,16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cloud_done.xml b/compose/material/material/icons/generator/raw-icons/rounded/cloud_done.xml
index fcd0e62..1fd8d8f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cloud_done.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cloud_done.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7C8.78,4 6.07,6.18 5.26,9.15C2.82,9.71 1,11.89 1,14.5C1,17.54 3.46,20 6.5,20c1.76,0 10.25,0 12,0l0,0c2.49,-0.01 4.5,-2.03 4.5,-4.52C23,13.15 21.25,11.26 19,11zM9.64,16.29l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-4.24,4.24C10.66,16.68 10.03,16.68 9.64,16.29z"/>
+ android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM10.71,16.29c-0.39,0.39 -1.02,0.39 -1.41,0L7.2,14.2c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L10,14.18l4.48,-4.48c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-5.18,5.18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cloud_download.xml b/compose/material/material/icons/generator/raw-icons/rounded/cloud_download.xml
index 0ba8cad..7e25c04 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cloud_download.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cloud_download.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7C8.78,4 6.07,6.18 5.26,9.15C2.82,9.71 1,11.89 1,14.5C1,17.54 3.46,20 6.5,20c1.76,0 10.25,0 12,0l0,0c2.49,-0.01 4.5,-2.03 4.5,-4.52C23,13.15 21.25,11.26 19,11zM14.79,13c0.45,0 0.67,0.54 0.35,0.85l-2.79,2.79c-0.2,0.2 -0.51,0.2 -0.71,0l-2.79,-2.79C8.54,13.54 8.76,13 9.21,13H11v-3c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3H14.79z"/>
+ android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-4.65,4.65c-0.2,0.2 -0.51,0.2 -0.71,0L7,13h3V9h4v4h3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cloud_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/cloud_off.xml
index 75532f3..76cace1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cloud_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cloud_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7c-1.47,0 -2.81,0.47 -3.93,1.24l13.51,13.51c0.87,-0.82 1.42,-1.98 1.42,-3.28C23,13.15 21.25,11.26 19,11zM2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l3.44,3.44c-0.1,0.26 -0.21,0.51 -0.28,0.78c-2.56,0.59 -4.44,2.97 -4.24,5.76C1.22,17.82 3.8,20 6.73,20l10.44,0l1.9,1.9c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51L2.1,3.51z"/>
+ android:pathData="M24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96C18.67,6.59 15.64,4 12,4c-1.33,0 -2.57,0.36 -3.65,0.97l1.49,1.49C10.51,6.17 11.23,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,0.99 -0.48,1.85 -1.21,2.4l1.41,1.41c1.09,-0.92 1.8,-2.27 1.8,-3.81zM3.71,4.56c-0.39,0.39 -0.39,1.02 0,1.41l2.06,2.06h-0.42c-3.28,0.35 -5.76,3.34 -5.29,6.79C0.46,17.84 3.19,20 6.22,20h11.51l1.29,1.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.12,4.56c-0.39,-0.39 -1.02,-0.39 -1.41,0zM6,18c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73l8,8H6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cloud_queue.xml b/compose/material/material/icons/generator/raw-icons/rounded/cloud_queue.xml
index e12604d..8f71d61 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cloud_queue.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cloud_queue.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7C8.78,4 6.07,6.18 5.26,9.15C2.82,9.71 1,11.89 1,14.5C1,17.54 3.46,20 6.5,20c1.76,0 10.25,0 12,0l0,0c2.49,-0.01 4.5,-2.03 4.5,-4.52C23,13.15 21.25,11.26 19,11zM18.5,18c-0.82,0 -10.41,0 -12,0C4.57,18 3,16.43 3,14.5S4.57,11 6.5,11C7,11 7,11 7,11c0,-2.76 2.24,-5 5,-5s5,2.24 5,5v2c0,0 1.33,0 1.5,0c1.38,0 2.5,1.12 2.5,2.5C21,16.88 19.88,18 18.5,18z"/>
+ android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM19,18H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h0.71C7.37,7.69 9.48,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3s-1.34,3 -3,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cloud_upload.xml b/compose/material/material/icons/generator/raw-icons/rounded/cloud_upload.xml
index 57ba6ac..775e18c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/cloud_upload.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cloud_upload.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7C8.78,4 6.07,6.18 5.26,9.15C2.82,9.71 1,11.89 1,14.5C1,17.54 3.46,20 6.5,20c1.76,0 10.25,0 12,0l0,0c2.49,-0.01 4.5,-2.03 4.5,-4.52C23,13.15 21.25,11.26 19,11zM13,13v3c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-3H9.21c-0.45,0 -0.67,-0.54 -0.35,-0.85l2.79,-2.79c0.2,-0.2 0.51,-0.2 0.71,0l2.79,2.79c0.31,0.31 0.09,0.85 -0.35,0.85H13z"/>
+ android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l4.65,-4.65c0.2,-0.2 0.51,-0.2 0.71,0L17,13h-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/co2.xml b/compose/material/material/icons/generator/raw-icons/rounded/co2.xml
new file mode 100644
index 0000000..362f287
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/co2.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,9h-3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-4C15,9.45 14.55,9 14,9zM13.5,13.5h-2v-3h2V13.5zM20.5,15.5h-2v1h2.25c0.41,0 0.75,0.34 0.75,0.75l0,0c0,0.41 -0.34,0.75 -0.75,0.75H18c-0.55,0 -1,-0.45 -1,-1v-1.5c0,-0.55 0.45,-1 1,-1h2v-1h-2.25c-0.41,0 -0.75,-0.34 -0.75,-0.75v0c0,-0.41 0.34,-0.75 0.75,-0.75h2.75c0.55,0 1,0.45 1,1v1.5C21.5,15.05 21.05,15.5 20.5,15.5zM8,14c0,0.55 -0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v0.25C8,10.66 7.66,11 7.25,11c-0.33,0 -0.6,-0.21 -0.71,-0.5c0,0 -2.04,0 -2.04,0v3l2.04,0c0.1,-0.29 0.38,-0.5 0.71,-0.5C7.66,13 8,13.34 8,13.75V14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/code.xml b/compose/material/material/icons/generator/raw-icons/rounded/code.xml
index 076b257..14302a8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/code.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/code.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.7,15.9L4.8,12l3.9,-3.9c0.39,-0.39 0.39,-1.01 0,-1.4s-1.01,-0.39 -1.4,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.6c0.39,0.39 1.01,0.39 1.4,0S9.09,16.29 8.7,15.9zM15.3,15.9l3.9,-3.9l-3.9,-3.9c-0.39,-0.39 -0.39,-1.01 0,-1.4s1.01,-0.39 1.4,0l4.59,4.59c0.39,0.39 0.39,1.02 0,1.41l-4.59,4.6c-0.39,0.39 -1.01,0.39 -1.4,0C14.91,16.91 14.91,16.29 15.3,15.9z"/>
+ android:pathData="M8.7,15.9L4.8,12l3.9,-3.9c0.39,-0.39 0.39,-1.01 0,-1.4 -0.39,-0.39 -1.01,-0.39 -1.4,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.6c0.39,0.39 1.01,0.39 1.4,0 0.39,-0.39 0.39,-1.01 0,-1.4zM15.3,15.9l3.9,-3.9 -3.9,-3.9c-0.39,-0.39 -0.39,-1.01 0,-1.4 0.39,-0.39 1.01,-0.39 1.4,0l4.59,4.59c0.39,0.39 0.39,1.02 0,1.41l-4.59,4.6c-0.39,0.39 -1.01,0.39 -1.4,0 -0.39,-0.39 -0.39,-1.01 0,-1.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/collections.xml b/compose/material/material/icons/generator/raw-icons/rounded/collections.xml
index f9ae294..6690de0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/collections.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/collections.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM9.6,13.2l1.38,-1.83c0.2,-0.27 0.6,-0.27 0.8,0L13,13l2.23,-2.97c0.2,-0.27 0.6,-0.27 0.8,0l2.38,3.17c0.25,0.33 0.01,0.8 -0.4,0.8h-8C9.59,14 9.35,13.53 9.6,13.2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M22,16L22,4c0,-1.1 -0.9,-2 -2,-2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zM11.4,12.53l1.63,2.18 2.58,-3.22c0.2,-0.25 0.58,-0.25 0.78,0l2.96,3.7c0.26,0.33 0.03,0.81 -0.39,0.81L9,16c-0.41,0 -0.65,-0.47 -0.4,-0.8l2,-2.67c0.2,-0.26 0.6,-0.26 0.8,0zM2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/collections_bookmark.xml b/compose/material/material/icons/generator/raw-icons/rounded/collections_bookmark.xml
index 66cbfa4..6109c4c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/collections_bookmark.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/collections_bookmark.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.56,6 3,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17.24,10.55L15.5,9.5l-1.74,1.05c-0.33,0.2 -0.76,-0.04 -0.76,-0.43V4h5v6.12C18,10.51 17.57,10.75 17.24,10.55z"/>
+ android:pathData="M17,20L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,12l-2.5,-1.5L15,12L15,4h5v8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/color_lens.xml b/compose/material/material/icons/generator/raw-icons/rounded/color_lens.xml
index 0d97f03..4bf1550 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/color_lens.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/color_lens.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10c1.38,0 2.5,-1.12 2.5,-2.5c0,-0.61 -0.23,-1.2 -0.64,-1.67c-0.08,-0.1 -0.13,-0.21 -0.13,-0.33c0,-0.28 0.22,-0.5 0.5,-0.5H16c3.31,0 6,-2.69 6,-6C22,6.04 17.51,2 12,2zM17.5,13c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C19,12.33 18.33,13 17.5,13zM14.5,9C13.67,9 13,8.33 13,7.5C13,6.67 13.67,6 14.5,6S16,6.67 16,7.5C16,8.33 15.33,9 14.5,9zM5,11.5C5,10.67 5.67,10 6.5,10S8,10.67 8,11.5C8,12.33 7.33,13 6.5,13S5,12.33 5,11.5zM11,7.5C11,8.33 10.33,9 9.5,9S8,8.33 8,7.5C8,6.67 8.67,6 9.5,6S11,6.67 11,7.5z"/>
+ android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/colorize.xml b/compose/material/material/icons/generator/raw-icons/rounded/colorize.xml
index 9686a1a..3cbf6d0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/colorize.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/colorize.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.1,3.1l-1.22,-1.21c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l0.71,0.72l-8.64,8.62C3.11,16.13 3,16.39 3,16.65V20c0,0.55 0.45,1 1,1h3.35c0.27,0 0.52,-0.11 0.71,-0.29l8.63,-8.64l0.72,0.71c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-1.22,-1.22l3.11,-3.11C21.1,6.65 21.1,6.02 20.71,5.63zM6.93,19H5v-1.93l8.34,-8.33l1.92,1.92L6.93,19z"/>
+ android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.12,3.12 -1.23,-1.21c-0.39,-0.39 -1.02,-0.38 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l0.72,0.72 -8.77,8.77c-0.1,0.1 -0.15,0.22 -0.15,0.36v4.04c0,0.28 0.22,0.5 0.5,0.5h4.04c0.13,0 0.26,-0.05 0.35,-0.15l8.77,-8.77 0.72,0.72c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41l-1.22,-1.22 3.12,-3.12c0.41,-0.4 0.41,-1.03 0.02,-1.42zM6.92,19L5,17.08l8.06,-8.06 1.92,1.92L6.92,19z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/comment.xml b/compose/material/material/icons/generator/raw-icons/rounded/comment.xml
index 95ee93b..e567d1b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/comment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/comment.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,4v12c0,1.1 0.9,2 2,2h14l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71L21.99,4c0,-1.1 -0.9,-2 -2,-2H4C2.9,2 2,2.9 2,4zM18,10L18,10c0,0.55 -0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h10C17.55,9 18,9.45 18,10zM18,13L18,13c0,0.55 -0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h10C17.55,12 18,12.45 18,13zM6,7L6,7c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H7C6.45,8 6,7.55 6,7z"/>
+ android:pathData="M21.99,4c0,-1.1 -0.89,-2 -1.99,-2L4,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4 -0.01,-18zM17,14L7,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,11L7,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,8L7,8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/comments_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/comments_disabled.xml
new file mode 100644
index 0000000..781d785
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/comments_disabled.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M1.39,2.81C1,3.2 1,3.83 1.39,4.22L2,4.83V16c0,1.1 0.9,2 2,2h11.17l4.61,4.61c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81C2.42,2.42 1.78,2.42 1.39,2.81zM6.38,9.21L8.17,11H7c-0.55,0 -1,-0.45 -1,-1C6,9.68 6.15,9.4 6.38,9.21zM7,14c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h2.17l2,2H7zM14.83,12l-1,-1H17c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-5.17l-1,-1H17c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H8.83l-4,-4H20c1.1,0 2,0.9 2,2v15.17L16.83,14H17c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H14.83z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/commute.xml b/compose/material/material/icons/generator/raw-icons/rounded/commute.xml
index c3c6d3a..9f9732e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/commute.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/commute.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.61,9.67C20.47,9.28 20.1,9 19.66,9h-7.33c-0.44,0 -0.8,0.28 -0.94,0.67L10,13.66v5.67C10,19.7 10.3,20 10.66,20h0.67C11.7,20 12,19.7 12,19.33V18.5h8v0.83C20,19.7 20.3,20 20.66,20h0.67C21.7,20 22,19.7 22,19.34v-5.67L20.61,9.67zM13,16.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S13.55,16.5 13,16.5zM19,16.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S19.55,16.5 19,16.5zM11.99,12.5l0.7,-2h6.62l0.69,2H11.99z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,13V7h9v1h2V7c0,-2.84 -2.91,-3 -6.5,-3C5.25,4 2,4.16 2,7l0,0v8c0,1.66 1.34,3 3,3l-1,1v1h5l0,-7H4zM5,16c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1c0.55,0 1,0.45 1,1C6,15.55 5.55,16 5,16z"/>
+ android:pathData="M12,4L5,4C3.34,4 2,5.34 2,7v8c0,1.66 1.34,3 3,3l-0.77,0.77c-0.28,0.28 -0.28,0.72 0,1s0.72,0.28 1,0L7,18h2v-5L4.5,13c-0.28,0 -0.5,-0.22 -0.5,-0.5v-6c0,-0.28 0.22,-0.5 0.5,-0.5h8c0.28,0 0.5,0.22 0.5,0.5L13,8h2L15,7c0,-1.66 -1.34,-3 -3,-3zM5,14c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM20.57,9.66c-0.14,-0.4 -0.52,-0.66 -0.97,-0.66h-7.19c-0.46,0 -0.83,0.26 -0.98,0.66l-1.42,4.11v5.24c0,0.55 0.45,0.99 1,0.99s1,-0.45 1,-1v-1h8v1c0,0.55 0.45,1 1,1s0.99,-0.44 1,-0.99L22,13.77l-1.43,-4.11zM12.77,10h6.48c0.21,0 0.4,0.14 0.47,0.34l0.69,2c0.11,0.32 -0.13,0.66 -0.47,0.66h-7.85c-0.34,0 -0.58,-0.34 -0.47,-0.66l0.69,-2c0.05,-0.2 0.24,-0.34 0.46,-0.34zM12,16c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM20,16c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/compare.xml b/compose/material/material/icons/generator/raw-icons/rounded/compare.xml
index 1d3ba24..d03f133 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/compare.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/compare.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1V3zM10,18H5l5,-6V18zM19,3h-5v2h4c0.55,0 1,0.45 1,1v12l-5,-6v9h5c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3z"/>
+ android:pathData="M10,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1L12,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1zM10,18L5,18l5,-6v6zM19,3h-5v2h4c0.55,0 1,0.45 1,1v12l-5,-6v9h5c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/compare_arrows.xml b/compose/material/material/icons/generator/raw-icons/rounded/compare_arrows.xml
index 3122243..03a1773 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/compare_arrows.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/compare_arrows.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M9.01,14H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6.01v1.79c0,0.45 0.54,0.67 0.85,0.35l2.78,-2.79c0.19,-0.2 0.19,-0.51 0,-0.71l-2.78,-2.79c-0.31,-0.32 -0.85,-0.09 -0.85,0.35V14zM14.99,11.79V10H21c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-6.01V6.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.78,2.79c-0.19,0.2 -0.19,0.51 0,0.71l2.78,2.79C14.45,12.46 14.99,12.24 14.99,11.79z"/>
+ android:pathData="M9.01,14L3,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6.01v1.79c0,0.45 0.54,0.67 0.85,0.35l2.78,-2.79c0.19,-0.2 0.19,-0.51 0,-0.71l-2.78,-2.79c-0.31,-0.32 -0.85,-0.09 -0.85,0.35L9.01,14zM14.99,11.79L14.99,10L21,10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-6.01L14.99,6.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.78,2.79c-0.19,0.2 -0.19,0.51 0,0.71l2.78,2.79c0.31,0.31 0.85,0.09 0.85,-0.36z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/compass_calibration.xml b/compose/material/material/icons/generator/raw-icons/rounded/compass_calibration.xml
index 84d4dde..2310390 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/compass_calibration.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/compass_calibration.xml
@@ -9,5 +9,5 @@
android:pathData="M12,17m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,3C8.49,3 5.28,4.29 2.8,6.41C2.36,6.79 2.32,7.47 2.74,7.89l3.6,3.6c0.36,0.36 0.92,0.39 1.32,0.08c1.2,-0.94 2.71,-1.5 4.34,-1.5c1.64,0 3.14,0.56 4.34,1.49c0.4,0.31 0.96,0.28 1.31,-0.08l3.6,-3.6c0.42,-0.42 0.38,-1.1 -0.07,-1.48C18.72,4.28 15.51,3 12,3z"/>
+ android:pathData="M12,3C8.49,3 5.28,4.29 2.8,6.41c-0.44,0.38 -0.48,1.06 -0.06,1.48l3.6,3.6c0.36,0.36 0.92,0.39 1.32,0.08 1.2,-0.94 2.71,-1.5 4.34,-1.5 1.64,0 3.14,0.56 4.34,1.49 0.4,0.31 0.96,0.28 1.31,-0.08l3.6,-3.6c0.42,-0.42 0.38,-1.1 -0.07,-1.48C18.72,4.28 15.51,3 12,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/compost.xml b/compose/material/material/icons/generator/raw-icons/rounded/compost.xml
new file mode 100644
index 0000000..16215d4
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/compost.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.73,21.5c-4.95,-0.14 -9.08,-4.27 -9.22,-9.22C2.35,6.91 6.67,2.5 12,2.5V1.21c0,-0.45 0.54,-0.67 0.85,-0.35l2.79,2.79c0.2,0.2 0.2,0.51 0,0.71l-2.79,2.79C12.54,7.46 12,7.24 12,6.79V5.5c-3.58,0 -6.5,2.92 -6.5,6.5c0,2.21 1.11,4.17 2.81,5.35c0.51,-0.92 1.63,-1.62 2.98,-1.8c-0.09,-0.69 -0.26,-1.42 -0.49,-2.03c-0.33,0.28 -0.75,0.46 -1.22,0.48c-1.14,0.05 -2.08,-0.99 -2.08,-2.13l0,-0.86c0,-0.29 -0.05,-0.57 -0.14,-0.83C7.24,9.84 7.5,9.49 7.86,9.52c1.3,0.09 3.6,0.52 3.64,2.48c0,0.29 -0.06,0.56 -0.17,0.8C10.91,12.48 10.47,12.2 10,12c0.58,0.43 1.37,1.37 2,2.6c0.67,-1.62 1.68,-3.27 3,-4.6c-0.76,0.52 -1.47,1.12 -2.13,1.81c-0.26,-0.42 -0.4,-0.93 -0.36,-1.47C12.59,9 13.79,8 15.13,8L16,8c0.56,0 0.97,-0.14 1.28,-0.31c0.34,-0.19 0.76,0.05 0.75,0.44C17.99,9.87 17.56,13 15,13c-0.49,0 -0.94,-0.14 -1.32,-0.38c-0.24,0.64 -0.59,1.76 -0.76,2.96c1.26,0.22 2.28,0.89 2.77,1.77c1.57,-1.09 2.64,-2.85 2.79,-4.87C18.5,12.22 18.71,12 18.98,12l1.82,0c0.47,0 0.71,0.24 0.69,0.52C21.21,17.61 16.91,21.64 11.73,21.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/computer.xml b/compose/material/material/icons/generator/raw-icons/rounded/computer.xml
index d4bfea5..904b0b9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/computer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/computer.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h16c1.1,0 1.99,-0.9 1.99,-2L22,5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v11C2,17.1 2.9,18 4,18zM4,5h16v11H4V5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1,20L1,20c0,0.55 0.45,1 1,1h20c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H2C1.45,19 1,19.45 1,20z"/>
+ android:pathData="M20,18c1.1,0 1.99,-0.9 1.99,-2L22,6c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2H1c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h22c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3zM5,6h14c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/confirmation_number.xml b/compose/material/material/icons/generator/raw-icons/rounded/confirmation_number.xml
index 52de72c..48af3ad 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/confirmation_number.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/confirmation_number.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,10V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2.01,4.89 2.01,6l0,4C3.11,10 4,10.9 4,12c0,1.1 -0.89,2 -2,2l0,4c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-4c-1.1,-0.02 -2,-0.91 -2,-2S20.9,10.01 22,10zM12,17.5L12,17.5c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,17.05 12.55,17.5 12,17.5zM12,13L12,13c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,12.55 12.55,13 12,13zM12,8.5L12,8.5c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,8.05 12.55,8.5 12,8.5z"/>
+ android:pathData="M22,8.54L22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -1.99,0.89 -1.99,2v2.54c0,0.69 0.33,1.37 0.94,1.69C3.58,10.58 4,11.24 4,12s-0.43,1.43 -1.06,1.76c-0.6,0.33 -0.94,1.01 -0.94,1.7L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-2.54c0,-0.69 -0.34,-1.37 -0.94,-1.7 -0.63,-0.34 -1.06,-1 -1.06,-1.76s0.43,-1.42 1.06,-1.76c0.6,-0.33 0.94,-1.01 0.94,-1.7zM13,17.5h-2v-2h2v2zM13,13h-2v-2h2v2zM13,8.5h-2v-2h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/connecting_airports.xml b/compose/material/material/icons/generator/raw-icons/rounded/connecting_airports.xml
new file mode 100644
index 0000000..463e0af
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/connecting_airports.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.93,10.6c0.39,0 0.66,0.37 0.55,0.74L15.4,15h2.85l0.59,-0.78c0.1,-0.14 0.26,-0.22 0.43,-0.22c0.36,0 0.62,0.35 0.52,0.7L19.4,16l0.39,1.3c0.1,0.35 -0.16,0.7 -0.52,0.7c-0.17,0 -0.33,-0.08 -0.43,-0.22L18.25,17H15.4l1.08,3.66c0.11,0.37 -0.17,0.74 -0.55,0.74c-0.2,0 -0.39,-0.11 -0.5,-0.28L13,17h-2.97c-0.53,0 -1,-0.4 -1.03,-0.93C8.96,15.48 9.43,15 10,15h3l2.43,-4.12C15.54,10.71 15.73,10.6 15.93,10.6zM8.07,2.6c-0.39,0 -0.66,0.37 -0.55,0.74L8.6,7H5.75L5.16,6.22C5.06,6.08 4.9,6 4.73,6C4.37,6 4.11,6.35 4.21,6.7L4.6,8L4.21,9.3C4.11,9.65 4.37,10 4.73,10c0.17,0 0.33,-0.08 0.43,-0.22L5.75,9H8.6l-1.08,3.66c-0.11,0.37 0.17,0.74 0.55,0.74c0.2,0 0.39,-0.11 0.5,-0.28L11,9h2.97c0.53,0 1,-0.4 1.03,-0.93C15.04,7.48 14.57,7 14,7h-3L8.57,2.88C8.46,2.71 8.27,2.6 8.07,2.6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/construction.xml b/compose/material/material/icons/generator/raw-icons/rounded/construction.xml
index 92043a8..e7cd3a6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/construction.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/construction.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.41,15.54l4.4,4.4c0.59,0.59 1.54,0.59 2.12,0l0,0c0.59,-0.59 0.59,-1.54 0,-2.12l-4.4,-4.4L13.41,15.54z"/>
+ android:pathData="M20.99,17.99l-4.94,-4.94l-2.12,2.12l4.94,4.94c0.59,0.59 1.54,0.59 2.12,0C21.57,19.52 21.57,18.57 20.99,17.99z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M16.34,9.79c0.88,0.31 1.89,0.36 3.03,-0.39c0.79,-0.52 1.4,-1.32 1.57,-2.25c0.14,-0.75 0.03,-1.45 -0.25,-2.07L18.27,7.5L16.5,5.73l2.43,-2.43c-0.62,-0.28 -1.33,-0.39 -2.08,-0.25c-0.93,0.18 -1.73,0.79 -2.25,1.58c-0.74,1.14 -0.69,2.14 -0.38,3.02L12,9.88l-1.69,-1.69l0,0c0.38,-0.38 0.38,-1 0,-1.38L9.75,6.25l2.32,-2.32C11.45,3.31 10.63,3 9.82,3C9,3 8.19,3.31 7.57,3.93L4.71,6.79c-0.39,0.39 -0.39,1.02 0,1.41l0.54,0.54H3.5c-0.19,0 -0.37,0.07 -0.5,0.21l0,0c-0.28,0.28 -0.28,0.72 0,1l2,2c0.28,0.28 0.72,0.28 1,0l0,0c0.13,-0.13 0.21,-0.31 0.21,-0.5V9.71l0.04,0.04l0.56,0.56c0.38,0.38 1,0.38 1.38,0l0,0L9.88,12l-5.82,5.82c-0.59,0.59 -0.59,1.54 0,2.12l0,0c0.59,0.59 1.54,0.59 2.12,0l5.38,-5.38L16.34,9.79z"/>
+ android:pathData="M17.65,10c1.93,0 3.5,-1.57 3.5,-3.5c0,-0.58 -0.16,-1.12 -0.41,-1.6l-2.7,2.7l-1.49,-1.49l2.7,-2.7C18.77,3.16 18.23,3 17.65,3c-1.93,0 -3.5,1.57 -3.5,3.5c0,0.41 0.08,0.8 0.21,1.16l-1.85,1.85l-1.78,-1.78l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-0.71,-0.71l2.12,-2.12c-1.17,-1.17 -3.07,-1.17 -4.24,0L5.08,6.32c-0.39,0.39 -0.39,1.02 0,1.41l0.71,0.71H3.25c-0.19,0 -0.37,0.07 -0.5,0.21c-0.28,0.28 -0.28,0.72 0,1l2.54,2.54c0.28,0.28 0.72,0.28 1,0c0.13,-0.13 0.21,-0.31 0.21,-0.5V9.15L7.2,9.85c0.39,0.39 1.02,0.39 1.41,0l1.78,1.78l-6.35,6.35c-0.59,0.59 -0.59,1.54 0,2.12v0c0.59,0.59 1.54,0.59 2.12,0L16.48,9.79C16.85,9.92 17.24,10 17.65,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/contact_mail.xml b/compose/material/material/icons/generator/raw-icons/rounded/contact_mail.xml
index 868798f..2abd447 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/contact_mail.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/contact_mail.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,8l0,-1l-2.5,1.75l-2.5,-1.75l0,1l2.5,1.75z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22,3H2C0.9,3 0,3.9 0,5v14c0,1.1 0.9,2 2,2h20c1.1,0 1.99,-0.9 1.99,-2L24,5C24,3.9 23.1,3 22,3zM9,8c1.65,0 3,1.35 3,3s-1.35,3 -3,3s-3,-1.35 -3,-3S7.35,8 9,8zM2.08,19c1.38,-2.39 3.96,-4 6.92,-4s5.54,1.61 6.92,4H2.08zM20,11h-5c-0.55,0 -1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1v3C21,10.55 20.55,11 20,11z"/>
+ android:pathData="M21,8L21,7l-3,2 -3,-2v1l2.72,1.82c0.17,0.11 0.39,0.11 0.55,0L21,8zM22,3L2,3C0.9,3 0,3.9 0,5v14c0,1.1 0.9,2 2,2h20c1.1,0 1.99,-0.9 1.99,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM8,6c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM14,18L2,18v-1c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1zM21.5,12h-7c-0.28,0 -0.5,-0.22 -0.5,-0.5v-5c0,-0.28 0.22,-0.5 0.5,-0.5h7c0.28,0 0.5,0.22 0.5,0.5v5c0,0.28 -0.22,0.5 -0.5,0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/contact_phone.xml b/compose/material/material/icons/generator/raw-icons/rounded/contact_phone.xml
index fa947fd..d3b2733 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/contact_phone.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/contact_phone.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,3H2C0.9,3 0,3.9 0,5v14c0,1.1 0.9,2 2,2h20c1.1,0 1.99,-0.9 1.99,-2L24,5C24,3.9 23.1,3 22,3zM9,8c1.65,0 3,1.35 3,3s-1.35,3 -3,3s-3,-1.35 -3,-3S7.35,8 9,8zM2.08,19c1.38,-2.39 3.96,-4 6.92,-4s5.54,1.61 6.92,4H2.08zM17.85,14.01h1.14c0.31,0 0.61,0.15 0.8,0.4l0.69,0.91c0.3,0.4 0.26,0.96 -0.09,1.31l-0.72,0.72c-0.39,0.39 -1.02,0.39 -1.41,0.01c-2.2,-2.13 -2.26,-4.8 -2.26,-5.35c0,-0.55 0.06,-3.22 2.26,-5.35c0.39,-0.38 1.02,-0.37 1.41,0.01l0.72,0.72c0.35,0.35 0.39,0.91 0.09,1.31l-0.69,0.91c-0.19,0.25 -0.48,0.4 -0.8,0.4h-1.14c-0.22,0.63 -0.35,1.3 -0.35,2S17.63,13.38 17.85,14.01z"/>
+ android:pathData="M22,3L2,3C0.9,3 0,3.9 0,5v14c0,1.1 0.9,2 2,2h20c1.1,0 1.99,-0.9 1.99,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM8,6c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM14,18L2,18v-1c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1zM17.85,14h1.39c0.16,0 0.3,0.07 0.4,0.2l1.1,1.45c0.15,0.2 0.13,0.48 -0.05,0.65l-1.36,1.36c-0.18,0.18 -0.48,0.2 -0.67,0.04 -1.13,-0.96 -1.97,-2.25 -2.38,-3.71 -0.18,-0.63 -0.28,-1.3 -0.28,-1.99s0.1,-1.36 0.28,-2c0.41,-1.47 1.25,-2.75 2.38,-3.71 0.2,-0.17 0.49,-0.14 0.67,0.04l1.36,1.36c0.18,0.18 0.2,0.46 0.05,0.65l-1.1,1.45c-0.09,0.13 -0.24,0.2 -0.4,0.2h-1.39c-0.22,0.63 -0.35,1.3 -0.35,2s0.13,1.38 0.35,2.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/contact_support.xml b/compose/material/material/icons/generator/raw-icons/rounded/contact_support.xml
index cdae41e..2699f80f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/contact_support.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/contact_support.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.5,2C6.81,2 3,5.81 3,10.5S6.81,19 11.5,19H12v3c4.86,-2.34 8,-7 8,-11.5C20,5.81 16.19,2 11.5,2zM11.48,16c-0.59,0 -1.05,-0.47 -1.05,-1.05c0,-0.59 0.47,-1.04 1.05,-1.04c0.59,0 1.04,0.45 1.04,1.04C12.52,15.53 12.08,16 11.48,16zM13.99,9.83c-0.63,0.93 -1.23,1.21 -1.56,1.81c-0.08,0.14 -0.13,0.26 -0.16,0.49c-0.05,0.39 -0.36,0.68 -0.75,0.68h-0.03c-0.44,0 -0.79,-0.38 -0.75,-0.82c0.03,-0.28 0.09,-0.57 0.25,-0.84c0.41,-0.73 1.18,-1.16 1.63,-1.8c0.48,-0.68 0.21,-1.94 -1.14,-1.94c-0.61,0 -1.01,0.32 -1.26,0.7c-0.19,0.29 -0.57,0.39 -0.89,0.25l0,0c-0.42,-0.18 -0.6,-0.7 -0.34,-1.07C9.5,6.55 10.35,6 11.47,6c1.23,0 2.08,0.56 2.51,1.26C14.34,7.87 14.56,8.99 13.99,9.83z"/>
+ android:pathData="M11.5,2C6.81,2 3,5.81 3,10.5S6.81,19 11.5,19h0.5v3c4.86,-2.34 8,-7 8,-11.5C20,5.81 16.19,2 11.5,2zM12.5,16.5h-2v-2h2v2zM12.9,11.72c-0.01,0.01 -0.02,0.03 -0.03,0.05 -0.05,0.08 -0.1,0.16 -0.14,0.24 -0.02,0.03 -0.03,0.07 -0.04,0.11 -0.03,0.07 -0.06,0.14 -0.08,0.21 -0.07,0.21 -0.1,0.43 -0.1,0.68L10.5,13.01c0,-0.51 0.08,-0.94 0.2,-1.3 0,-0.01 0,-0.02 0.01,-0.03 0.01,-0.04 0.04,-0.06 0.05,-0.1 0.06,-0.16 0.13,-0.3 0.22,-0.44 0.03,-0.05 0.07,-0.1 0.1,-0.15 0.03,-0.04 0.05,-0.09 0.08,-0.12l0.01,0.01c0.84,-1.1 2.21,-1.44 2.32,-2.68 0.09,-0.98 -0.61,-1.93 -1.57,-2.13 -1.04,-0.22 -1.98,0.39 -2.3,1.28 -0.14,0.36 -0.47,0.65 -0.88,0.65h-0.2c-0.6,0 -1.04,-0.59 -0.87,-1.17 0.55,-1.82 2.37,-3.09 4.43,-2.79 1.69,0.25 3.04,1.64 3.33,3.33 0.44,2.44 -1.63,3.03 -2.53,4.35z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/contactless.xml b/compose/material/material/icons/generator/raw-icons/rounded/contactless.xml
index e320b20..5381766 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/contactless.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/contactless.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7.46,14.28L7.46,14.28C7,14.09 6.77,13.59 6.88,13.11C6.96,12.76 7,12.4 7,12.03c0,-0.37 -0.04,-0.73 -0.12,-1.08C6.77,10.47 7,9.97 7.46,9.78l0,0c0.56,-0.23 1.22,0.08 1.36,0.68C8.94,10.96 9,11.49 9,12.03c0,0.54 -0.06,1.07 -0.18,1.57C8.68,14.2 8.03,14.51 7.46,14.28zM10.73,15.62L10.73,15.62c-0.47,-0.19 -0.72,-0.71 -0.58,-1.19c0.23,-0.76 0.35,-1.56 0.35,-2.4c0,-0.83 -0.12,-1.64 -0.35,-2.4c-0.14,-0.49 0.11,-1 0.58,-1.19l0,0c0.55,-0.23 1.18,0.08 1.35,0.65c0.27,0.93 0.42,1.92 0.42,2.95c0,1.02 -0.15,2.01 -0.42,2.94C11.91,15.55 11.28,15.85 10.73,15.62zM13.98,16.96L13.98,16.96c-0.48,-0.2 -0.73,-0.72 -0.57,-1.21c0.38,-1.17 0.59,-2.42 0.59,-3.72c0,-1.3 -0.21,-2.55 -0.59,-3.72c-0.16,-0.49 0.1,-1.02 0.57,-1.21l0,0c0.54,-0.22 1.16,0.07 1.34,0.63c0.44,1.36 0.68,2.8 0.68,4.3c0,1.5 -0.24,2.95 -0.68,4.3C15.14,16.89 14.52,17.19 13.98,16.96z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM8.75,13.68c-0.13,0.43 -0.62,0.63 -1.02,0.45l0,0c-0.34,-0.16 -0.51,-0.54 -0.4,-0.9c0.12,-0.41 0.18,-0.83 0.17,-1.24c-0.01,-0.41 -0.06,-0.8 -0.17,-1.18c-0.1,-0.36 0.06,-0.75 0.4,-0.9l0,0c0.42,-0.19 0.91,0.04 1.04,0.49c0.15,0.51 0.22,1.03 0.23,1.57C9,12.53 8.92,13.11 8.75,13.68zM11.89,15.27c-0.17,0.41 -0.67,0.57 -1.06,0.35l0,0c-0.33,-0.19 -0.46,-0.59 -0.32,-0.94c0.33,-0.77 0.49,-1.63 0.49,-2.56c0,-0.96 -0.18,-1.89 -0.53,-2.78c-0.14,-0.36 0.02,-0.76 0.36,-0.94l0,0c0.39,-0.2 0.87,-0.02 1.03,0.39c0.42,1.06 0.63,2.18 0.63,3.33C12.51,13.25 12.3,14.31 11.89,15.27zM15,16.6c-0.17,0.4 -0.64,0.58 -1.02,0.39l0,0c-0.35,-0.17 -0.52,-0.59 -0.37,-0.95c0.59,-1.39 0.89,-2.75 0.89,-4.06c0,-1.31 -0.3,-2.65 -0.88,-4.01c-0.16,-0.36 0.01,-0.78 0.36,-0.95C14.37,6.82 14.83,7 15,7.4c0.66,1.54 1,3.08 1,4.58C16,13.48 15.66,15.04 15,16.6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/contacts.xml b/compose/material/material/icons/generator/raw-icons/rounded/contacts.xml
index d992229b..fb0782773 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/contacts.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/contacts.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,1H5C4.45,1 4,1.45 4,2v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0C20,1.45 19.55,1 19,1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM12,7c1.66,0 3,1.34 3,3c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3C9,8.34 10.34,7 12,7zM5.76,18c1.47,-1.83 3.71,-3 6.24,-3s4.77,1.17 6.24,3H5.76z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5,23h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v0C4,22.55 4.45,23 5,23z"/>
+ android:pathData="M19,0L5,0c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM5,24h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,22c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,6.75c1.24,0 2.25,1.01 2.25,2.25s-1.01,2.25 -2.25,2.25S9.75,10.24 9.75,9 10.76,6.75 12,6.75zM17,17L7,17v-1.5c0,-1.67 3.33,-2.5 5,-2.5s5,0.83 5,2.5L17,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/content_cut.xml b/compose/material/material/icons/generator/raw-icons/rounded/content_cut.xml
index 9cd8c41..3c627dc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/content_cut.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/content_cut.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.59,4.41c0.55,-0.55 0.55,-1.45 0,-2l0,0c-0.55,-0.55 -1.45,-0.55 -2,0L13,9l2,2L21.59,4.41z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.64,7.64C9.87,7.14 10,6.59 10,6c0,-2.21 -1.79,-4 -4,-4S2,3.79 2,6s1.79,4 4,4c0.59,0 1.14,-0.13 1.64,-0.36L10,12l-2.36,2.36C7.14,14.13 6.59,14 6,14c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4c0,-0.59 -0.13,-1.14 -0.36,-1.64L12,14l7.59,7.59c0.55,0.55 1.45,0.55 2,0l0,0c0.55,-0.55 0.55,-1.45 0,-2L9.64,7.64zM6,8C4.9,8 4,7.11 4,6s0.9,-2 2,-2s2,0.89 2,2S7.1,8 6,8zM6,20c-1.1,0 -2,-0.89 -2,-2s0.9,-2 2,-2s2,0.89 2,2S7.1,20 6,20zM12,12.5c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5S12.28,12.5 12,12.5z"/>
+ android:pathData="M9.64,7.64c0.29,-0.62 0.42,-1.33 0.34,-2.09 -0.19,-1.73 -1.54,-3.2 -3.26,-3.49 -2.77,-0.48 -5.14,1.89 -4.66,4.65 0.3,1.72 1.76,3.07 3.49,3.26 0.76,0.08 1.46,-0.05 2.09,-0.34L10,12l-2.36,2.36c-0.62,-0.29 -1.33,-0.42 -2.09,-0.34 -1.73,0.19 -3.2,1.54 -3.49,3.26 -0.48,2.77 1.89,5.13 4.65,4.65 1.72,-0.3 3.07,-1.76 3.26,-3.49 0.08,-0.76 -0.05,-1.46 -0.34,-2.09L12,14l7.59,7.59c0.89,0.89 2.41,0.26 2.41,-1v-0.01c0,-0.37 -0.15,-0.73 -0.41,-1L9.64,7.64zM6,8c-1.1,0 -2,-0.89 -2,-2s0.9,-2 2,-2 2,0.89 2,2 -0.9,2 -2,2zM6,20c-1.1,0 -2,-0.89 -2,-2s0.9,-2 2,-2 2,0.89 2,2 -0.9,2 -2,2zM12,12.5c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5 0.5,0.22 0.5,0.5 -0.22,0.5 -0.5,0.5zM19.59,2.41L13,9l2,2 6.59,-6.59c0.26,-0.26 0.41,-0.62 0.41,-1L22,3.4c0,-1.25 -1.52,-1.88 -2.41,-0.99z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/content_paste.xml b/compose/material/material/icons/generator/raw-icons/rounded/content_paste.xml
index 68b6c1d..e95fdde 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/content_paste.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/content_paste.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S11.45,3 12,3zM19,19H5V5h2v1c0,1.1 0.9,2 2,2h6c1.1,0 2,-0.9 2,-2V5h2V19z"/>
+ android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0S9.6,0.84 9.18,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM18,20L6,20c-0.55,0 -1,-0.45 -1,-1L5,5c0,-0.55 0.45,-1 1,-1h1v1c0,1.1 0.9,2 2,2h6c1.1,0 2,-0.9 2,-2L17,4h1c0.55,0 1,0.45 1,1v14c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/control_camera.xml b/compose/material/material/icons/generator/raw-icons/rounded/control_camera.xml
index e1a2a6d..1bcbf37 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/control_camera.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/control_camera.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
+ android:pathData="M4.65,9.35L2.7,11.3c-0.39,0.39 -0.39,1.02 0,1.41l1.95,1.95c0.49,0.49 1.28,0.49 1.77,0 0.48,-0.49 0.48,-1.27 0,-1.76l-0.88,-0.9 0.88,-0.89c0.48,-0.49 0.48,-1.27 0,-1.76s-1.28,-0.49 -1.77,0zM17.58,9.35c-0.48,0.49 -0.48,1.27 0,1.76l0.88,0.89 -0.88,0.89c-0.48,0.49 -0.48,1.27 0,1.76 0.49,0.49 1.28,0.49 1.77,0l1.95,-1.95c0.39,-0.39 0.39,-1.02 0,-1.41l-1.95,-1.95c-0.49,-0.48 -1.29,-0.48 -1.77,0.01zM12,18.46l-0.89,-0.88c-0.49,-0.48 -1.27,-0.48 -1.76,0 -0.49,0.49 -0.49,1.28 0,1.77l1.95,1.95c0.39,0.39 1.02,0.39 1.41,0l1.95,-1.95c0.49,-0.49 0.49,-1.28 0,-1.77 -0.49,-0.48 -1.27,-0.48 -1.76,0l-0.9,0.88zM9.35,6.42c0.49,0.48 1.27,0.48 1.76,0l0.89,-0.88 0.89,0.88c0.49,0.48 1.27,0.48 1.76,0 0.49,-0.49 0.49,-1.28 0,-1.77L12.7,2.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L9.35,4.65c-0.49,0.49 -0.49,1.29 0,1.77z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M5.54,8.46l-2.83,2.83c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.03 0,-1.42L4.83,12l2.12,-2.12c0.39,-0.39 0.39,-1.03 0,-1.42l0,0C6.56,8.07 5.92,8.08 5.54,8.46zM8.46,6.95L8.46,6.95c0.39,0.39 1.03,0.39 1.42,0L12,4.83l2.12,2.12c0.39,0.39 1.03,0.39 1.42,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.83,-2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.46,5.54C8.08,5.92 8.07,6.56 8.46,6.95zM17.05,8.46L17.05,8.46c-0.39,0.39 -0.39,1.03 0,1.42L19.17,12l-2.12,2.12c-0.39,0.39 -0.39,1.03 0,1.42l0,0c0.39,0.39 1.02,0.39 1.41,0l2.83,-2.83c0.39,-0.39 0.39,-1.02 0,-1.41l-2.83,-2.83C18.08,8.08 17.44,8.07 17.05,8.46zM12,19.17l-2.12,-2.12c-0.39,-0.39 -1.03,-0.39 -1.42,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l2.83,-2.83c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.03,-0.39 -1.42,0L12,19.17z"/>
+ android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/control_point.xml b/compose/material/material/icons/generator/raw-icons/rounded/control_point.xml
index 0409efd..139d9db 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/control_point.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/control_point.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM16,13h-3v3c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-3H8c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h3V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v3h3c0.55,0 1,0.45 1,1l0,0C17,12.55 16.55,13 16,13z"/>
+ android:pathData="M12,7c-0.55,0 -1,0.45 -1,1v3L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L13,8c0,-0.55 -0.45,-1 -1,-1zM12,2C6.49,2 2,6.49 2,12s4.49,10 10,10 10,-4.49 10,-10S17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/control_point_duplicate.xml b/compose/material/material/icons/generator/raw-icons/rounded/control_point_duplicate.xml
index a27916e..f259d05 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/control_point_duplicate.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/control_point_duplicate.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,3c-4.96,0 -9,4.04 -9,9s4.04,9 9,9s9,-4.04 9,-9S19.96,3 15,3zM18,13h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2h-2c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h2V9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1C19,12.55 18.55,13 18,13zM5.48,18.04C3.4,16.83 2,14.58 2,12s1.4,-4.83 3.48,-6.04C5.8,5.77 6.01,5.45 6.01,5.08c0,-0.77 -0.84,-1.25 -1.51,-0.86C1.82,5.78 0,8.68 0,12c0,3.32 1.82,6.22 4.5,7.78c0.67,0.39 1.51,-0.09 1.51,-0.86C6.01,18.55 5.8,18.23 5.48,18.04z"/>
+ android:pathData="M15,8c-0.55,0 -1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2L16,9c0,-0.55 -0.45,-1 -1,-1zM2,12c0,-2.58 1.4,-4.83 3.48,-6.04 0.32,-0.19 0.53,-0.51 0.53,-0.88 0,-0.77 -0.84,-1.25 -1.51,-0.86C1.82,5.78 0,8.68 0,12s1.82,6.22 4.5,7.78c0.67,0.39 1.51,-0.09 1.51,-0.86 0,-0.37 -0.21,-0.69 -0.53,-0.88C3.4,16.83 2,14.58 2,12zM15,3c-4.96,0 -9,4.04 -9,9s4.04,9 9,9 9,-4.04 9,-9 -4.04,-9 -9,-9zM15,19c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/copyright.xml b/compose/material/material/icons/generator/raw-icons/rounded/copyright.xml
index a5933e5..2fde576 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/copyright.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/copyright.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14,8h-4C9.45,8 9,8.45 9,9v6c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-1c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1l-2,0v-4l2,0c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V9C15,8.45 14.55,8 14,8z"/>
+ android:pathData="M10.08,10.86c0.05,-0.33 0.16,-0.62 0.3,-0.87s0.34,-0.46 0.59,-0.62c0.24,-0.15 0.54,-0.22 0.91,-0.23 0.23,0.01 0.44,0.05 0.63,0.13 0.2,0.09 0.38,0.21 0.52,0.36s0.25,0.33 0.34,0.53 0.13,0.42 0.14,0.64h1.79c-0.02,-0.47 -0.11,-0.9 -0.28,-1.29s-0.4,-0.73 -0.7,-1.01 -0.66,-0.5 -1.08,-0.66 -0.88,-0.23 -1.39,-0.23c-0.65,0 -1.22,0.11 -1.7,0.34s-0.88,0.53 -1.2,0.92 -0.56,0.84 -0.71,1.36S8,11.29 8,11.87v0.27c0,0.58 0.08,1.12 0.23,1.64s0.39,0.97 0.71,1.35 0.72,0.69 1.2,0.91c0.48,0.22 1.05,0.34 1.7,0.34 0.47,0 0.91,-0.08 1.32,-0.23s0.77,-0.36 1.08,-0.63 0.56,-0.58 0.74,-0.94 0.29,-0.74 0.3,-1.15h-1.79c-0.01,0.21 -0.06,0.4 -0.15,0.58s-0.21,0.33 -0.36,0.46 -0.32,0.23 -0.52,0.3c-0.19,0.07 -0.39,0.09 -0.6,0.1 -0.36,-0.01 -0.66,-0.08 -0.89,-0.23 -0.25,-0.16 -0.45,-0.37 -0.59,-0.62s-0.25,-0.55 -0.3,-0.88 -0.08,-0.67 -0.08,-1v-0.27c0,-0.35 0.03,-0.68 0.08,-1.01zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/create.xml b/compose/material/material/icons/generator/raw-icons/rounded/create.xml
index 89fee4c..1599eed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/create.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/create.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,17.46l0,3.04C3,20.78 3.22,21 3.5,21h3.04c0.13,0 0.26,-0.05 0.35,-0.15L17.81,9.94l-3.75,-3.75L3.15,17.1C3.05,17.2 3,17.32 3,17.46z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83l3.75,3.75l1.83,-1.83C21.1,6.65 21.1,6.02 20.71,5.63z"/>
+ android:pathData="M3,17.46v3.04c0,0.28 0.22,0.5 0.5,0.5h3.04c0.13,0 0.26,-0.05 0.35,-0.15L17.81,9.94l-3.75,-3.75L3.15,17.1c-0.1,0.1 -0.15,0.22 -0.15,0.36zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/create_new_folder.xml b/compose/material/material/icons/generator/raw-icons/rounded/create_new_folder.xml
index ec7a28a..0c785da 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/create_new_folder.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/create_new_folder.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4H4C2.89,4 2.01,4.89 2.01,6L2,18c0,1.11 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM17,14h-1v1c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-1h-1c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h1v-1c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v1h1c0.55,0 1,0.45 1,1v0C18,13.55 17.55,14 17,14z"/>
+ android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM18,14h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/credit_card.xml b/compose/material/material/icons/generator/raw-icons/rounded/credit_card.xml
index 45ccc71..509aeac 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/credit_card.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/credit_card.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2.01,4.89 2.01,6L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6C22,4.89 21.11,4 20,4zM20,18H4v-6h16V18zM20,8H4V6h16V8z"/>
+ android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM19,18L5,18c-0.55,0 -1,-0.45 -1,-1v-5h16v5c0,0.55 -0.45,1 -1,1zM20,8L4,8L4,6h16v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop.xml
index 353121b..c7f94e1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,15h2V7c0,-1.1 -0.9,-2 -2,-2H9v2h8V15zM7,17V2c0,-0.55 -0.45,-1 -1,-1l0,0C5.45,1 5,1.45 5,2v3H2C1.45,5 1,5.45 1,6l0,0c0,0.55 0.45,1 1,1h3v10c0,1.1 0.9,2 2,2h10v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H7z"/>
+ android:pathData="M17,15h2L19,7c0,-1.1 -0.9,-2 -2,-2L9,5v2h7c0.55,0 1,0.45 1,1v7zM8,17c-0.55,0 -1,-0.45 -1,-1L7,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3L2,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v10c0,1.1 0.9,2 2,2h10v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_16_9.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_16_9.xml
index acaa273..4ca2d2b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_16_9.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_16_9.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,6H5C3.9,6 3,6.9 3,8v8c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V8C21,6.9 20.1,6 19,6zM19,16H5V8h14V16z"/>
+ android:pathData="M19,6L5,6c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,8c0,-1.1 -0.9,-2 -2,-2zM18,16L6,16c-0.55,0 -1,-0.45 -1,-1L5,9c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v6c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_3_2.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_3_2.xml
index e9fc8e8..aee22db 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_3_2.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_3_2.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4H5C3.9,4 3,4.9 3,6v12c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,18H5V6h14V18z"/>
+ android:pathData="M19,4L5,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM18,18L6,18c-0.55,0 -1,-0.45 -1,-1L5,7c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_5_4.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_5_4.xml
index d151917..1623ef5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_5_4.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_5_4.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,5H5C3.9,5 3,5.9 3,7v10c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V7C21,5.9 20.1,5 19,5zM19,17H5V7h14V17z"/>
+ android:pathData="M19,5L5,5c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM18,17L6,17c-0.55,0 -1,-0.45 -1,-1L5,8c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_7_5.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_7_5.xml
index 7bc13cb..0560b23 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_7_5.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_7_5.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,7H5C3.9,7 3,7.9 3,9v6c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V9C21,7.9 20.1,7 19,7zM19,15H5V9h14V15z"/>
+ android:pathData="M19,7L5,7c-1.1,0 -2,0.9 -2,2v6c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,9c0,-1.1 -0.9,-2 -2,-2zM18,15L6,15c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_din.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_din.xml
index d2c5465..7a6b75c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_din.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_din.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_free.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_free.xml
index 8b3085c..561870e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_free.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_free.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,5v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5zM4,15L4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5v-3C5,15.45 4.55,15 4,15zM19,19h-3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1V19zM19,3h-3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5C21,3.9 20.1,3 19,3z"/>
+ android:pathData="M3,5v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L5,6c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,3c-1.1,0 -2,0.9 -2,2zM4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,19c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 -0.45,-1 -1,-1zM19,18c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2zM19,3h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2c0.55,0 1,0.45 1,1v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L21,5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_landscape.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_landscape.xml
index dc426e1..1623ef5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_landscape.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_landscape.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,18H4V6h16V18z"/>
+ android:pathData="M19,5L5,5c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM18,17L6,17c-0.55,0 -1,-0.45 -1,-1L5,8c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_original.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_original.xml
index 7d1e4db..06e9e2e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_original.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_original.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,17h10c0.41,0 0.65,-0.47 0.4,-0.8l-2.75,-3.67c-0.2,-0.27 -0.6,-0.27 -0.8,0L11.25,16L9.4,13.53c-0.2,-0.27 -0.6,-0.27 -0.8,0l-2,2.67C6.35,16.53 6.59,17 7,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM13.56,12.81l-2.35,3.02 -1.56,-1.88c-0.2,-0.25 -0.58,-0.24 -0.78,0.01l-1.74,2.23c-0.26,0.33 -0.02,0.81 0.39,0.81h8.98c0.41,0 0.65,-0.47 0.4,-0.8l-2.55,-3.39c-0.19,-0.26 -0.59,-0.26 -0.79,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_portrait.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_portrait.xml
index 5367c37..dcf243a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_portrait.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_portrait.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM18,20H6V4h12V20z"/>
+ android:pathData="M17,3L7,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,5c0,-1.1 -0.9,-2 -2,-2zM16,19L8,19c-0.55,0 -1,-0.45 -1,-1L7,6c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_rotate.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_rotate.xml
index 2e834f2..aaebcd2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_rotate.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_rotate.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9.45,0.28C9.05,0.36 8.9,0.84 9.19,1.12l3.01,3.01c0.32,0.31 0.85,0.09 0.85,-0.35V2.04c4.45,0.44 8.06,3.82 8.84,8.17c0.08,0.46 0.5,0.78 0.97,0.78c0.62,0 1.09,-0.57 0.98,-1.18C22.61,2.89 15.79,-1.12 9.45,0.28z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.8,19.87c-0.32,-0.32 -0.85,-0.09 -0.85,0.35v1.74c-4.45,-0.44 -8.06,-3.82 -8.84,-8.17c-0.08,-0.46 -0.5,-0.78 -0.97,-0.78c-0.62,0 -1.09,0.57 -0.98,1.18c1.24,6.92 8.06,10.93 14.4,9.53c0.39,-0.09 0.55,-0.56 0.26,-0.85L11.8,19.87z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,15H9V6c0,-0.55 -0.45,-1 -1,-1S7,5.45 7,6v1H6C5.45,7 5,7.45 5,8s0.45,1 1,1h1v6c0,1.1 0.9,2 2,2h6v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h1c0.55,0 1,-0.45 1,-1S18.55,15 18,15z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,13V9c0,-1.11 -0.9,-2 -2,-2h-4v2h4v4H17z"/>
+ android:pathData="M16,9v5h2L18,8c0,-1.1 -0.9,-2 -2,-2h-6v2h5c0.55,0 1,0.45 1,1zM19,16L9,16c-0.55,0 -1,-0.45 -1,-1L8,5c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v8c0,1.1 0.9,2 2,2h8v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM17.66,1.4C15.99,0.51 13.83,-0.11 11.39,0.04l3.81,3.81 1.33,-1.33c3.09,1.46 5.34,4.37 5.89,7.86 0.06,0.41 0.44,0.69 0.86,0.62 0.41,-0.06 0.69,-0.45 0.62,-0.86 -0.6,-3.8 -2.96,-7 -6.24,-8.74zM7.47,21.49c-3.09,-1.46 -5.34,-4.37 -5.89,-7.86 -0.06,-0.41 -0.44,-0.69 -0.86,-0.62 -0.41,0.06 -0.69,0.45 -0.62,0.86 0.6,3.81 2.96,7.01 6.24,8.75 1.67,0.89 3.83,1.51 6.27,1.36L8.8,20.16l-1.33,1.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/crop_square.xml b/compose/material/material/icons/generator/raw-icons/rounded/crop_square.xml
index d2c5465..b19471f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/crop_square.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/crop_square.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"/>
+ android:pathData="M18,4L6,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,6c0,-1.1 -0.9,-2 -2,-2zM17,18L7,18c-0.55,0 -1,-0.45 -1,-1L6,7c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/cruelty_free.xml b/compose/material/material/icons/generator/raw-icons/rounded/cruelty_free.xml
new file mode 100644
index 0000000..4fc1fef
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/cruelty_free.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.84,14.52c-0.26,-0.19 -0.62,-0.63 -0.79,-0.84C17.24,12.01 19,8.87 19,5c0,-1.95 -0.74,-3 -2,-3c-1.54,0 -3.96,2.06 -5,5.97C10.96,4.06 8.54,2 7,2C5.74,2 5,3.05 5,5c0,3.87 1.76,7.01 2.95,8.68c-0.17,0.21 -0.53,0.65 -0.79,0.84c-0.5,0.41 -1.66,1.37 -1.66,2.98c0,2.21 1.79,4 4,4c1.55,0 2.5,-0.56 2.5,-0.56s0.95,0.56 2.5,0.56c2.21,0 4,-1.79 4,-4C18.5,15.89 17.34,14.93 16.84,14.52zM9.35,12.2C8.34,10.7 7,8.12 7,5c0,-0.49 0.06,-0.8 0.12,-0.97c0.94,0.31 3.24,2.71 3.38,7.64C10.03,11.79 9.66,11.97 9.35,12.2zM10.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S11,15.59 11,16C11,16.41 10.78,16.75 10.5,16.75zM12,19.5c-0.55,0 -1,-0.72 -1,-1c0,-0.28 0.45,-0.5 1,-0.5s1,0.22 1,0.5C13,18.78 12.55,19.5 12,19.5zM13.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S14,15.59 14,16C14,16.41 13.78,16.75 13.5,16.75zM13.5,11.67c0.14,-4.93 2.44,-7.33 3.38,-7.64C16.94,4.2 17,4.51 17,5c0,3.12 -1.34,5.7 -2.35,7.2C14.34,11.97 13.97,11.79 13.5,11.67z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/dashboard.xml b/compose/material/material/icons/generator/raw-icons/rounded/dashboard.xml
index cccf16e..628af9a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/dashboard.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/dashboard.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,13h6c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4v8C3,12.55 3.45,13 4,13zM4,21h6c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v4C3,20.55 3.45,21 4,21zM14,21h6c0.55,0 1,-0.45 1,-1v-8c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1v8C13,20.55 13.45,21 14,21zM13,4v4c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1h-6C13.45,3 13,3.45 13,4z"/>
+ android:pathData="M4,13h6c0.55,0 1,-0.45 1,-1L11,4c0,-0.55 -0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1zM4,21h6c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1L4,15c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM14,21h6c0.55,0 1,-0.45 1,-1v-8c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1zM13,4v4c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/data_exploration.xml b/compose/material/material/icons/generator/raw-icons/rounded/data_exploration.xml
new file mode 100644
index 0000000..f2cf785
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/data_exploration.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12c0,1.33 0.26,2.61 0.74,3.77l4.61,-4.62c0.37,-0.37 0.95,-0.39 1.35,-0.06l2.6,2.19L14.58,10H14c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-0.58l-3.94,3.93c-0.37,0.37 -0.96,0.39 -1.35,0.05l-2.59,-2.19l-4.4,4.4C5.52,20.26 8.56,22 12,22h8c1.1,0 2,-0.9 2,-2V12zM19.5,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.05,20.5 19.5,20.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/data_usage.xml b/compose/material/material/icons/generator/raw-icons/rounded/data_usage.xml
index 7a0a8be..a639680 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/data_usage.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/data_usage.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,2.05v3.03c3.39,0.49 6,3.39 6,6.92c0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53C21.68,14.83 22,13.45 22,12C22,6.82 18.05,2.55 13,2.05zM12,19c-3.87,0 -7,-3.13 -7,-7c0,-3.53 2.61,-6.43 6,-6.92V2.05C5.94,2.55 2,6.81 2,12c0,5.52 4.47,10 9.99,10c3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"/>
+ android:pathData="M13,3.87v0.02c0,0.67 0.45,1.23 1.08,1.43C16.93,6.21 19,8.86 19,12c0,0.52 -0.06,1.01 -0.17,1.49 -0.14,0.64 0.12,1.3 0.69,1.64l0.01,0.01c0.86,0.5 1.98,0.05 2.21,-0.91 0.17,-0.72 0.26,-1.47 0.26,-2.23 0,-4.5 -2.98,-8.32 -7.08,-9.57 -0.95,-0.29 -1.92,0.44 -1.92,1.44zM10.94,18.92c-2.99,-0.43 -5.42,-2.86 -5.86,-5.84 -0.54,-3.6 1.66,-6.77 4.83,-7.76 0.64,-0.19 1.09,-0.76 1.09,-1.43v-0.02c0,-1 -0.97,-1.73 -1.93,-1.44 -4.51,1.38 -7.66,5.86 -6.98,10.96 0.59,4.38 4.13,7.92 8.51,8.51 3.14,0.42 6.04,-0.61 8.13,-2.53 0.74,-0.68 0.61,-1.89 -0.26,-2.39 -0.58,-0.34 -1.3,-0.23 -1.8,0.22 -1.47,1.34 -3.51,2.05 -5.73,1.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/date_range.xml b/compose/material/material/icons/generator/raw-icons/rounded/date_range.xml
index e106f7e..ccabff0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/date_range.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/date_range.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4h-1V3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1S6,2.45 6,3v1H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,10v10H5V10H19zM8,12L8,12c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v0C7,12.45 7.45,12 8,12zM12,12L12,12c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v0C11,12.45 11.45,12 12,12zM16,12L16,12c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v0C15,12.45 15.45,12 16,12z"/>
+ android:pathData="M19,4h-1L18,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L8,4L8,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,4c-1.11,0 -1.99,0.9 -1.99,2L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM19,19c0,0.55 -0.45,1 -1,1L6,20c-0.55,0 -1,-0.45 -1,-1L5,9h14v10zM7,11h2v2L7,13zM11,11h2v2h-2zM15,11h2v2h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/deck.xml b/compose/material/material/icons/generator/raw-icons/rounded/deck.xml
index 12b9b49..496bce5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/deck.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/deck.xml
@@ -12,5 +12,5 @@
android:pathData="M8,16H4.9l-0.57,-3.02c-0.1,-0.54 -0.62,-0.9 -1.17,-0.8c-0.54,0.1 -0.9,0.62 -0.8,1.17L3,16.74V21c0,0.55 0.45,1 1,1h0.01c0.55,0 1,-0.44 1,-0.99L5.02,18H7v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4C9,16.45 8.55,16 8,16z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M20.84,12.18c-0.54,-0.1 -1.06,0.26 -1.17,0.8L19.1,16H16c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1c0.55,0 1,-0.45 1,-1v-3h1.98L19,21.01c0,0.55 0.45,0.99 1,0.99l0,0c0.55,0 1,-0.45 1,-1v-4.26l0.64,-3.39C21.74,12.81 21.38,12.28 20.84,12.18z"/>
+ android:pathData="M20.84,12.18c-0.54,-0.1 -1.06,0.26 -1.17,0.8L19.1,16H16c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h1.98l0.02,3.01c0,0.55 0.45,0.99 1,0.99H20c0.55,0 1,-0.45 1,-1v-4.26l0.64,-3.39C21.74,12.81 21.38,12.28 20.84,12.18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/dehaze.xml b/compose/material/material/icons/generator/raw-icons/rounded/dehaze.xml
index 6de1e78..14ed5b9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/dehaze.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/dehaze.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,17L2,17c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H3C2.45,16 2,16.45 2,17zM2,12L2,12c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H3C2.45,11 2,11.45 2,12zM2,7L2,7c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H3C2.45,6 2,6.45 2,7z"/>
+ android:pathData="M2,17c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,16c-0.55,0 -1,0.45 -1,1zM2,12c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,11c-0.55,0 -1,0.45 -1,1zM2,7c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/delete.xml b/compose/material/material/icons/generator/raw-icons/rounded/delete.xml
index 5298989..ba98203 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/delete.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/delete.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6V19zM18,4h-2.5l-0.71,-0.71C14.61,3.11 14.35,3 14.09,3H9.91c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4H6C5.45,4 5,4.45 5,5s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1S18.55,4 18,4z"/>
+ android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V9c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v10zM18,4h-2.5l-0.71,-0.71c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29H9.91c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4H6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/delete_sweep.xml b/compose/material/material/icons/generator/raw-icons/rounded/delete_sweep.xml
index 9376cd2..cbf7fd4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/delete_sweep.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/delete_sweep.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,16h2c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,-0.45 -1,-1l0,0C15,16.45 15.45,16 16,16zM16,8h5c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-5c-0.55,0 -1,-0.45 -1,-1l0,0C15,8.45 15.45,8 16,8zM16,12h4c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1l0,0C15,12.45 15.45,12 16,12zM3,18c0,1.1 0.9,2 2,2h6c1.1,0 2,-0.9 2,-2V8H3V18zM13,5h-2l-0.71,-0.71C10.11,4.11 9.85,4 9.59,4H6.41C6.15,4 5.89,4.11 5.71,4.29L5,5H3C2.45,5 2,5.45 2,6l0,0c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1l0,0C14,5.45 13.55,5 13,5z"/>
+ android:pathData="M16,16h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM16,8h5c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM16,12h4c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM3,18c0,1.1 0.9,2 2,2h6c1.1,0 2,-0.9 2,-2L13,8L3,8v10zM13,5h-2l-0.71,-0.71c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29L6.41,4c-0.26,0 -0.52,0.11 -0.7,0.29L5,5L3,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/departure_board.xml b/compose/material/material/icons/generator/raw-icons/rounded/departure_board.xml
index 4517558..d1c911a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/departure_board.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/departure_board.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,11V8h7.29c-0.77,-2.6 0.21,-4.61 0.37,-4.97C2.97,2.67 2,5.02 2,7v9.5c0,0.95 0.38,1.81 1,2.44v1.56C3,21.32 3.67,22 4.5,22S6,21.32 6,20.5V20h8v0.5c0,0.82 0.67,1.5 1.5,1.5s1.5,-0.68 1.5,-1.5v-1.56c0.62,-0.63 1,-1.49 1,-2.44V13c-1.91,0 -3.63,-0.76 -4.89,-2H4zM6.5,17C5.67,17 5,16.33 5,15.5S5.67,14 6.5,14S8,14.67 8,15.5S7.33,17 6.5,17zM15,15.5c0,0.83 -0.67,1.5 -1.5,1.5S12,16.33 12,15.5s0.67,-1.5 1.5,-1.5S15,14.67 15,15.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,1c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S20.76,1 18,1zM20.02,8.03c-0.2,0.2 -0.51,0.2 -0.71,0l-1.67,-1.67C17.54,6.26 17.49,6.13 17.49,6V3.5c0,-0.28 0.22,-0.5 0.5,-0.5h0c0.28,0 0.5,0.22 0.5,0.5v2.29l1.53,1.53C20.21,7.51 20.21,7.83 20.02,8.03z"/>
+ android:pathData="M17.34,1.13c-2.94,-0.55 -5.63,0.75 -7.12,2.92 0.01,-0.01 0.01,-0.02 0.02,-0.03C9.84,4 9.42,4 9,4c-4.42,0 -8,0.5 -8,4v10c0,0.88 0.39,1.67 1,2.22v1.28c0,0.83 0.67,1.5 1.5,1.5S5,22.33 5,21.5L5,21h8v0.5c0,0.82 0.67,1.5 1.5,1.5 0.82,0 1.5,-0.67 1.5,-1.5v-1.28c0.61,-0.55 1,-1.34 1,-2.22v-3.08c3.72,-0.54 6.5,-3.98 5.92,-7.97 -0.42,-2.9 -2.7,-5.29 -5.58,-5.82zM4.5,19c-0.83,0 -1.5,-0.67 -1.5,-1.5S3.67,16 4.5,16s1.5,0.67 1.5,1.5S5.33,19 4.5,19zM3,13L3,8h6c0,1.96 0.81,3.73 2.11,5L3,13zM13.5,19c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM16,13c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM15.75,4c-0.41,0 -0.75,0.34 -0.75,0.75v3.68c0,0.35 0.19,0.68 0.49,0.86l2.52,1.51c0.34,0.2 0.78,0.09 0.98,-0.24 0.21,-0.34 0.1,-0.79 -0.25,-0.99L16.5,8.25v-3.5c0,-0.41 -0.34,-0.75 -0.75,-0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/description.xml b/compose/material/material/icons/generator/raw-icons/rounded/description.xml
index 47bb769..37d99d2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/description.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/description.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.59,2.59C14.21,2.21 13.7,2 13.17,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8.83c0,-0.53 -0.21,-1.04 -0.59,-1.41L14.59,2.59zM15,18H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1S15.55,18 15,18zM15,14H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1S15.55,14 15,14zM13,8V3.5L18.5,9H14C13.45,9 13,8.55 13,8z"/>
+ android:pathData="M14.59,2.59c-0.38,-0.38 -0.89,-0.59 -1.42,-0.59L6,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.82,-4.83zM15,18L9,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM15,14L9,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM13,8L13,3.5L18.5,9L14,9c-0.55,0 -1,-0.45 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/desktop_access_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/desktop_access_disabled.xml
index abf7a23..07985f9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/desktop_access_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/desktop_access_disabled.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5v11h-1.17l1.87,1.87C21.46,17.58 22,16.86 22,16V5c0,-1.1 -0.9,-2 -2,-2H5.83l2,2H20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1.39,2.81L1.39,2.81C1,3.2 1,3.83 1.39,4.22l0.62,0.62C2.01,4.9 2,4.95 2,5v11c0,1.1 0.9,2 2,2h6v2H9c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1v-2h1.17l4.61,4.61c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81C2.42,2.42 1.78,2.42 1.39,2.81zM4,16V6.83L13.17,16H4z"/>
+ android:pathData="M0.31,2c-0.39,0.39 -0.39,1.02 0,1.41l0.69,0.68L1,16c0,1.1 0.9,2 2,2h7v2L9,20c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-2h0.9l5.29,5.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L1.72,2C1.33,1.61 0.7,1.61 0.31,2zM2.99,15L2.99,6.09L12.9,16L3.99,16c-0.55,0 -1,-0.45 -1,-1zM4.55,2l2,2L20,4c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1h-1.45l2,2h0.44c1.1,0 2,-0.9 2,-2L22.99,4c0,-1.1 -0.9,-2 -2,-2L4.55,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/desktop_mac.xml b/compose/material/material/icons/generator/raw-icons/rounded/desktop_mac.xml
index 00255ce..6ccde2a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/desktop_mac.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/desktop_mac.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h6l-1.29,1.29C8.08,20.92 8.52,22 9.41,22h5.17c0.89,0 1.34,-1.08 0.71,-1.71L14,19h6c1.1,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3zM20,14H4V5h16V14z"/>
+ android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7l-1.63,2.45c-0.44,0.66 0.03,1.55 0.83,1.55h5.6c0.8,0 1.28,-0.89 0.83,-1.55L14,18h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM21,14L3,14L3,5c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/desktop_windows.xml b/compose/material/material/icons/generator/raw-icons/rounded/desktop_windows.xml
index ab0e2c3..66b96fc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/desktop_windows.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/desktop_windows.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v11c0,1.1 0.9,2 2,2h6v2H9c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1v-2h6c1.1,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3zM20,16H4V5h16V16z"/>
+ android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v2L9,20c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-2h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM20,16L4,16c-0.55,0 -1,-0.45 -1,-1L3,5c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/developer_board.xml b/compose/material/material/icons/generator/raw-icons/rounded/developer_board.xml
index 38eb3b1..c381e5d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/developer_board.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/developer_board.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,8L22,8c0,-0.55 -0.45,-1 -1,-1h-1V5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-2h1c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-1v-2h1c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-1V9h1C21.55,9 22,8.55 22,8zM18,19H4V5h14V19zM7,13h3c0.55,0 1,0.45 1,1v2c0,0.55 -0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1v-2C6,13.45 6.45,13 7,13zM13,7h2c0.55,0 1,0.45 1,1v1c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,-0.45 -1,-1V8C12,7.45 12.45,7 13,7zM7,7h3c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1V8C6,7.45 6.45,7 7,7zM13,11h2c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,-0.45 -1,-1v-4C12,11.45 12.45,11 13,11z"/>
+ android:pathData="M22,8c0,-0.55 -0.45,-1 -1,-1h-1L20,5c0,-1.1 -0.9,-2 -2,-2L4,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-2h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-2h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1L20,9h1c0.55,0 1,-0.45 1,-1zM17,19L5,19c-0.55,0 -1,-0.45 -1,-1L4,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM6.5,13h4c0.28,0 0.5,0.22 0.5,0.5v3c0,0.28 -0.22,0.5 -0.5,0.5h-4c-0.28,0 -0.5,-0.22 -0.5,-0.5v-3c0,-0.28 0.22,-0.5 0.5,-0.5zM12.5,7h3c0.28,0 0.5,0.22 0.5,0.5v2c0,0.28 -0.22,0.5 -0.5,0.5h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5v-2c0,-0.28 0.22,-0.5 0.5,-0.5zM6.5,7h4c0.28,0 0.5,0.22 0.5,0.5v4c0,0.28 -0.22,0.5 -0.5,0.5h-4c-0.28,0 -0.5,-0.22 -0.5,-0.5v-4c0,-0.28 0.22,-0.5 0.5,-0.5zM12.5,11h3c0.28,0 0.5,0.22 0.5,0.5v5c0,0.28 -0.22,0.5 -0.5,0.5h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5v-5c0,-0.28 0.22,-0.5 0.5,-0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/developer_mode.xml b/compose/material/material/icons/generator/raw-icons/rounded/developer_mode.xml
index cfd0d54..a12379e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/developer_mode.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/developer_mode.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,6h10l0,0c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V3c0,-1.1 -0.9,-1.99 -2,-1.99L7,1C5.9,1 5,1.9 5,3v3c0,0.55 0.45,1 1,1l0,0C6.55,7 7,6.55 7,6L7,6zM16.12,15.88l3.17,-3.17c0.39,-0.39 0.39,-1.02 0,-1.41l-3.17,-3.17c-0.39,-0.39 -1.03,-0.39 -1.42,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L17.17,12l-2.47,2.47c-0.39,0.39 -0.39,1.02 0,1.41l0,0C15.09,16.27 15.73,16.27 16.12,15.88zM9.29,14.46L6.83,12l2.46,-2.46c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.03,-0.39 -1.42,0L4.7,11.3c-0.39,0.39 -0.39,1.02 0,1.41l3.17,3.17c0.39,0.39 1.03,0.39 1.42,0l0,0C9.69,15.49 9.68,14.85 9.29,14.46zM17,18H7l0,0c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1l0,0C17.45,17 17,17.45 17,18L17,18z"/>
+ android:pathData="M7,5h10v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1L19,3c0,-1.1 -0.9,-1.99 -2,-1.99L7,1c-1.1,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L7,5zM16.12,15.88l3.17,-3.17c0.39,-0.39 0.39,-1.02 0,-1.41l-3.17,-3.17c-0.39,-0.39 -1.03,-0.39 -1.42,0 -0.39,0.39 -0.39,1.02 0,1.41L17.17,12l-2.47,2.47c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.03,0.39 1.42,0zM9.29,14.46L6.83,12l2.46,-2.46c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.03,-0.39 -1.42,0L4.7,11.3c-0.39,0.39 -0.39,1.02 0,1.41l3.17,3.17c0.39,0.39 1.03,0.39 1.42,0 0.4,-0.39 0.39,-1.03 0,-1.42zM17,19L7,19v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/device_hub.xml b/compose/material/material/icons/generator/raw-icons/rounded/device_hub.xml
index 25aeb12..f88bd59 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/device_hub.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/device_hub.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,16l-4,-4V8.82c1.35,-0.49 2.26,-1.89 1.93,-3.46c-0.25,-1.18 -1.23,-2.12 -2.42,-2.32C10.63,2.73 9,4.17 9,6c0,1.3 0.84,2.4 2,2.82V12l-4,4H4c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-2.05l4,-4.2l4,4.2V20c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1H17z"/>
+ android:pathData="M17,16l-4,-4V8.82c1.35,-0.49 2.26,-1.89 1.93,-3.46 -0.25,-1.18 -1.23,-2.12 -2.42,-2.32C10.63,2.73 9,4.17 9,6c0,1.3 0.84,2.4 2,2.82V12l-4,4H4c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-2.05l4,-4.2 4,4.2V20c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1h-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/device_unknown.xml b/compose/material/material/icons/generator/raw-icons/rounded/device_unknown.xml
index 2b50fe4..f448f12 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/device_unknown.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/device_unknown.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1 17,1zM17,18H7V6h10V18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.01,14.91c-0.58,0 -1.05,0.45 -1.05,1.04c0,0.59 0.46,1.05 1.05,1.05c0.6,0 1.04,-0.47 1.04,-1.05C13.04,15.36 12.59,14.91 12.01,14.91z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.86,9.38c0.32,0.13 0.7,0.04 0.89,-0.25c0.25,-0.38 0.64,-0.7 1.26,-0.7c1.35,0 1.62,1.26 1.14,1.94c-0.45,0.64 -1.23,1.08 -1.63,1.8c-0.15,0.27 -0.22,0.56 -0.25,0.84c-0.04,0.44 0.31,0.82 0.75,0.82h0.03c0.39,0 0.7,-0.3 0.75,-0.68c0.03,-0.24 0.08,-0.35 0.16,-0.49c0.32,-0.6 0.93,-0.88 1.56,-1.81c0.57,-0.84 0.35,-1.97 -0.01,-2.57C14.07,7.56 13.22,7 11.99,7c-1.12,0 -1.97,0.55 -2.48,1.31C9.26,8.68 9.44,9.2 9.86,9.38z"/>
+ android:pathData="M17,1L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-2 -2,-2zM17,19L7,19L7,5h10v14zM11,16h2v2h-2zM9.52,10.19h0.13c0.33,0 0.59,-0.23 0.7,-0.54 0.24,-0.69 0.91,-1.21 1.66,-1.21 0.93,0 1.75,0.82 1.75,1.75 0,1.32 -1.49,1.55 -2.23,2.82h-0.01c-0.08,0.14 -0.14,0.29 -0.2,0.45 -0.01,0.02 -0.02,0.03 -0.02,0.05 -0.01,0.02 -0.01,0.04 -0.01,0.05 -0.1,0.31 -0.16,0.66 -0.16,1.08h1.76c0,-0.25 0.04,-0.47 0.12,-0.67 0.54,-1.47 2.77,-1.86 2.48,-4.18 -0.19,-1.55 -1.43,-2.84 -2.98,-3.04 -1.77,-0.23 -3.29,0.78 -3.81,2.3 -0.2,0.56 0.23,1.14 0.82,1.14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/devices.xml b/compose/material/material/icons/generator/raw-icons/rounded/devices.xml
index 8417337..d7dbff9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/devices.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/devices.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,6h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H6C4.9,4 4,4.9 4,6v11H3.5C2.67,17 2,17.67 2,18.5v0C2,19.33 2.67,20 3.5,20h7c0.83,0 1.5,-0.67 1.5,-1.5v0c0,-0.83 -0.67,-1.5 -1.5,-1.5H6V6zM21,8h-6c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1V9C22,8.45 21.55,8 21,8zM20,17h-4v-7h4V17z"/>
+ android:pathData="M4,7c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,4c-1.1,0 -2,0.9 -2,2v11h-0.5c-0.83,0 -1.5,0.67 -1.5,1.5S0.67,20 1.5,20L14,20v-3L4,17L4,7zM23,8h-6c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1L24,9c0,-0.55 -0.45,-1 -1,-1zM22,17h-4v-7h4v7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/devices_other.xml b/compose/material/material/icons/generator/raw-icons/rounded/devices_other.xml
index 7ba8bcc..a8babc3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/devices_other.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/devices_other.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,6h15c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,13.78V13c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v0.78C8.39,14.33 8,15.11 8,16s0.39,1.67 1,2.22V19c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-0.78c0.61,-0.55 1,-1.34 1,-2.22S13.61,14.33 13,13.78zM11,17.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S11.83,17.5 11,17.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,9h-5c-0.5,0 -1,0.5 -1,1v9c0,0.5 0.5,1 1,1h5c0.5,0 1,-0.5 1,-1v-9C22,9.5 21.5,9 21,9zM20,18h-3v-7h3V18z"/>
+ android:pathData="M3,7c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,18c-0.55,0 -1,-0.45 -1,-1L3,7zM12,12h-2c-0.55,0 -1,0.45 -1,1v0.78c-0.61,0.55 -1,1.33 -1,2.22 0,0.89 0.39,1.67 1,2.22L9,19c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-0.78c0.61,-0.55 1,-1.34 1,-2.22s-0.39,-1.67 -1,-2.22L13,13c0,-0.55 -0.45,-1 -1,-1zM11,17.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM22,8h-6c-0.5,0 -1,0.5 -1,1v10c0,0.5 0.5,1 1,1h6c0.5,0 1,-0.5 1,-1L23,9c0,-0.5 -0.5,-1 -1,-1zM21,18h-4v-8h4v8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/dialer_sip.xml b/compose/material/material/icons/generator/raw-icons/rounded/dialer_sip.xml
index fc25ded..1455e28 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/dialer_sip.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/dialer_sip.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.5,8C16.78,8 17,7.78 17,7.5v-4C17,3.22 16.78,3 16.5,3S16,3.22 16,3.5v4C16,7.78 16.22,8 16.5,8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.5,7C12.22,7 12,7.22 12,7.5S12.22,8 12.5,8h1.95C14.75,8 15,7.75 15,7.45v-1.9C15,5.25 14.75,5 14.45,5H13V4h1.5C14.78,4 15,3.78 15,3.5S14.78,3 14.5,3h-1.95C12.25,3 12,3.25 12,3.55v1.89C12,5.75 12.25,6 12.55,6H14v1H12.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.45,3h-1.89C18.25,3 18,3.25 18,3.55V7.5C18,7.78 18.22,8 18.5,8S19,7.78 19,7.5V6h1.45C20.75,6 21,5.75 21,5.45v-1.9C21,3.25 20.75,3 20.45,3zM20,5h-1V4h1V5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M16.5,8c0.28,0 0.5,-0.22 0.5,-0.5v-4c0,-0.28 -0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5v4c0,0.28 0.22,0.5 0.5,0.5zM12.5,7c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h1.95c0.3,0 0.55,-0.25 0.55,-0.55v-1.9c0,-0.3 -0.25,-0.55 -0.55,-0.55L13,5L13,4h1.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5h-1.95c-0.3,0 -0.55,0.25 -0.55,0.55v1.89c0,0.31 0.25,0.56 0.55,0.56L14,6v1h-1.5zM20.45,3h-1.89c-0.31,0 -0.56,0.25 -0.56,0.55L18,7.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5L19,6h1.45c0.3,0 0.55,-0.25 0.55,-0.55v-1.9c0,-0.3 -0.25,-0.55 -0.55,-0.55zM20,5h-1L19,4h1v1zM19.21,15.27l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.04 0.57,-1.64l-0.29,-2.52c-0.11,-1.01 -0.97,-1.78 -1.98,-1.78L5.02,3.01c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1 -0.76,-1.86 -1.77,-1.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/dialpad.xml b/compose/material/material/icons/generator/raw-icons/rounded/dialpad.xml
index b6a197f..a9a5544 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/dialpad.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/dialpad.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,19c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,19 12,19zM6,1C4.9,1 4,1.9 4,3s0.9,2 2,2s2,-0.9 2,-2S7.1,1 6,1zM6,7C4.9,7 4,7.9 4,9s0.9,2 2,2s2,-0.9 2,-2S7.1,7 6,7zM6,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S7.1,13 6,13zM18,5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S16.9,5 18,5zM12,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,13 12,13zM18,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S19.1,13 18,13zM18,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S19.1,7 18,7zM12,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,7 12,7zM12,1c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,1 12,1z"/>
+ android:pathData="M12,19c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,1c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,1c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions.xml
index ff30654..2594458 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.41,10.59l-7.99,-8c-0.78,-0.78 -2.05,-0.78 -2.83,0l-8.01,8c-0.78,0.78 -0.78,2.05 0,2.83l8.01,8c0.78,0.78 2.05,0.78 2.83,0l7.99,-8C22.2,12.63 22.2,11.37 21.41,10.59zM16.65,11.35l-2.29,2.29c-0.32,0.32 -0.85,0.09 -0.85,-0.35V12H10v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1h4.5V8.71c0,-0.45 0.54,-0.67 0.85,-0.35l2.29,2.29C16.84,10.84 16.84,11.16 16.65,11.35z"/>
+ android:pathData="M21.71,11.29l-9,-9c-0.39,-0.39 -1.02,-0.39 -1.41,0l-9,9c-0.39,0.39 -0.39,1.02 0,1.41l9,9c0.39,0.39 1.02,0.39 1.41,0l9,-9c0.39,-0.38 0.39,-1.01 0,-1.41zM14,14.5V12h-4v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1h5V7.5l3.15,3.15c0.2,0.2 0.2,0.51 0,0.71L14,14.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_bike.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_bike.xml
index 2b7d3c2..36ef688 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_bike.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_bike.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S14.4,5.5 15.5,5.5zM5,12c-2.8,0 -5,2.2 -5,5s2.2,5 5,5s5,-2.2 5,-5S7.8,12 5,12zM5,20.5c-1.9,0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S6.9,20.5 5,20.5zM10.8,10.5l2.4,-2.4L14,8.9c1.05,1.05 2.31,1.78 3.86,2.02c0.6,0.09 1.14,-0.39 1.14,-1v0c0,-0.49 -0.36,-0.9 -0.85,-0.98c-1.08,-0.18 -1.93,-0.71 -2.65,-1.43l-1.9,-1.9C13.1,5.2 12.6,5 12,5s-1.1,0.2 -1.4,0.6L7.8,8.4C7.4,8.8 7.2,9.3 7.2,9.8c0,0.6 0.2,1.1 0.6,1.4L11,14v4c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-4.4c0,-0.52 -0.2,-1.01 -0.55,-1.38L10.8,10.5zM19,12c-2.8,0 -5,2.2 -5,5s2.2,5 5,5s5,-2.2 5,-5S21.8,12 19,12zM19,20.5c-1.9,0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S20.9,20.5 19,20.5z"/>
+ android:pathData="M15.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM5,12c-2.8,0 -5,2.2 -5,5s2.2,5 5,5 5,-2.2 5,-5 -2.2,-5 -5,-5zM5,20.5c-1.9,0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5 3.5,1.6 3.5,3.5 -1.6,3.5 -3.5,3.5zM10.8,10.5l2.4,-2.4 0.8,0.8c1.06,1.06 2.38,1.78 3.96,2.02 0.6,0.09 1.14,-0.39 1.14,-1 0,-0.49 -0.37,-0.91 -0.85,-0.99 -1.11,-0.18 -2.02,-0.71 -2.75,-1.43l-1.9,-1.9c-0.5,-0.4 -1,-0.6 -1.6,-0.6s-1.1,0.2 -1.4,0.6L7.8,8.4c-0.4,0.4 -0.6,0.9 -0.6,1.4 0,0.6 0.2,1.1 0.6,1.4L11,14v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4.4c0,-0.52 -0.2,-1.01 -0.55,-1.38L10.8,10.5zM19,12c-2.8,0 -5,2.2 -5,5s2.2,5 5,5 5,-2.2 5,-5 -2.2,-5 -5,-5zM19,20.5c-1.9,0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5 3.5,1.6 3.5,3.5 -1.6,3.5 -3.5,3.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_bus.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_bus.xml
index a14477d..a53139b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_bus.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_bus.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C8,2 4,2.5 4,6v9.5c0,0.95 0.38,1.81 1,2.44v1.56C5,20.33 5.67,21 6.5,21h0C7.33,21 8,20.33 8,19.5V19h8v0.5c0,0.82 0.67,1.5 1.5,1.5h0c0.82,0 1.5,-0.67 1.5,-1.5v-1.56c0.62,-0.63 1,-1.49 1,-2.44V6C20,2.5 16.42,2 12,2zM8.5,16C7.67,16 7,15.33 7,14.5S7.67,13 8.5,13s1.5,0.67 1.5,1.5S9.33,16 8.5,16zM15.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S16.33,16 15.5,16zM18,10H6V7h12V10z"/>
+ android:pathData="M4,16c0,0.88 0.39,1.67 1,2.22v1.28c0,0.83 0.67,1.5 1.5,1.5S8,20.33 8,19.5L8,19h8v0.5c0,0.82 0.67,1.5 1.5,1.5 0.82,0 1.5,-0.67 1.5,-1.5v-1.28c0.61,-0.55 1,-1.34 1,-2.22L20,6c0,-3.5 -3.58,-4 -8,-4s-8,0.5 -8,4v10zM7.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,14 7.5,14s1.5,0.67 1.5,1.5S8.33,17 7.5,17zM16.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM18,11L6,11L6,6h12v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_car.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_car.xml
index fbfe158..0210bd9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_car.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_car.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5h-11C5.84,5 5.29,5.42 5.08,6.01L3,12v7.5C3,20.33 3.67,21 4.5,21h0C5.33,21 6,20.33 6,19.5V19h12v0.5c0,0.82 0.67,1.5 1.5,1.5h0c0.82,0 1.5,-0.67 1.5,-1.5V12L18.92,6.01zM7.5,16C6.67,16 6,15.33 6,14.5S6.67,13 7.5,13S9,13.67 9,14.5S8.33,16 7.5,16zM16.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S17.33,16 16.5,16zM5.81,10l1.04,-3h10.29l1.04,3H5.81z"/>
+ android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5h-11c-0.66,0 -1.21,0.42 -1.42,1.01l-1.97,5.67c-0.07,0.21 -0.11,0.43 -0.11,0.66v7.16c0,0.83 0.67,1.5 1.5,1.5S6,20.33 6,19.5L6,19h12v0.5c0,0.82 0.67,1.5 1.5,1.5 0.82,0 1.5,-0.67 1.5,-1.5v-7.16c0,-0.22 -0.04,-0.45 -0.11,-0.66l-1.97,-5.67zM6.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,13 6.5,13s1.5,0.67 1.5,1.5S7.33,16 6.5,16zM17.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,11l1.27,-3.82c0.14,-0.4 0.52,-0.68 0.95,-0.68h9.56c0.43,0 0.81,0.28 0.95,0.68L19,11L5,11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_railway.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_railway.xml
index 5893b91..5af9866 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_railway.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_railway.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C8,2 4,2.5 4,6v9.5C4,17.43 5.57,19 7.5,19l-1.21,0.81C6.11,19.93 6,20.13 6,20.35v0C6,20.71 6.29,21 6.65,21h10.7c0.36,0 0.65,-0.29 0.65,-0.65v0c0,-0.22 -0.11,-0.42 -0.29,-0.54L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5V6C20,2.5 16.42,2 12,2zM12,16c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,13 12,13s1.5,0.67 1.5,1.5S12.83,16 12,16zM18,10H6V7h12V10z"/>
+ android:pathData="M4,15.5C4,17.43 5.57,19 7.5,19L6,20.5v0.5h12v-0.5L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5L20,5c0,-3.5 -3.58,-4 -8,-4s-8,0.5 -8,4v10.5zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM18,10L6,10L6,5h12v5zM4,15.5C4,17.43 5.57,19 7.5,19l-1.14,1.15c-0.32,0.31 -0.1,0.85 0.35,0.85h10.58c0.45,0 0.67,-0.54 0.35,-0.85L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5L20,5c0,-3.5 -3.58,-4 -8,-4s-8,0.5 -8,4v10.5zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM18,10L6,10L6,5h12v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_run.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_run.xml
index 570f940..3a823a8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_run.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_run.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.5,3.5m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,11.91L19,11.91c0,-0.49 -0.36,-0.9 -0.84,-0.98c-1.53,-0.25 -2.79,-1.16 -3.47,-2.35l-1,-1.58c-0.4,-0.6 -1,-1 -1.7,-1c-0.68,0 -1.28,0.28 -4.77,1.76C6.49,8.07 6,8.8 6,9.6V12c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V9.58l1.79,-0.7l-1.6,8.1L4.4,16.19c-0.55,-0.12 -1.09,0.24 -1.21,0.8l0,0c-0.11,0.55 0.25,1.08 0.79,1.2l3.98,0.81c1.06,0.22 2.11,-0.46 2.35,-1.52l0.57,-2.49l2.11,2V22c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-5.66c0,-0.55 -0.23,-1.07 -0.62,-1.45l-1.49,-1.41l0.6,-3c1.07,1.24 2.63,2.15 4.37,2.43C18.46,13.01 19,12.52 19,11.91z"/>
+ android:pathData="M13.49,5.48c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM10.32,17.48l0.57,-2.5 2.1,2v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5.64c0,-0.55 -0.22,-1.07 -0.62,-1.45l-1.48,-1.41 0.6,-3c1.07,1.24 2.62,2.13 4.36,2.41 0.6,0.09 1.14,-0.39 1.14,-1 0,-0.49 -0.36,-0.9 -0.85,-0.98 -1.52,-0.25 -2.78,-1.15 -3.45,-2.33l-1,-1.6c-0.4,-0.6 -1,-1 -1.7,-1 -0.3,0 -0.5,0.1 -0.8,0.1L7.21,7.76c-0.74,0.32 -1.22,1.04 -1.22,1.85v2.37c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.4l1.8,-0.7 -1.6,8.1 -3.92,-0.8c-0.54,-0.11 -1.07,0.24 -1.18,0.78L3.09,17c-0.11,0.54 0.24,1.07 0.78,1.18l4.11,0.82c1.06,0.21 2.1,-0.46 2.34,-1.52z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_subway.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_subway.xml
index aaf5774..bb4bf7c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_subway.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_subway.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C8,2 4,2.5 4,6v9.5C4,17.43 5.57,19 7.5,19l-1.21,0.81C6.11,19.93 6,20.13 6,20.35v0C6,20.71 6.29,21 6.65,21h10.7c0.36,0 0.65,-0.29 0.65,-0.65v0c0,-0.22 -0.11,-0.42 -0.29,-0.54L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5V6C20,2.5 16.42,2 12,2zM8.5,16C7.67,16 7,15.33 7,14.5S7.67,13 8.5,13s1.5,0.67 1.5,1.5S9.33,16 8.5,16zM11,10H6V7h5V10zM15.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S16.33,16 15.5,16zM18,10h-5V7h5V10z"/>
+ android:pathData="M12,2c-4.42,0 -8,0.5 -8,4v9.5C4,17.43 5.57,19 7.5,19l-1.15,1.15c-0.31,0.31 -0.09,0.85 0.36,0.85L17.3,21c0.45,0 0.67,-0.54 0.35,-0.85L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5L20,6c0,-3.5 -3.58,-4 -8,-4zM7.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,14 7.5,14s1.5,0.67 1.5,1.5S8.33,17 7.5,17zM11,11L6,11L6,6h5v5zM16.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM18,11h-5L13,6h5v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_transit.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_transit.xml
index aaf5774..bb4bf7c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_transit.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_transit.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C8,2 4,2.5 4,6v9.5C4,17.43 5.57,19 7.5,19l-1.21,0.81C6.11,19.93 6,20.13 6,20.35v0C6,20.71 6.29,21 6.65,21h10.7c0.36,0 0.65,-0.29 0.65,-0.65v0c0,-0.22 -0.11,-0.42 -0.29,-0.54L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5V6C20,2.5 16.42,2 12,2zM8.5,16C7.67,16 7,15.33 7,14.5S7.67,13 8.5,13s1.5,0.67 1.5,1.5S9.33,16 8.5,16zM11,10H6V7h5V10zM15.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S16.33,16 15.5,16zM18,10h-5V7h5V10z"/>
+ android:pathData="M12,2c-4.42,0 -8,0.5 -8,4v9.5C4,17.43 5.57,19 7.5,19l-1.15,1.15c-0.31,0.31 -0.09,0.85 0.36,0.85L17.3,21c0.45,0 0.67,-0.54 0.35,-0.85L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5L20,6c0,-3.5 -3.58,-4 -8,-4zM7.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,14 7.5,14s1.5,0.67 1.5,1.5S8.33,17 7.5,17zM11,11L6,11L6,6h5v5zM16.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM18,11h-5L13,6h5v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/directions_walk.xml b/compose/material/material/icons/generator/raw-icons/rounded/directions_walk.xml
index 4513045..adfca41 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/directions_walk.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/directions_walk.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S12.4,5.5 13.5,5.5zM9.8,8.9L7.24,21.81C7.11,22.42 7.59,23 8.22,23H8.3c0.47,0 0.87,-0.32 0.98,-0.78L10.9,15l2.1,2v5c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-5.64c0,-0.55 -0.22,-1.07 -0.62,-1.45L12.9,13.5l0.6,-3c1.07,1.24 2.62,2.13 4.36,2.41c0.6,0.09 1.14,-0.39 1.14,-1l0,0c0,-0.49 -0.36,-0.9 -0.85,-0.98c-1.52,-0.25 -2.78,-1.15 -3.45,-2.33l-1,-1.6l0,0c-0.56,-0.89 -1.68,-1.25 -2.65,-0.84L7.22,7.78C6.48,8.1 6,8.82 6,9.63V12c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V9.6L9.8,8.9"/>
+ android:pathData="M13.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM9.8,8.9L7.24,21.81c-0.13,0.61 0.35,1.19 0.98,1.19h0.08c0.47,0 0.87,-0.32 0.98,-0.78L10.9,15l2.1,2v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5.64c0,-0.55 -0.22,-1.07 -0.62,-1.45L12.9,13.5l0.6,-3c1.07,1.24 2.62,2.13 4.36,2.41 0.6,0.09 1.14,-0.39 1.14,-1 0,-0.49 -0.36,-0.9 -0.85,-0.98 -1.52,-0.25 -2.78,-1.15 -3.45,-2.33l-1,-1.6c-0.56,-0.89 -1.68,-1.25 -2.65,-0.84L7.22,7.78C6.48,8.1 6,8.82 6,9.63V12c0,0.55 0.45,1 1,1s1,-0.45 1,-1V9.6l1.8,-0.7"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/disabled_visible.xml b/compose/material/material/icons/generator/raw-icons/rounded/disabled_visible.xml
new file mode 100644
index 0000000..dfeb407
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/disabled_visible.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21.99,12.34C22,12.23 22,12.11 22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12c0,5.17 3.93,9.43 8.96,9.95c-0.93,-0.73 -1.72,-1.64 -2.32,-2.68C5.9,18 4,15.22 4,12c0,-1.85 0.63,-3.55 1.69,-4.9l5.66,5.66c0.56,-0.4 1.17,-0.73 1.82,-1L7.1,5.69C8.45,4.63 10.15,4 12,4c4.24,0 7.7,3.29 7.98,7.45C20.69,11.67 21.37,11.97 21.99,12.34zM17,13c-3.18,0 -5.9,1.87 -7,4.5c1.1,2.63 3.82,4.5 7,4.5s5.9,-1.87 7,-4.5C22.9,14.87 20.18,13 17,13zM17,20c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C19.5,18.88 18.38,20 17,20zM18.5,17.5c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5S18.5,16.67 18.5,17.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/disc_full.xml b/compose/material/material/icons/generator/raw-icons/rounded/disc_full.xml
index 589c41b..a0b541a4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/disc_full.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/disc_full.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C5.92,2 1.1,7.44 2.14,13.72c0.65,3.89 3.64,7.09 7.48,8c3.14,0.75 6.13,-0.04 8.38,-1.74V10c0,-1.1 0.9,-2 2,-2h1.16C19.62,4.47 16.1,2 12,2zM12,16.5c-2.49,0 -4.5,-2.01 -4.5,-4.5S9.51,7.5 12,7.5s4.5,2.01 4.5,4.5S14.49,16.5 12,16.5zM12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S12.55,11 12,11zM20,11v6c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1h0C20.45,10 20,10.45 20,11zM21,20c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S21.55,20 21,20z"/>
+ android:pathData="M20,16h2v-2h-2v2zM20,8v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L22,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM10,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8 8,-3.58 8,-8 -3.58,-8 -8,-8zM10,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/dns.xml b/compose/material/material/icons/generator/raw-icons/rounded/dns.xml
index 49aea8c..a43abcc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/dns.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/dns.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,13H4c-0.55,0 -1,0.45 -1,1v7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-7C21,13.45 20.55,13 20,13zM7.5,19C6.67,19 6,18.33 6,17.5S6.67,16 7.5,16S9,16.67 9,17.5S8.33,19 7.5,19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,3H4C3.45,3 3,3.45 3,4v7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1V4C21,3.45 20.55,3 20,3zM7.5,9C6.67,9 6,8.33 6,7.5S6.67,6 7.5,6S9,6.67 9,7.5S8.33,9 7.5,9z"/>
+ android:pathData="M19,13H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2zM7,19c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM19,3H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2zM7,9c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb.xml b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb.xml
index 16a9b46..b5c518b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM4,12c0,-4.4 3.6,-8 8,-8c1.8,0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4,13.8 4,12zM12,20c-1.8,0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20,10.2 20,12C20,16.4 16.4,20 12,20z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8 0,-1.85 0.63,-3.55 1.69,-4.9L16.9,18.31C15.55,19.37 13.85,20 12,20zM18.31,16.9L7.1,5.69C8.45,4.63 10.15,4 12,4c4.42,0 8,3.58 8,8 0,1.85 -0.63,3.55 -1.69,4.9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_alt.xml
index cb2d8a7..3354d6e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_alt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8c0,-1.85 0.63,-3.55 1.69,-4.9L16.9,18.31C15.55,19.37 13.85,20 12,20zM18.31,16.9L7.1,5.69C8.45,4.63 10.15,4 12,4c4.42,0 8,3.58 8,8C20,13.85 19.37,15.55 18.31,16.9z"/>
+ android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10 10,-4.5 10,-10S17.5,2 12,2zM4,12c0,-4.4 3.6,-8 8,-8 1.8,0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4,13.8 4,12zM12,20c-1.8,0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20,10.2 20,12c0,4.4 -3.6,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_off.xml
index e780447..b56b8f1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,11v2h-1.17l4.51,4.51C21.39,15.93 22,14.04 22,12c0,-5.52 -4.48,-10 -10,-10C9.96,2 8.07,2.61 6.49,3.66L13.83,11H17zM2.1,4.93l1.56,1.56c-1.37,2.07 -2,4.68 -1.48,7.45c0.75,3.95 3.92,7.13 7.88,7.88c2.77,0.52 5.38,-0.1 7.45,-1.48l1.56,1.56c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.71,3.91 1.71,4.54 2.1,4.93zM7,11h1.17l2,2H7V11z"/>
+ android:pathData="M17,11v2h-0.88l4.33,4.33C21.43,15.79 22,13.96 22,12c0,-5.52 -4.48,-10 -10,-10 -1.96,0 -3.79,0.57 -5.33,1.55L14.12,11L17,11zM21.17,20.88L3.12,2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.07,2.07C2.66,7.93 2,9.89 2,12c0,5.52 4.48,10 10,10 2.11,0 4.07,-0.66 5.68,-1.78l2.07,2.07c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.39 0.4,-1.02 0.01,-1.41zM7,13v-2h1.46l2,2L7,13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_on.xml
index 3f1ee44..68d8599 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/do_disturb_on.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM16,13H8c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1l0,0C17,12.55 16.55,13 16,13z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM16,13L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/dock.xml b/compose/material/material/icons/generator/raw-icons/rounded/dock.xml
index ee40dd4..a157947 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/dock.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/dock.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,21H9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c0.55,0 1,-0.45 1,-1S15.55,21 15,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,1.01L8,1C6.9,1 6,1.9 6,3v14c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V3C18,1.9 17.1,1.01 16,1.01zM16,14H8V6h8V14z"/>
+ android:pathData="M9,23h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L9,21c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM16,1.01L8,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,3c0,-1.1 -0.9,-1.99 -2,-1.99zM16,15L8,15L8,5h8v10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/document_scanner.xml b/compose/material/material/icons/generator/raw-icons/rounded/document_scanner.xml
new file mode 100644
index 0000000..9340fec
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/document_scanner.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,6C2.45,6 2,5.55 2,5V2c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1S6.55,3 6,3H4v2C4,5.55 3.55,6 3,6zM17,2c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V2c0,-0.55 -0.45,-1 -1,-1h-3C17.45,1 17,1.45 17,2zM3,18c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1H4v-2C4,18.45 3.55,18 3,18zM17,22c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2C17.45,21 17,21.45 17,22zM19,18c0,1.1 -0.9,2 -2,2H7c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10c1.1,0 2,0.9 2,2V18zM9,9c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-4C9.45,8 9,8.45 9,9zM9,12c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-4C9.45,11 9,11.45 9,12zM9,15c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-4C9.45,14 9,14.45 9,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/domain.xml b/compose/material/material/icons/generator/raw-icons/rounded/domain.xml
index 4ccc403..e54a454 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/domain.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/domain.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7V4c0,-0.55 -0.45,-1 -1,-1H3C2.45,3 2,3.45 2,4v16c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1H12zM6,19H4v-2h2V19zM6,15H4v-2h2V15zM6,11H4V9h2V11zM6,7H4V5h2V7zM10,19H8v-2h2V19zM10,15H8v-2h2V15zM10,11H8V9h2V11zM10,7H8V5h2V7zM20,19h-8v-2h2v-2h-2v-2h2v-2h-2V9h8V19zM18,11h-2v2h2V11zM18,15h-2v2h2V15z"/>
+ android:pathData="M12,7L12,5c0,-1.1 -0.9,-2 -2,-2L4,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,9c0,-1.1 -0.9,-2 -2,-2h-8zM6,19L4,19v-2h2v2zM6,15L4,15v-2h2v2zM6,11L4,11L4,9h2v2zM6,7L4,7L4,5h2v2zM10,19L8,19v-2h2v2zM10,15L8,15v-2h2v2zM10,11L8,11L8,9h2v2zM10,7L8,7L8,5h2v2zM19,19h-7v-2h2v-2h-2v-2h2v-2h-2L12,9h7c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1zM18,11h-2v2h2v-2zM18,15h-2v2h2v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/domain_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/domain_disabled.xml
index 5adc149..bf862fd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/domain_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/domain_disabled.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.83,3l2,2L10,5l0,2.17L11.83,9L20,9v8.17l2,2V8c0,-0.55 -0.45,-1 -1,-1h-9V4c0,-0.55 -0.45,-1 -1,-1H5.83z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1.39,2.81L1.39,2.81C1,3.2 1,3.83 1.39,4.22L2,4.83V20c0,0.55 0.45,1 1,1h15.17l1.61,1.61c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81C2.42,2.42 1.78,2.42 1.39,2.81zM6,19H4v-2h2V19zM6,15H4v-2h2V15zM6,11H4V9h2V11zM10,19H8v-2h2V19zM10,15H8v-2h2V15zM12,19v-2h2.17l2,2H12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,11h2v2h-2z"/>
+ android:pathData="M0.71,2.39c-0.39,0.39 -0.39,1.02 0,1.41L2,5.1L2,19c0,1.1 0.9,2 2,2h13.9l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L2.12,2.39C1.73,2 1.1,2 0.71,2.39zM6,19L4,19v-2h2v2zM6,15L4,15v-2h2v2zM4,11L4,9h2v2L4,11zM10,19L8,19v-2h2v2zM8,15v-2h2v2L8,15zM12,19v-2h1.9l2,2L12,19zM8,5h2v2h-0.45L12,9.45L12,9h7c0.55,0 1,0.45 1,1v7.45l2,2L22,9c0,-1.1 -0.9,-2 -2,-2h-8L12,5c0,-1.1 -0.9,-2 -2,-2L5.55,3L8,5.45L8,5zM16,11h2v2h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/domain_verification.xml b/compose/material/material/icons/generator/raw-icons/rounded/domain_verification.xml
index 553f77ca..7854ccb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/domain_verification.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/domain_verification.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2,4.9 2,6v12c0,1.1 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.11,4 20,4zM20,18H4V8h16V18zM15.89,10.17L15.89,10.17c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.54,3.54l-1.41,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l2.12,2.12c0.39,0.39 1.02,0.39 1.41,0l4.24,-4.24C16.28,11.2 16.28,10.56 15.89,10.17z"/>
+ android:pathData="M10.23,15.83c0.39,0.39 1.02,0.39 1.41,0l4.24,-4.24c0.39,-0.39 0.39,-1.02 0,-1.42v0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.54,3.53l-1.41,-1.41c-0.39,-0.39 -1.02,-0.39 -1.42,0s-0.39,1.02 0,1.41L10.23,15.83z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,4H5C3.89,4 3,4.9 3,6v12c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.11,4 19,4zM19,17c0,0.55 -0.45,1 -1,1H6c-0.55,0 -1,-0.45 -1,-1V8h14V17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/done.xml b/compose/material/material/icons/generator/raw-icons/rounded/done.xml
index 8f3250d..6a86ea5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/done.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/done.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,6.7l-8.48,8.48l-3.54,-3.54c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l4.24,4.24c0.39,0.39 1.02,0.39 1.41,0l9.18,-9.18c0.39,-0.39 0.39,-1.03 -0.01,-1.42l0,0C19.02,6.31 18.39,6.31 18,6.7z"/>
+ android:pathData="M9,16.2l-3.5,-3.5c-0.39,-0.39 -1.01,-0.39 -1.4,0 -0.39,0.39 -0.39,1.01 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7c0.39,-0.39 0.39,-1.01 0,-1.4 -0.39,-0.39 -1.01,-0.39 -1.4,0L9,16.2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/done_all.xml b/compose/material/material/icons/generator/raw-icons/rounded/done_all.xml
index 1399b44f..5ce8c1e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/done_all.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/done_all.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.83,6.7l-8.48,8.48l-3.54,-3.53c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l4.24,4.24c0.39,0.39 1.02,0.39 1.41,0l9.18,-9.18c0.39,-0.39 0.39,-1.03 -0.01,-1.42l0,0C21.84,6.31 21.22,6.32 20.83,6.7zM16.6,6.7L16.6,6.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.24,4.24l1.41,1.41l4.24,-4.24C16.99,7.72 16.99,7.09 16.6,6.7zM1.75,13.06l4.24,4.24c0.39,0.39 1.02,0.39 1.41,0l0.71,-0.71l-4.95,-4.95c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.36,12.04 1.36,12.67 1.75,13.06z"/>
+ android:pathData="M17.3,6.3c-0.39,-0.39 -1.02,-0.39 -1.41,0l-5.64,5.64 1.41,1.41L17.3,7.7c0.38,-0.38 0.38,-1.02 0,-1.4zM21.54,6.29l-9.88,9.88 -3.48,-3.47c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L22.95,7.71c0.39,-0.39 0.39,-1.02 0,-1.41h-0.01c-0.38,-0.4 -1.01,-0.4 -1.4,-0.01zM1.12,14.12L5.3,18.3c0.39,0.39 1.02,0.39 1.41,0l0.7,-0.7 -4.88,-4.9c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.03 0,1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/done_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/done_outline.xml
index 9dae9ca..3bfa893 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/done_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/done_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.69,5.99l1.43,1.4L9.52,18l-5.66,-5.66l1.41,-1.41l4.24,4.24L18.69,5.99M9.52,12.34L6.69,9.51c-0.78,-0.78 -2.05,-0.78 -2.83,0l-1.42,1.41c-0.78,0.78 -0.78,2.05 0,2.83l5.66,5.66c0.78,0.78 2.05,0.78 2.83,0L21.54,8.8c0.79,-0.79 0.78,-2.07 -0.02,-2.84l-1.43,-1.4c-0.78,-0.77 -2.04,-0.76 -2.81,0.02L9.52,12.34z"/>
+ android:pathData="M20.47,5.63c0.39,0.39 0.39,1.01 0,1.4L9.13,18.37c-0.39,0.39 -1.01,0.39 -1.4,0l-4.2,-4.2c-0.39,-0.39 -0.39,-1.01 0,-1.4 0.39,-0.39 1.01,-0.39 1.4,0l3.5,3.5L19.07,5.63c0.39,-0.39 1.01,-0.39 1.4,0zM18.36,3.51l-9.93,9.93 -2.79,-2.79c-0.78,-0.78 -2.05,-0.78 -2.83,0l-1.4,1.4c-0.78,0.78 -0.78,2.05 0,2.83l5.6,5.6c0.78,0.78 2.05,0.78 2.83,0L22.59,7.74c0.78,-0.78 0.78,-2.05 0,-2.83l-1.4,-1.4c-0.79,-0.78 -2.05,-0.78 -2.83,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/donut_large.xml b/compose/material/material/icons/generator/raw-icons/rounded/donut_large.xml
index a4b33ae..98db1bc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/donut_large.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/donut_large.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.02,5.08c3.06,0.44 5.48,2.86 5.92,5.92h3.03c-0.47,-4.72 -4.23,-8.48 -8.95,-8.95L13.02,5.08zM18.94,13c-0.44,3.06 -2.86,5.48 -5.92,5.92v3.03c4.72,-0.47 8.48,-4.23 8.95,-8.95L18.94,13zM11.02,18.92c-3.39,-0.49 -6,-3.4 -6,-6.92s2.61,-6.43 6,-6.92V2.05c-5.05,0.5 -9,4.76 -9,9.95s3.95,9.45 9,9.95V18.92z"/>
+ android:pathData="M14.07,5.32C16.26,6 18,7.74 18.68,9.93c0.19,0.63 0.76,1.07 1.41,1.07h0.04c1,0 1.72,-0.96 1.43,-1.91 -0.97,-3.18 -3.48,-5.69 -6.66,-6.66 -0.94,-0.29 -1.9,0.43 -1.9,1.43v0.04c0,0.66 0.44,1.23 1.07,1.42zM18.68,14.07c-0.68,2.2 -2.42,3.93 -4.61,4.61 -0.63,0.19 -1.07,0.76 -1.07,1.41v0.04c0,1 0.96,1.72 1.91,1.43 3.18,-0.97 5.69,-3.48 6.66,-6.66 0.29,-0.95 -0.43,-1.91 -1.42,-1.91h-0.05c-0.66,0.01 -1.23,0.45 -1.42,1.08zM11,20.11c0,-0.67 -0.45,-1.24 -1.09,-1.44C7.07,17.78 5,15.13 5,12s2.07,-5.78 4.91,-6.67c0.64,-0.2 1.09,-0.77 1.09,-1.44v-0.01c0,-1 -0.97,-1.74 -1.93,-1.44C4.98,3.69 2,7.5 2,12c0,4.5 2.98,8.31 7.07,9.56 0.96,0.3 1.93,-0.44 1.93,-1.45z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/donut_small.xml b/compose/material/material/icons/generator/raw-icons/rounded/donut_small.xml
index 3c9e616..ff69f48 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/donut_small.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/donut_small.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.02,9.18c0.85,0.3 1.51,0.97 1.82,1.82h7.13c-0.47,-4.72 -4.23,-8.48 -8.95,-8.95L13.02,9.18zM11.02,14.82c-1.16,-0.42 -2,-1.52 -2,-2.82s0.84,-2.4 2,-2.82V2.05c-5.05,0.5 -9,4.76 -9,9.95s3.95,9.45 9,9.95V14.82zM14.84,13c-0.3,0.85 -0.97,1.51 -1.82,1.82v7.13c4.72,-0.47 8.48,-4.23 8.95,-8.95L14.84,13z"/>
+ android:pathData="M11,3.18v17.64c0,0.64 -0.59,1.12 -1.21,0.98C5.32,20.8 2,16.79 2,12s3.32,-8.8 7.79,-9.8c0.62,-0.14 1.21,0.34 1.21,0.98zM13.03,3.18v6.81c0,0.55 0.45,1 1,1h6.79c0.64,0 1.12,-0.59 0.98,-1.22 -0.85,-3.76 -3.8,-6.72 -7.55,-7.57 -0.63,-0.14 -1.22,0.34 -1.22,0.98zM13.03,14.01v6.81c0,0.64 0.59,1.12 1.22,0.98 3.76,-0.85 6.71,-3.82 7.56,-7.58 0.14,-0.62 -0.35,-1.22 -0.98,-1.22h-6.79c-0.56,0.01 -1.01,0.46 -1.01,1.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/double_arrow.xml b/compose/material/material/icons/generator/raw-icons/rounded/double_arrow.xml
index 3c0d60b..3e1784b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/double_arrow.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/double_arrow.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.99,5h-0.04c-0.81,0 -1.29,0.92 -0.81,1.58L17,12l-3.87,5.42c-0.47,0.66 0,1.58 0.81,1.58h0.04c0.32,0 0.63,-0.16 0.81,-0.42l4.29,-6c0.25,-0.35 0.25,-0.81 0,-1.16l-4.29,-6C14.61,5.16 14.31,5 13.99,5z"/>
+ android:pathData="M20.08,11.42l-4.04,-5.65C15.7,5.29 15.15,5 14.56,5h0c-1.49,0 -2.35,1.68 -1.49,2.89L16,12l-2.93,4.11c-0.87,1.21 0,2.89 1.49,2.89h0c0.59,0 1.15,-0.29 1.49,-0.77l4.04,-5.65C20.33,12.23 20.33,11.77 20.08,11.42z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M7.99,5H7.94C7.13,5 6.66,5.92 7.13,6.58L11,12l-3.87,5.42C6.66,18.08 7.13,19 7.94,19h0.04c0.32,0 0.63,-0.16 0.81,-0.42l4.29,-6c0.25,-0.35 0.25,-0.81 0,-1.16l-4.29,-6C8.61,5.16 8.31,5 7.99,5z"/>
+ android:pathData="M13.08,11.42L9.05,5.77C8.7,5.29 8.15,5 7.56,5h0C6.07,5 5.2,6.68 6.07,7.89L9,12l-2.93,4.11C5.2,17.32 6.07,19 7.56,19h0c0.59,0 1.15,-0.29 1.49,-0.77l4.04,-5.65C13.33,12.23 13.33,11.77 13.08,11.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/download.xml b/compose/material/material/icons/generator/raw-icons/rounded/download.xml
index 876e1d0..dd79e4c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/download.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/download.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.59,9H15V4c0,-0.55 -0.45,-1 -1,-1h-4C9.45,3 9,3.45 9,4v5H7.41c-0.89,0 -1.34,1.08 -0.71,1.71l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59C17.92,10.08 17.48,9 16.59,9zM5,19c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6C5.45,18 5,18.45 5,19z"/>
+ android:pathData="M16.59,9H15V4c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v5H7.41c-0.89,0 -1.34,1.08 -0.71,1.71l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.63,-0.63 0.19,-1.71 -0.7,-1.71zM5,19c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/download_done.xml b/compose/material/material/icons/generator/raw-icons/rounded/download_done.xml
index 02c68fa..612f498 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/download_done.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/download_done.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.42,4.71L19.42,4.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l-8.48,8.49L5.99,9.66c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l4.24,4.24c0.39,0.39 1.02,0.39 1.41,0l9.19,-9.19C19.82,5.73 19.82,5.1 19.42,4.71z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,20h12c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1v0C5,19.55 5.45,20 6,20z"/>
+ android:pathData="M6,18h12c0.55,0 1,0.45 1,1s-0.45,1 -1,1L6,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM11.01,13.9c-0.78,0.77 -2.04,0.77 -2.82,-0.01L6,11.7c-0.55,-0.55 -0.54,-1.44 0.03,-1.97 0.54,-0.52 1.4,-0.5 1.92,0.02L9.6,11.4l6.43,-6.43c0.54,-0.54 1.41,-0.54 1.95,0l0.04,0.04c0.54,0.54 0.54,1.42 -0.01,1.96l-7,6.93z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/drafts.xml b/compose/material/material/icons/generator/raw-icons/rounded/drafts.xml
index 47be9f3..368c0ff 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/drafts.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/drafts.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,8c0,-0.72 -0.38,-1.35 -0.95,-1.7l-8.04,-4.71c-0.62,-0.37 -1.4,-0.37 -2.02,0L2.95,6.3C2.38,6.65 2,7.28 2,8v11c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8zM10.94,12.34l-7.2,-4.5l7.75,-4.54c0.31,-0.18 0.7,-0.18 1.01,0l7.75,4.54l-7.2,4.5C12.41,12.74 11.59,12.74 10.94,12.34z"/>
+ android:pathData="M21.99,8c0,-0.72 -0.37,-1.35 -0.94,-1.7l-8.04,-4.71c-0.62,-0.37 -1.4,-0.37 -2.02,0L2.95,6.3C2.38,6.65 2,7.28 2,8v10c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2l-0.01,-10zM10.94,12.34l-7.2,-4.5 7.25,-4.25c0.62,-0.37 1.4,-0.37 2.02,0l7.25,4.25 -7.2,4.5c-0.65,0.4 -1.47,0.4 -2.12,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/drag_handle.xml b/compose/material/material/icons/generator/raw-icons/rounded/drag_handle.xml
index 1213b7f..3f4f79c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/drag_handle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/drag_handle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,9H5c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1l0,0C20,9.45 19.55,9 19,9zM5,15h14c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1l0,0C4,14.55 4.45,15 5,15z"/>
+ android:pathData="M19,9H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM5,15h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/drag_indicator.xml b/compose/material/material/icons/generator/raw-icons/rounded/drag_indicator.xml
index 2aa0790..6dcde80 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/drag_indicator.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/drag_indicator.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,18c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2s0.9,-2 2,-2S11,16.9 11,18zM9,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S10.1,10 9,10zM9,4C7.9,4 7,4.9 7,6s0.9,2 2,2s2,-0.9 2,-2S10.1,4 9,4zM15,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S13.9,8 15,8zM15,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S16.1,10 15,10zM15,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S16.1,16 15,16z"/>
+ android:pathData="M11,18c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2 2,0.9 2,2zM9,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM9,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM15,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/draw.xml b/compose/material/material/icons/generator/raw-icons/rounded/draw.xml
new file mode 100644
index 0000000..0be4c61
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/draw.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.85,10.39l1.06,-1.06c0.78,-0.78 0.78,-2.05 0,-2.83L18.5,5.09c-0.78,-0.78 -2.05,-0.78 -2.83,0l-1.06,1.06L18.85,10.39zM13.19,7.56l-9.05,9.05C4.05,16.7 4,16.83 4,16.96v3.54C4,20.78 4.22,21 4.5,21h3.54c0.13,0 0.26,-0.05 0.35,-0.15l9.05,-9.05L13.19,7.56zM19,17.5c0,2.19 -2.54,3.5 -5,3.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1c1.54,0 3,-0.73 3,-1.5c0,-0.47 -0.48,-0.87 -1.23,-1.2l1.48,-1.48C18.32,15.45 19,16.29 19,17.5zM4.58,13.35C3.61,12.79 3,12.06 3,11c0,-1.8 1.89,-2.63 3.56,-3.36C7.59,7.18 9,6.56 9,6c0,-0.41 -0.78,-1 -2,-1C5.74,5 5.2,5.61 5.17,5.64C4.82,6.05 4.19,6.1 3.77,5.76C3.36,5.42 3.28,4.81 3.62,4.38C3.73,4.24 4.76,3 7,3c2.24,0 4,1.32 4,3c0,1.87 -1.93,2.72 -3.64,3.47C6.42,9.88 5,10.5 5,11c0,0.31 0.43,0.6 1.07,0.86L4.58,13.35z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/drive_eta.xml b/compose/material/material/icons/generator/raw-icons/rounded/drive_eta.xml
index fbfe158..f1714e4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/drive_eta.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/drive_eta.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5h-11C5.84,5 5.29,5.42 5.08,6.01L3,12v7.5C3,20.33 3.67,21 4.5,21h0C5.33,21 6,20.33 6,19.5V19h12v0.5c0,0.82 0.67,1.5 1.5,1.5h0c0.82,0 1.5,-0.67 1.5,-1.5V12L18.92,6.01zM7.5,16C6.67,16 6,15.33 6,14.5S6.67,13 7.5,13S9,13.67 9,14.5S8.33,16 7.5,16zM16.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S17.33,16 16.5,16zM5.81,10l1.04,-3h10.29l1.04,3H5.81z"/>
+ android:pathData="M18.92,5.01C18.72,4.42 18.16,4 17.5,4h-11c-0.66,0 -1.21,0.42 -1.42,1.01l-1.97,5.67c-0.07,0.21 -0.11,0.43 -0.11,0.66v7.16c0,0.83 0.67,1.5 1.5,1.5S6,19.33 6,18.5L6,18h12v0.5c0,0.82 0.67,1.5 1.5,1.5 0.82,0 1.5,-0.67 1.5,-1.5v-7.16c0,-0.22 -0.04,-0.45 -0.11,-0.66l-1.97,-5.67zM6.5,15c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,12 6.5,12s1.5,0.67 1.5,1.5S7.33,15 6.5,15zM17.5,15c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,10l1.27,-3.82c0.14,-0.4 0.52,-0.68 0.95,-0.68h9.56c0.43,0 0.81,0.28 0.95,0.68L19,10L5,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/drive_file_move_rtl.xml b/compose/material/material/icons/generator/raw-icons/rounded/drive_file_move_rtl.xml
new file mode 100644
index 0000000..eb75921
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/drive_file_move_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM11.15,16.15l-2.79,-2.79c-0.2,-0.2 -0.2,-0.51 0,-0.71l2.79,-2.79C11.46,9.54 12,9.76 12,10.21V12h3c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1h-3v1.79C12,16.24 11.46,16.46 11.15,16.15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/duo.xml b/compose/material/material/icons/generator/raw-icons/rounded/duo.xml
index 388fafa..acc6429 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/duo.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/duo.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2h-8C6.38,2 2,6.66 2,12.28C2,17.5 6.49,22 11.72,22C17.39,22 22,17.62 22,12V4C22,2.9 21.1,2 20,2zM17,15l-3,-2v2H7V9h7v2l3,-2V15z"/>
+ android:pathData="M20,2h-8C6.38,2 2,6.66 2,12.28 2,17.5 6.49,22 11.72,22 17.39,22 22,17.62 22,12L22,4c0,-1.1 -0.9,-2 -2,-2zM17,15l-3,-2v2L7,15L7,9h7v2l3,-2v6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/dvr.xml b/compose/material/material/icons/generator/raw-icons/rounded/dvr.xml
index cd6a4e3..d253535 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/dvr.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/dvr.xml
@@ -7,11 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h4c1.1,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3zM20,17H4V5h16V17zM17,8h-7C9.45,8 9,8.45 9,9v0c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1v0C18,8.45 17.55,8 17,8zM17,12h-7c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1v0C18,12.45 17.55,12 17,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,9m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,13m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h5c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM20,17L4,17c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1zM18,8L9,8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM18,12L9,12c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM7,8L5,8v2h2L7,8zM7,12L5,12v2h2v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/edit.xml b/compose/material/material/icons/generator/raw-icons/rounded/edit.xml
index 89fee4c..1599eed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/edit.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/edit.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,17.46l0,3.04C3,20.78 3.22,21 3.5,21h3.04c0.13,0 0.26,-0.05 0.35,-0.15L17.81,9.94l-3.75,-3.75L3.15,17.1C3.05,17.2 3,17.32 3,17.46z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83l3.75,3.75l1.83,-1.83C21.1,6.65 21.1,6.02 20.71,5.63z"/>
+ android:pathData="M3,17.46v3.04c0,0.28 0.22,0.5 0.5,0.5h3.04c0.13,0 0.26,-0.05 0.35,-0.15L17.81,9.94l-3.75,-3.75L3.15,17.1c-0.1,0.1 -0.15,0.22 -0.15,0.36zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/edit_attributes.xml b/compose/material/material/icons/generator/raw-icons/rounded/edit_attributes.xml
index 4e775db..1ffe54b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/edit_attributes.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/edit_attributes.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,7H7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h10c2.76,0 5,-2.24 5,-5S19.76,7 17,7zM7.34,13.59l-0.81,-0.82c-0.29,-0.29 -0.29,-0.77 0,-1.06l0,0c0.29,-0.29 0.77,-0.29 1.06,0l0.46,0.46l1.94,-1.94c0.3,-0.3 0.77,-0.29 1.07,0l0,0c0.29,0.29 0.29,0.77 0,1.06l-2.29,2.29C8.37,13.98 7.73,13.98 7.34,13.59z"/>
+ android:pathData="M17.63,7L6.37,7C3.96,7 2,9.24 2,12s1.96,5 4.37,5h11.26c2.41,0 4.37,-2.24 4.37,-5s-1.96,-5 -4.37,-5zM11.11,10.6L7.6,14.11c-0.1,0.1 -0.23,0.15 -0.35,0.15s-0.26,-0.05 -0.35,-0.15l-1.86,-1.86c-0.2,-0.2 -0.2,-0.51 0,-0.71s0.51,-0.2 0.71,0l1.51,1.51 3.16,-3.16c0.2,-0.2 0.51,-0.2 0.71,0s0.17,0.51 -0.02,0.71z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/edit_calendar.xml b/compose/material/material/icons/generator/raw-icons/rounded/edit_calendar.xml
new file mode 100644
index 0000000..bb529dd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/edit_calendar.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,22H5c-1.11,0 -2,-0.9 -2,-2L3.01,6c0,-1.1 0.88,-2 1.99,-2h1V3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v1h8V3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v1h1c1.1,0 2,0.9 2,2v6h-2v-2H5v10h7V22zM22.13,16.99l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41l-0.71,-0.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71L22.13,16.99zM21.42,17.7l-5.01,5.01c-0.18,0.18 -0.44,0.29 -0.7,0.29H14.5c-0.28,0 -0.5,-0.22 -0.5,-0.5v-1.21c0,-0.27 0.11,-0.52 0.29,-0.71l5.01,-5.01L21.42,17.7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/edit_note.xml b/compose/material/material/icons/generator/raw-icons/rounded/edit_note.xml
new file mode 100644
index 0000000..d710fa9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/edit_note.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,11c0,0.55 -0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h9C13.55,10 14,10.45 14,11zM3,7c0,0.55 0.45,1 1,1h9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4C3.45,6 3,6.45 3,7zM10,15c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h5C9.55,16 10,15.55 10,15zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.16,5.16C12.05,18.83 12,18.95 12,19.09v1.41c0,0.28 0.22,0.5 0.5,0.5h1.41c0.13,0 0.26,-0.05 0.35,-0.15l5.16,-5.16L17.3,13.58z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/edit_road.xml b/compose/material/material/icons/generator/raw-icons/rounded/edit_road.xml
index aaa80b6..be00b77 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/edit_road.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/edit_road.xml
@@ -6,20 +6,20 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,4L17,4c-0.55,0 -1,0.45 -1,1v4.49c0,0.89 1.08,1.34 1.71,0.71l0,0C17.89,10.01 18,9.75 18,9.49V5C18,4.45 17.55,4 17,4z"/>
+ android:pathData="M17,4L17,4c-0.55,0 -1,0.45 -1,1v6.9l2,-2V5C18,4.45 17.55,4 17,4z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M5,4L5,4c0.55,0 1,0.45 1,1v14c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V5C4,4.45 4.45,4 5,4z"/>
+ android:pathData="M5,20L5,20c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1h0C4.45,4 4,4.45 4,5v14C4,19.55 4.45,20 5,20z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,4L11,4c0.55,0 1,0.45 1,1v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V5C10,4.45 10.45,4 11,4z"/>
+ android:pathData="M11,8L11,8c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2C10,7.55 10.45,8 11,8z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,10L11,10c0.55,0 1,0.45 1,1v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-2C10,10.45 10.45,10 11,10z"/>
+ android:pathData="M11,14L11,14c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2C10,13.55 10.45,14 11,14z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,16L11,16c0.55,0 1,0.45 1,1v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-2C10,16.45 10.45,16 11,16z"/>
+ android:pathData="M11,20L11,20c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2C10,19.55 10.45,20 11,20z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M22.56,12.59l-1.15,-1.15c-0.59,-0.59 -1.54,-0.59 -2.12,0l-4.99,5C14.11,16.62 14,16.88 14,17.14V19c0,0.55 0.45,1 1,1h1.86c0.27,0 0.52,-0.11 0.71,-0.29l4.99,-5C23.15,14.12 23.15,13.17 22.56,12.59zM16.58,18.45h-1.03v-1.03L19,13.97L20.03,15L16.58,18.45z"/>
+ android:pathData="M22.56,12.59l-1.15,-1.15c-0.59,-0.59 -1.54,-0.59 -2.12,0L14,16.73v2.77c0,0.28 0.22,0.5 0.5,0.5h2.77l5.29,-5.29C23.15,14.12 23.15,13.17 22.56,12.59zM16.58,18.45h-1.03v-1.03L19,13.97L20.03,15L16.58,18.45z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/eject.xml b/compose/material/material/icons/generator/raw-icons/rounded/eject.xml
index 91aa037..a16cdbb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/eject.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/eject.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,17h12c0.55,0 1,0.45 1,1s-0.45,1 -1,1H6c-0.55,0 -1,-0.45 -1,-1S5.45,17 6,17zM11.17,6.25l-4.8,7.2C5.92,14.11 6.4,15 7.2,15h9.6c0.8,0 1.28,-0.89 0.83,-1.55l-4.8,-7.2C12.44,5.65 11.56,5.65 11.17,6.25z"/>
+ android:pathData="M6,17h12c0.55,0 1,0.45 1,1s-0.45,1 -1,1L6,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM11.17,6.25l-4.8,7.2c-0.45,0.66 0.03,1.55 0.83,1.55h9.6c0.8,0 1.28,-0.89 0.83,-1.55l-4.8,-7.2c-0.39,-0.6 -1.27,-0.6 -1.66,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/electric_bike.xml b/compose/material/material/icons/generator/raw-icons/rounded/electric_bike.xml
index 0643518..20e4edf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/electric_bike.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/electric_bike.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,7h-0.82l-1.7,-4.68C16.19,1.53 15.44,1 14.6,1H13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.6l1.46,4h-4.81l-0.36,-1h0.09c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8C7.45,4 7,4.45 7,5s0.45,1 1,1h0.75l1.82,5H9.9C9.46,8.77 7.59,7.12 5.25,7.01C2.45,6.87 0,9.2 0,12s2.2,5 5,5c2.46,0 4.45,-1.69 4.9,-4h4.2c0.44,2.23 2.31,3.88 4.65,3.99c2.8,0.13 5.25,-2.19 5.25,-5C24,9.2 21.8,7 19,7zM6,13h1.82c-0.42,1.23 -1.6,2.08 -3.02,1.99C3.31,14.9 2.07,13.64 2,12.14C1.93,10.39 3.27,9 5,9c1.33,0 2.42,0.83 2.82,2H6c-0.55,0 -1,0.45 -1,1S5.45,13 6,13zM14.1,11h-1.4l-0.73,-2H15C14.56,9.58 14.24,10.25 14.1,11zM18.88,15c-1.54,-0.06 -2.84,-1.37 -2.88,-2.92c-0.02,-0.96 0.39,-1.8 1.05,-2.36l0.62,1.7c0.19,0.52 0.76,0.79 1.28,0.6s0.79,-0.76 0.6,-1.28l-0.63,-1.73c0,0 0,0 0.01,-0.01C20.64,8.96 22,10.29 22,12C22,13.72 20.62,15.06 18.88,15z"/>
+ android:pathData="M19,7h-0.82l-1.7,-4.68C16.19,1.53 15.44,1 14.6,1H13c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h1.6l1.46,4h-4.81l-0.36,-1h0.09c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1H8C7.45,4 7,4.45 7,5c0,0.55 0.45,1 1,1h0.75l1.82,5H9.9C9.46,8.77 7.59,7.12 5.25,7.01C2.45,6.87 0,9.2 0,12c0,2.8 2.2,5 5,5c2.46,0 4.45,-1.69 4.9,-4h4.2c0.44,2.23 2.31,3.88 4.65,3.99c2.8,0.13 5.25,-2.19 5.25,-5C24,9.2 21.8,7 19,7zM6,13h1.82c-0.42,1.23 -1.6,2.08 -3.02,1.99C3.31,14.9 2.07,13.64 2,12.14C1.93,10.39 3.27,9 5,9c1.33,0 2.42,0.83 2.82,2H6c-0.55,0 -1,0.45 -1,1C5,12.55 5.45,13 6,13zM14.1,11h-1.4l-0.73,-2H15C14.56,9.58 14.24,10.25 14.1,11zM18.88,15c-1.54,-0.06 -2.84,-1.37 -2.88,-2.92c-0.02,-0.96 0.39,-1.8 1.05,-2.36l0.62,1.7c0.19,0.52 0.76,0.79 1.28,0.6c0.52,-0.19 0.79,-0.76 0.6,-1.28l-0.63,-1.73c0,0 0,0 0.01,-0.01C20.64,8.96 22,10.29 22,12C22,13.72 20.62,15.06 18.88,15z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M11,20l-4,0l6,3l0,-2l4,0l-6,-3z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/electric_car.xml b/compose/material/material/icons/generator/raw-icons/rounded/electric_car.xml
index 9cd1901..47b8fe2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/electric_car.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/electric_car.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,20l-4,0l6,3l0,-2l4,0l-6,-3z"/>
+ android:pathData="M18.92,2.01C18.72,1.42 18.16,1 17.5,1h-11C5.84,1 5.29,1.42 5.08,2.01L3.11,7.68C3.04,7.89 3,8.11 3,8.34v7.16C3,16.33 3.67,17 4.5,17h0C5.33,17 6,16.33 6,15.5V15h12v0.5c0,0.82 0.67,1.5 1.5,1.5h0c0.82,0 1.5,-0.67 1.5,-1.5V8.34c0,-0.22 -0.04,-0.45 -0.11,-0.66L18.92,2.01zM6.5,12C5.67,12 5,11.33 5,10.5S5.67,9 6.5,9S8,9.67 8,10.5S7.33,12 6.5,12zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9S19,9.67 19,10.5S18.33,12 17.5,12zM5,7l1.27,-3.82C6.41,2.78 6.79,2.5 7.22,2.5h9.56c0.43,0 0.81,0.28 0.95,0.68L19,7H5z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M18.92,2.01C18.72,1.42 18.16,1 17.5,1h-11C5.84,1 5.29,1.42 5.08,2.01L3,8v7.5C3,16.32 3.67,17 4.5,17S6,16.32 6,15.5V15h12v0.5c0,0.82 0.67,1.5 1.5,1.5s1.5,-0.68 1.5,-1.5V8L18.92,2.01zM7.5,12C6.67,12 6,11.33 6,10.5S6.67,9 7.5,9S9,9.67 9,10.5S8.33,12 7.5,12zM16.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S15.67,9 16.5,9S18,9.67 18,10.5S17.33,12 16.5,12zM5.81,6l1.04,-3h10.29l1.04,3H5.81z"/>
+ android:pathData="M7,20l4,0l0,-2l6,3l-4,0l0,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/electric_moped.xml b/compose/material/material/icons/generator/raw-icons/rounded/electric_moped.xml
index 105294c..ccca770 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/electric_moped.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/electric_moped.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,5c0,-1.1 -0.9,-2 -2,-2h-2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h2v2.65L13.52,12H10V8c0,-0.55 -0.45,-1 -1,-1H6c-2.21,0 -4,1.79 -4,4v3h2c0,1.66 1.34,3 3,3s3,-1.34 3,-3h4.48L19,8.35V5zM7,15c-0.55,0 -1,-0.45 -1,-1h2C8,14.55 7.55,15 7,15z"/>
+ android:pathData="M19,5c0,-1.1 -0.9,-2 -2,-2h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2.65L13.52,12H10V8c0,-0.55 -0.45,-1 -1,-1H6c-2.21,0 -4,1.79 -4,4v3h2c0,1.66 1.34,3 3,3s3,-1.34 3,-3h4.48L19,8.35V5zM7,15c-0.55,0 -1,-0.45 -1,-1h2C8,14.55 7.55,15 7,15z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M9,4H6C5.45,4 5,4.45 5,5l0,0c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1l0,0C10,4.45 9.55,4 9,4z"/>
+ android:pathData="M9,4H6C5.45,4 5,4.45 5,5v0c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v0C10,4.45 9.55,4 9,4z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M19,11c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,11 19,11zM19,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S19.55,15 19,15z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/electric_rickshaw.xml b/compose/material/material/icons/generator/raw-icons/rounded/electric_rickshaw.xml
index db6cfcd..6eaacf9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/electric_rickshaw.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/electric_rickshaw.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,11.18V9.72c0,-0.47 -0.16,-0.92 -0.46,-1.28L16.6,3.72C16.22,3.26 15.66,3 15.06,3H3C1.9,3 1,3.9 1,5v8c0,1.1 0.9,2 2,2h0.18C3.6,16.16 4.7,17 6,17s2.4,-0.84 2.82,-2h8.37c0.41,1.16 1.51,2 2.82,2c1.66,0 3,-1.34 3,-3C23,12.7 22.16,11.6 21,11.18zM18.4,9H16V6.12L18.4,9zM3,5h4v4H3V5zM6,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S6.55,15 6,15zM9,13v-2h2c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H9V5h5v8H9zM20,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.55,15 20,15z"/>
+ android:pathData="M21,11.18V9.72c0,-0.47 -0.16,-0.92 -0.46,-1.28L16.6,3.72C16.22,3.26 15.66,3 15.06,3H3C1.9,3 1,3.9 1,5v8c0,1.1 0.9,2 2,2h0.18C3.6,16.16 4.7,17 6,17s2.4,-0.84 2.82,-2h8.37c0.41,1.16 1.51,2 2.82,2c1.66,0 3,-1.34 3,-3C23,12.7 22.16,11.6 21,11.18zM18.4,9H16V6.12L18.4,9zM4,5h3v4H3V6C3,5.45 3.45,5 4,5zM6,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S6.55,15 6,15zM9,13v-2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H9V5h4c0.55,0 1,0.45 1,1v7H9zM20,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.55,15 20,15z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M7,20l4,0l0,-2l6,3l-4,0l0,2z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/electric_scooter.xml b/compose/material/material/icons/generator/raw-icons/rounded/electric_scooter.xml
index bb7b2423..c41e8bb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/electric_scooter.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/electric_scooter.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.82,16H15v-1c0,-2.21 1.79,-4 4,-4h0.74l-1.9,-8.44C17.63,1.65 16.82,1 15.89,1H13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2.89l1.4,6.25h-0.01c-2.16,0.65 -3.81,2.48 -4.19,4.75H7.82c-0.48,-1.34 -1.86,-2.24 -3.42,-1.94c-1.18,0.23 -2.13,1.2 -2.35,2.38C1.7,16.34 3.16,18 5,18C6.3,18 7.4,17.16 7.82,16zM5,16c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S5.55,16 5,16z"/>
+ android:pathData="M7.82,16H15v-1c0,-2.21 1.79,-4 4,-4h0.74l-1.9,-8.44C17.63,1.65 16.82,1 15.89,1H13c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h2.89l1.4,6.25c0,0 -0.01,0 -0.01,0c-2.16,0.65 -3.81,2.48 -4.19,4.75H7.82c-0.48,-1.34 -1.86,-2.24 -3.42,-1.94c-1.18,0.23 -2.13,1.2 -2.35,2.38C1.7,16.34 3.16,18 5,18C6.3,18 7.4,17.16 7.82,16zM5,16c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S5.55,16 5,16z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M19,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,12 19,12zM19,16c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S19.55,16 19,16z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/email.xml b/compose/material/material/icons/generator/raw-icons/rounded/email.xml
index 600919e..8bb2388 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/email.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/email.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM19.6,8.25l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25C4.15,8.09 4,7.82 4,7.53c0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19C19.27,6.46 20,6.86 20,7.53C20,7.82 19.85,8.09 19.6,8.25z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19.6,8.25l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25c-0.25,-0.16 -0.4,-0.43 -0.4,-0.72 0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19c0.57,-0.35 1.3,0.05 1.3,0.72 0,0.29 -0.15,0.56 -0.4,0.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emergency.xml b/compose/material/material/icons/generator/raw-icons/rounded/emergency.xml
new file mode 100644
index 0000000..c84089e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emergency.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.29,8.37l-1,-1.73c-0.28,-0.48 -0.89,-0.64 -1.37,-0.37L14,8.54V4c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v4.54L6.07,6.27C5.59,5.99 4.98,6.16 4.71,6.63l-1,1.73C3.43,8.84 3.59,9.46 4.07,9.73L8,12l-3.93,2.27c-0.48,0.28 -0.64,0.89 -0.37,1.37l1,1.73c0.28,0.48 0.89,0.64 1.37,0.37L10,15.46V20c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-4.54l3.93,2.27c0.48,0.28 1.09,0.11 1.37,-0.37l1,-1.73c0.28,-0.48 0.11,-1.09 -0.37,-1.37L16,12l3.93,-2.27C20.41,9.46 20.57,8.84 20.29,8.37z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_emotions.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_emotions.xml
index af9fe28..551db0b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_emotions.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_emotions.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM16.75,14.75C15.8,16.39 14.03,17.5 12,17.5s-3.8,-1.11 -4.75,-2.75C7.06,14.42 7.31,14 7.69,14h8.62C16.7,14 16.94,14.42 16.75,14.75zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12c0,5.52 4.47,10 9.99,10C17.52,22 22,17.52 22,12C22,6.48 17.52,2 11.99,2zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM16.71,14.72C15.8,16.67 14.04,18 12,18s-3.8,-1.33 -4.71,-3.28C7.13,14.39 7.37,14 7.74,14h8.52C16.63,14 16.87,14.39 16.71,14.72zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_events.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_events.xml
index d82695c..ab52436 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_events.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_events.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,5h-2V4c0,-0.55 -0.45,-1 -1,-1H8C7.45,3 7,3.45 7,4v1H5C3.9,5 3,5.9 3,7v1c0,2.55 1.92,4.63 4.39,4.94c0.63,1.5 1.98,2.63 3.61,2.96V19H8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3v-3.1c1.63,-0.33 2.98,-1.46 3.61,-2.96C19.08,12.63 21,10.55 21,8V7C21,5.9 20.1,5 19,5zM7,10.82C5.84,10.4 5,9.3 5,8V7h2V10.82zM19,8c0,1.3 -0.84,2.4 -2,2.82V7h2V8z"/>
+ android:pathData="M19,5h-2V4c0,-0.55 -0.45,-1 -1,-1H8C7.45,3 7,3.45 7,4v1H5C3.9,5 3,5.9 3,7v1c0,2.55 1.92,4.63 4.39,4.94c0.63,1.5 1.98,2.63 3.61,2.96V19H8c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-3v-3.1c1.63,-0.33 2.98,-1.46 3.61,-2.96C19.08,12.63 21,10.55 21,8V7C21,5.9 20.1,5 19,5zM5,8V7h2v3.82C5.84,10.4 5,9.3 5,8zM19,8c0,1.3 -0.84,2.4 -2,2.82V7h2V8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_flags.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_flags.xml
index 0457465..5abe8b9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_flags.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_flags.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,9h-5l-0.72,-1.44C13.11,7.22 12.77,7 12.39,7H7V5.72C7.6,5.38 8,4.74 8,4c0,-1.1 -0.9,-2 -2,-2S4,2.9 4,4c0,0.74 0.4,1.38 1,1.72V20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h5l0.72,1.45c0.17,0.34 0.52,0.55 0.89,0.55H19c0.55,0 1,-0.45 1,-1v-8C20,9.45 19.55,9 19,9z"/>
+ android:pathData="M19,9h-5l-0.72,-1.45C13.11,7.21 12.76,7 12.38,7H7V5.72C7.6,5.38 8,4.74 8,4c0,-1.1 -0.9,-2 -2,-2S4,2.9 4,4c0,0.74 0.4,1.38 1,1.72V20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h5l0.72,1.45c0.17,0.34 0.52,0.55 0.89,0.55H19c0.55,0 1,-0.45 1,-1v-8C20,9.45 19.55,9 19,9zM18,17h-4l-1,-2H7V9h5l1,2h5V17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_food_beverage.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_food_beverage.xml
index 84d23cc6..4acbfb2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_food_beverage.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_food_beverage.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,19H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1S19.55,19 19,19z"/>
+ android:pathData="M19,19H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h16c0.55,0 1,-0.45 1,-1S19.55,19 19,19z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H10v2.4l1.81,1.45C11.93,6.94 12,7.09 12,7.24v4.26c0,0.28 -0.22,0.5 -0.5,0.5h-4C7.22,12 7,11.78 7,11.5V7.24c0,-0.15 0.07,-0.3 0.19,-0.39L9,5.4V3H6C4.9,3 4,3.9 4,5v8c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.1,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3zM20,8h-2V5h2V8z"/>
+ android:pathData="M20,3H9v2.4l1.81,1.45C10.93,6.94 11,7.09 11,7.24v4.26c0,0.28 -0.22,0.5 -0.5,0.5h-4C6.22,12 6,11.78 6,11.5V7.24c0,-0.15 0.07,-0.3 0.19,-0.39L8,5.4V3H6C4.9,3 4,3.9 4,5v8c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.1,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3zM20,8h-2V5h2V8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_nature.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_nature.xml
index cbf6bf0..d238634 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_nature.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_nature.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.94,4.88C21.75,4.33 21.19,3.96 20.58,4H19.6l-0.31,-0.97C19.15,2.43 18.61,2 18,2h0c-0.61,0 -1.15,0.43 -1.29,1.04L16.4,4h-0.98c-0.61,-0.04 -1.16,0.32 -1.35,0.88c-0.19,0.56 0.04,1.17 0.56,1.48l0.87,0.52L15.1,8.12c-0.23,0.58 -0.04,1.25 0.45,1.62c0.5,0.37 1.17,0.35 1.64,-0.06L18,8.98l0.81,0.7c0.47,0.4 1.15,0.43 1.64,0.06c0.5,-0.37 0.68,-1.04 0.45,-1.62l-0.39,-1.24l0.87,-0.52C21.89,6.05 22.12,5.44 21.94,4.88zM18,7c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S18.55,7 18,7z"/>
+ android:pathData="M21.94,4.88C21.76,4.35 21.25,4 20.68,4c-0.03,0 -0.06,0 -0.09,0H19.6l-0.31,-0.97C19.15,2.43 18.61,2 18,2h0c-0.61,0 -1.15,0.43 -1.29,1.04L16.4,4h-0.98c-0.03,0 -0.06,0 -0.09,0c-0.57,0 -1.08,0.35 -1.26,0.88c-0.19,0.56 0.04,1.17 0.56,1.48l0.87,0.52L15.1,8.12c-0.23,0.58 -0.04,1.25 0.45,1.62C15.78,9.91 16.06,10 16.33,10c0.31,0 0.61,-0.11 0.86,-0.32L18,8.98l0.81,0.7C19.06,9.89 19.36,10 19.67,10c0.27,0 0.55,-0.09 0.78,-0.26c0.5,-0.37 0.68,-1.04 0.45,-1.62l-0.39,-1.24l0.87,-0.52C21.89,6.05 22.12,5.44 21.94,4.88zM18,7c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C19,6.55 18.55,7 18,7z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M14.78,11.75c-0.12,-0.38 -0.65,-1.91 -2.53,-2.53V7.75C12.25,7.34 11.91,7 11.5,7h0c-0.41,0 -0.75,0.34 -0.75,0.75v1.27c-0.82,0.05 -2.19,0.4 -3.1,1.79c-0.57,-0.23 -1,-0.4 -1.57,-0.62c-0.79,-0.3 -1.63,-0.23 -2.34,0.11s-1.29,0.98 -1.57,1.81c-0.25,0.73 -0.21,1.49 0.04,2.16s0.72,1.25 1.35,1.62c-0.13,0.83 -0.06,2.26 1.11,3.43c1.25,1.25 2.72,1.22 3.42,1.11c0.11,0.19 0.5,0.71 1.14,1.1c0.64,0.39 1.54,0.65 2.65,0.27c0.82,-0.28 1.46,-0.85 1.81,-1.56c0.35,-0.71 0.42,-1.54 0.11,-2.36c-0.22,-0.56 -0.39,-0.99 -0.62,-1.55c1.38,-0.91 1.74,-2.27 1.79,-3.1h1.27c0.41,0 0.75,-0.34 0.75,-0.75v0c0,-0.41 -0.34,-0.75 -0.75,-0.75H14.78zM6.8,14.26c-0.7,0.19 -1.43,0.24 -2.08,-0.01c-0.51,-0.19 -0.87,-0.82 -0.65,-1.49C4.22,12.28 4.63,12 5.05,12c0.24,0 0.02,-0.06 3.7,1.4C8.18,13.73 7.5,14.07 6.8,14.26zM11.25,19.94c-0.65,0.22 -1.3,-0.12 -1.49,-0.65c-0.23,-0.63 -0.2,-1.34 -0.01,-2.04c0.18,-0.7 0.51,-1.4 0.86,-2c0.48,1.22 0.85,2.15 1.34,3.37C12.07,18.96 12.02,19.67 11.25,19.94zM12.42,14.41c-0.28,-0.7 -0.86,-1.94 -0.86,-1.94s-1.56,-0.72 -1.97,-0.88c0.43,-0.43 1.75,-1.07 2.82,0C12.84,12.01 13.49,13.33 12.42,14.41z"/>
+ android:pathData="M15.5,12h-1.09c-0.19,-0.54 -0.49,-1.05 -0.93,-1.49S12.54,9.78 12,9.59V8.5C12,8.22 11.78,8 11.5,8S11,8.22 11,8.5v0.88c-0.11,-0.01 -0.23,-0.03 -0.34,-0.03c-1.02,0 -2.05,0.39 -2.83,1.17c-0.16,0.16 -0.3,0.34 -0.43,0.53L6,10.52c-1.56,-0.55 -3.28,0.27 -3.83,1.82c0,0 0,0 0,0c-0.27,0.75 -0.23,1.57 0.12,2.29c0.23,0.48 0.58,0.87 1,1.16c-0.38,1.35 -0.06,2.85 1,3.91c1.06,1.06 2.57,1.38 3.91,1c0.29,0.42 0.68,0.77 1.16,1C9.78,21.9 10.21,22 10.65,22c0.34,0 0.68,-0.06 1.01,-0.17c0,0 0,0 0,0c1.56,-0.55 2.38,-2.27 1.82,-3.85l-0.52,-1.37c0.18,-0.13 0.36,-0.27 0.53,-0.43c0.87,-0.87 1.24,-2.04 1.14,-3.17h0.88c0.28,0 0.5,-0.22 0.5,-0.5C16,12.22 15.78,12 15.5,12zM4.67,14.29c-0.25,-0.09 -0.45,-0.27 -0.57,-0.51s-0.13,-0.51 -0.04,-0.76c0.19,-0.52 0.76,-0.79 1.26,-0.61l3.16,1.19C7.33,14.2 5.85,14.71 4.67,14.29zM10.99,19.94c-0.25,0.09 -0.52,0.08 -0.76,-0.04c-0.24,-0.11 -0.42,-0.32 -0.51,-0.57c-0.42,-1.18 0.09,-2.65 0.7,-3.8l1.18,3.13C11.78,19.18 11.51,19.76 10.99,19.94zM12.2,14.6l-0.61,-1.61c0,-0.01 -0.01,-0.02 -0.02,-0.03c-0.02,-0.04 -0.04,-0.08 -0.06,-0.12c-0.02,-0.04 -0.04,-0.07 -0.07,-0.11c-0.03,-0.03 -0.06,-0.06 -0.09,-0.09c-0.03,-0.03 -0.06,-0.06 -0.09,-0.09c-0.03,-0.03 -0.07,-0.05 -0.11,-0.07c-0.04,-0.02 -0.07,-0.05 -0.12,-0.06c-0.01,0 -0.02,-0.01 -0.03,-0.02L9.4,11.8c0.36,-0.29 0.79,-0.46 1.26,-0.46c0.53,0 1.04,0.21 1.41,0.59C12.8,12.66 12.84,13.81 12.2,14.6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_objects.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_objects.xml
index ad664fd..086d3cc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_objects.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_objects.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C8,2 4.75,5.25 4.75,9.25c0,2.52 1.29,4.75 3.25,6.04v3.56c0,1.1 0.9,2 2,2h0.01C10.42,21.54 11.15,22 12,22s1.58,-0.46 1.99,-1.14H14c1.1,0 2,-0.9 2,-2v-3.56c1.96,-1.3 3.25,-3.52 3.25,-6.04C19.25,5.25 16,2 12,2zM13.54,18.86h-3.07c-0.26,0 -0.46,-0.21 -0.46,-0.46l0,0c0,-0.26 0.21,-0.46 0.46,-0.46h3.07c0.26,0 0.46,0.21 0.46,0.46l0,0C14,18.65 13.79,18.86 13.54,18.86zM13.54,16.93h-3.07c-0.26,0 -0.46,-0.21 -0.46,-0.46v0c0,-0.26 0.21,-0.46 0.46,-0.46h3.07c0.26,0 0.46,0.21 0.46,0.46v0C14,16.72 13.79,16.93 13.54,16.93zM12.75,11.31v2.06c0,0.41 -0.34,0.75 -0.75,0.75h0c-0.41,0 -0.75,-0.34 -0.75,-0.75v-2.06L9.58,9.64c-0.29,-0.29 -0.29,-0.77 0,-1.06l0,0c0.29,-0.29 0.77,-0.29 1.06,0L12,9.94l1.36,-1.36c0.29,-0.29 0.77,-0.29 1.06,0l0,0c0.29,0.29 0.29,0.77 0,1.06L12.75,11.31z"/>
+ android:pathData="M12,3c-0.46,0 -0.93,0.04 -1.4,0.14C7.84,3.67 5.64,5.9 5.12,8.66c-0.48,2.61 0.48,5.01 2.22,6.56C7.77,15.6 8,16.13 8,16.69V19c0,1.1 0.9,2 2,2h0.28c0.35,0.6 0.98,1 1.72,1s1.38,-0.4 1.72,-1H14c1.1,0 2,-0.9 2,-2v-2.31c0,-0.55 0.22,-1.09 0.64,-1.46C18.09,13.95 19,12.08 19,10C19,6.13 15.87,3 12,3zM12.5,14h-1v-2.59L9.67,9.59l0.71,-0.71L12,10.5l1.62,-1.62l0.71,0.71l-1.83,1.83V14zM13.5,19c-0.01,0 -0.02,-0.01 -0.03,-0.01V19h-2.94v-0.01c-0.01,0 -0.02,0.01 -0.03,0.01c-0.28,0 -0.5,-0.22 -0.5,-0.5c0,-0.28 0.22,-0.5 0.5,-0.5c0.01,0 0.02,0.01 0.03,0.01V18h2.94v0.01c0.01,0 0.02,-0.01 0.03,-0.01c0.28,0 0.5,0.22 0.5,0.5C14,18.78 13.78,19 13.5,19zM13.5,17h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5c0,-0.28 0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5C14,16.78 13.78,17 13.5,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_people.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_people.xml
index c705f25..d85521f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_people.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_people.xml
@@ -9,5 +9,5 @@
android:pathData="M12,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15.89,8.11C15.5,7.72 14.83,7 13.53,7c-0.21,0 -1.42,0 -2.54,0C8.53,6.99 6.48,5.2 6.07,2.85C5.99,2.36 5.58,2 5.09,2l0,0C4.48,2 4,2.54 4.09,3.14C4.53,5.8 6.47,7.95 9,8.71V21c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-5h2v5c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V10.05l3.24,3.24c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L15.89,8.11z"/>
+ android:pathData="M15.89,8.11C15.5,7.72 14.83,7 13.53,7c-0.21,0 -1.42,0 -2.54,0C8.53,6.99 6.48,5.2 6.07,2.85C5.99,2.36 5.58,2 5.09,2h0c-0.61,0 -1.09,0.54 -1,1.14C4.53,5.8 6.47,7.95 9,8.71V21c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-5h2v5c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V10.05l3.24,3.24c0.39,0.39 1.02,0.39 1.41,0v0c0.39,-0.39 0.39,-1.02 0,-1.41L15.89,8.11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_symbols.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_symbols.xml
index 86aa9a6..4380101 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_symbols.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_symbols.xml
@@ -6,13 +6,13 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,2H4C3.45,2 3,2.45 3,3v0c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v0C11,2.45 10.55,2 10,2z"/>
+ android:pathData="M10,5H4C3.45,5 3,5.45 3,6c0,0.55 0.45,1 1,1h2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7h2c0.55,0 1,-0.45 1,-1C11,5.45 10.55,5 10,5z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M7,11L7,11c0.55,0 1,-0.45 1,-1V7h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6v0c0,0.55 0.45,1 1,1h2v3C6,10.55 6.45,11 7,11z"/>
+ android:pathData="M10,2H4C3.45,2 3,2.45 3,3s0.45,1 1,1h6c0.55,0 1,-0.45 1,-1S10.55,2 10,2z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19.38,13.11l-6.36,6.36c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l6.36,-6.36c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C20.4,12.72 19.77,12.72 19.38,13.11z"/>
+ android:pathData="M20.89,13.11c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.36,6.36c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0l6.36,-6.36C21.28,14.13 21.28,13.5 20.89,13.11z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M14.5,14.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
@@ -21,8 +21,8 @@
android:pathData="M19.5,19.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15.88,10.97C17.12,10.79 18,9.64 18,8.38L18,4h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-2.5c-0.55,0 -1,0.45 -1,1v3.22c-0.4,-0.18 -0.84,-0.27 -1.33,-0.2c-1.08,0.15 -1.99,1.03 -2.14,2.11C12.79,9.8 14.21,11.22 15.88,10.97z"/>
+ android:pathData="M15.5,11c1.38,0 2.5,-1.12 2.5,-2.5V4h2c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v3.51C16.58,6.19 16.07,6 15.5,6C14.12,6 13,7.12 13,8.5C13,9.88 14.12,11 15.5,11z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M10.46,16.68c-0.39,-0.4 -1.03,-0.4 -1.43,-0.01l-0.69,0.69l-0.71,-0.71l0.24,-0.24c0.95,-0.95 1.11,-2.51 0.23,-3.52c-0.5,-0.58 -1.2,-0.86 -1.89,-0.86c-0.69,0 -1.39,0.28 -1.89,0.86c-0.88,1.01 -0.72,2.57 0.23,3.52l0.24,0.24l-0.97,0.97c-0.95,0.95 -1.09,2.52 -0.19,3.52C4.15,21.73 4.83,22 5.52,22c0.64,0 1.28,-0.24 1.77,-0.73l1.06,-1.06l0.71,0.71c0.39,0.39 1.02,0.39 1.41,0h0c0.39,-0.39 0.39,-1.02 0,-1.41l-0.7,-0.7l0.7,-0.71C10.85,17.7 10.85,17.07 10.46,16.68L10.46,16.68zM5.86,14.2c0.12,-0.12 0.26,-0.15 0.35,-0.15c0.09,0 0.23,0.03 0.35,0.15c0.19,0.2 0.19,0.51 0,0.71l-0.35,0.35L5.86,14.9C5.67,14.71 5.67,14.39 5.86,14.2zM5.86,19.85C5.74,19.97 5.6,20 5.52,20c-0.09,0 -0.23,-0.03 -0.35,-0.15c-0.19,-0.19 -0.19,-0.51 0,-0.71l1.06,-1.06l0.71,0.71L5.86,19.85z"/>
+ android:pathData="M10.45,18.09c0.39,-0.39 0.39,-1.02 0,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71l-0.71,-0.71l0.35,-0.35c0.98,-0.98 0.98,-2.56 0,-3.54h0c-0.49,-0.49 -1.13,-0.73 -1.77,-0.73c-0.64,0 -1.28,0.24 -1.77,0.73c-0.98,0.98 -0.98,2.56 0,3.54l0.35,0.35l-1.06,1.06c-0.98,0.98 -0.98,2.56 0,3.54C4.22,21.76 4.86,22 5.5,22c0.64,0 1.28,-0.24 1.77,-0.73l1.06,-1.06l0.71,0.71c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41l-0.71,-0.71v0L10.45,18.09zM5.85,14.2c0.12,-0.12 0.26,-0.15 0.35,-0.15s0.23,0.03 0.35,0.15c0.19,0.2 0.19,0.51 0,0.71l-0.35,0.35L5.85,14.9c-0.12,-0.12 -0.15,-0.26 -0.15,-0.35S5.73,14.32 5.85,14.2zM5.85,19.85C5.73,19.97 5.59,20 5.5,20s-0.23,-0.03 -0.35,-0.15C5.03,19.73 5,19.59 5,19.5s0.03,-0.23 0.15,-0.35l1.06,-1.06l0.71,0.71L5.85,19.85z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/emoji_transportation.xml b/compose/material/material/icons/generator/raw-icons/rounded/emoji_transportation.xml
index 6b6ae5d..25094d9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/emoji_transportation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/emoji_transportation.xml
@@ -6,20 +6,20 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.63,11h-7.26c-0.43,0 -0.8,0.27 -0.94,0.67l-1.37,3.94C10.02,15.72 10,15.83 10,15.94l0.01,5.07c0,0.55 0.45,0.99 1,0.99h0c0.55,0 1,-0.45 1,-1v-0.5h8V21c0,0.55 0.45,1 1,1h0c0.55,0 0.99,-0.44 1,-0.99L22,15.94c0,-0.11 -0.02,-0.22 -0.06,-0.33l-1.37,-3.94C20.43,11.27 20.06,11 19.63,11zM13.5,18.75c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S14.05,18.75 13.5,18.75zM18.5,18.75c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S19.05,18.75 18.5,18.75zM11.86,15l0.87,-2.5h6.55l0.87,2.5H11.86z"/>
+ android:pathData="M21.99,14.77l-1.43,-4.11c-0.14,-0.4 -0.52,-0.66 -0.97,-0.66H12.4c-0.46,0 -0.83,0.26 -0.98,0.66L10,14.77v5.24c0,0.55 0.45,0.99 1,0.99s1,-0.45 1,-1v-1h8v1c0,0.55 0.45,1 1,1s0.99,-0.44 1,-0.99L21.99,14.77zM11.61,13.34l0.69,-2c0.05,-0.2 0.24,-0.34 0.46,-0.34h6.48c0.21,0 0.4,0.14 0.47,0.34l0.69,2c0.11,0.32 -0.13,0.66 -0.47,0.66h-7.85C11.74,14 11.5,13.66 11.61,13.34zM11.99,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.54,17 11.99,17zM19.99,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.54,17 19.99,17z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M6,12h2v2h-2z"/>
+ android:pathData="M14,4.5V9h1V4c0,-0.55 -0.45,-1 -1,-1H8C7.45,3 7,3.45 7,4v4H3C2.45,8 2,8.45 2,9v12h1V9.5C3,9.22 3.22,9 3.5,9h4C7.78,9 8,8.78 8,8.5v-4C8,4.22 8.22,4 8.5,4h5C13.78,4 14,4.22 14,4.5z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,6h2v2h-2z"/>
+ android:pathData="M5,11h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M6,16h2v2h-2z"/>
+ android:pathData="M10,5h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M6,20h2v2h-2z"/>
+ android:pathData="M5,15h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15,9h2V4c0,-1.1 -0.9,-2 -2,-2H9C7.9,2 7,2.9 7,4v4H4c-1.1,0 -2,0.9 -2,2v12h2V10h5V4h6V9z"/>
+ android:pathData="M5,19h2v2h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/engineering.xml b/compose/material/material/icons/generator/raw-icons/rounded/engineering.xml
index bfb6e0e..175a6d0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/engineering.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/engineering.xml
@@ -6,5 +6,17 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.67,9h8.53c0.27,0 0.49,-0.22 0.49,-0.49V8.49C13.69,8.22 13.47,8 13.2,8h-0.27c0,-1.48 -0.81,-2.75 -2,-3.45V5.5c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5V4.14C9.61,4.06 9.28,4 8.93,4s-0.68,0.06 -1,0.14V5.5c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5V4.55c-1.19,0.7 -2,1.97 -2,3.45H4.67C4.4,8 4.18,8.22 4.18,8.49v0.03C4.18,8.78 4.4,9 4.67,9zM8.93,13c1.86,0 3.41,-1.28 3.86,-3H5.07C5.52,11.72 7.07,13 8.93,13zM15.32,16.56C13.64,15.7 11.46,15 8.93,15c-2.53,0 -4.71,0.7 -6.39,1.56c-1,0.51 -1.61,1.54 -1.61,2.66V21h16v-1.78C16.93,18.1 16.32,17.07 15.32,16.56zM22.06,6.5c0,-0.15 -0.02,-0.3 -0.04,-0.44l0.49,-0.43c0.18,-0.16 0.22,-0.42 0.1,-0.63l-0.29,-0.5c-0.12,-0.21 -0.37,-0.3 -0.59,-0.22L21.1,4.49c-0.23,-0.19 -0.48,-0.34 -0.76,-0.44L20.21,3.4C20.16,3.17 19.96,3 19.72,3h-0.58c-0.24,0 -0.44,0.17 -0.49,0.4l-0.13,0.64c-0.28,0.1 -0.53,0.25 -0.76,0.44l-0.63,-0.21c-0.23,-0.08 -0.47,0.02 -0.59,0.22L16.25,5c-0.12,0.21 -0.08,0.47 0.1,0.63l0.49,0.43c-0.02,0.14 -0.04,0.29 -0.04,0.44s0.02,0.3 0.04,0.44l-0.49,0.43c-0.18,0.16 -0.22,0.42 -0.1,0.63l0.29,0.5c0.12,0.21 0.37,0.3 0.59,0.22l0.63,-0.21c0.23,0.19 0.48,0.34 0.76,0.44l0.13,0.64C18.7,9.83 18.9,10 19.14,10h0.58c0.24,0 0.44,-0.17 0.49,-0.4l0.13,-0.64c0.28,-0.1 0.53,-0.25 0.76,-0.44l0.63,0.21c0.23,0.08 0.47,-0.02 0.59,-0.22L22.61,8c0.12,-0.21 0.08,-0.47 -0.1,-0.63l-0.49,-0.43C22.04,6.8 22.06,6.65 22.06,6.5zM19.43,7.75c-0.69,0 -1.25,-0.56 -1.25,-1.25s0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25S20.12,7.75 19.43,7.75zM18.65,10.88l-0.53,0.18c-0.16,-0.13 -0.34,-0.24 -0.54,-0.31l-0.11,-0.55c-0.02,-0.12 -0.13,-0.2 -0.25,-0.2h-0.59c-0.12,0 -0.22,0.08 -0.25,0.2l-0.11,0.55c-0.2,0.07 -0.38,0.18 -0.54,0.31l-0.53,-0.18c-0.11,-0.04 -0.24,0.01 -0.3,0.11l-0.3,0.51c-0.06,0.1 -0.04,0.23 0.05,0.31l0.42,0.37c-0.02,0.1 -0.03,0.21 -0.03,0.31s0.01,0.21 0.03,0.31l-0.42,0.37c-0.09,0.08 -0.11,0.21 -0.05,0.31l0.3,0.51c0.06,0.1 0.18,0.15 0.3,0.11l0.53,-0.18c0.16,0.13 0.34,0.24 0.54,0.31l0.11,0.55c0.02,0.12 0.13,0.2 0.25,0.2h0.59c0.12,0 0.22,-0.08 0.25,-0.2l0.11,-0.55c0.2,-0.07 0.38,-0.18 0.54,-0.31l0.53,0.18c0.11,0.04 0.24,-0.01 0.3,-0.11l0.3,-0.51c0.06,-0.1 0.04,-0.23 -0.05,-0.31l-0.42,-0.37c0.02,-0.1 0.03,-0.21 0.03,-0.31s-0.01,-0.21 -0.03,-0.31l0.42,-0.37c0.09,-0.08 0.11,-0.21 0.05,-0.31l-0.3,-0.51C18.89,10.89 18.76,10.84 18.65,10.88zM16.93,13.25c-0.41,0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75S17.35,13.25 16.93,13.25z"/>
+ android:pathData="M9,15c-2.67,0 -8,1.34 -8,4v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1C17,16.34 11.67,15 9,15z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4.74,9h8.53c0.27,0 0.49,-0.22 0.49,-0.49V8.49c0,-0.27 -0.22,-0.49 -0.49,-0.49H13c0,-1.48 -0.81,-2.75 -2,-3.45V5.5C11,5.78 10.78,6 10.5,6S10,5.78 10,5.5V4.14C9.68,4.06 9.35,4 9,4S8.32,4.06 8,4.14V5.5C8,5.78 7.78,6 7.5,6S7,5.78 7,5.5V4.55C5.81,5.25 5,6.52 5,8H4.74C4.47,8 4.25,8.22 4.25,8.49v0.03C4.25,8.78 4.47,9 4.74,9z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,13c1.86,0 3.41,-1.28 3.86,-3H5.14C5.59,11.72 7.14,13 9,13z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21.98,6.23l0.93,-0.83l-0.75,-1.3l-1.19,0.39c-0.14,-0.11 -0.3,-0.2 -0.47,-0.27L20.25,3h-1.5L18.5,4.22c-0.17,0.07 -0.33,0.16 -0.48,0.27L16.84,4.1l-0.75,1.3l0.93,0.83C17,6.4 17,6.58 17.02,6.75L16.09,7.6l0.75,1.3l1.2,-0.38c0.13,0.1 0.28,0.18 0.43,0.25L18.75,10h1.5l0.27,-1.22c0.16,-0.07 0.3,-0.15 0.44,-0.25l1.19,0.38l0.75,-1.3l-0.93,-0.85C22,6.57 21.99,6.4 21.98,6.23zM19.5,7.75c-0.69,0 -1.25,-0.56 -1.25,-1.25s0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25S20.19,7.75 19.5,7.75z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.4,10.79l-0.85,0.28c-0.1,-0.08 -0.21,-0.14 -0.33,-0.19L18.04,10h-1.07l-0.18,0.87c-0.12,0.05 -0.24,0.12 -0.34,0.19l-0.84,-0.28l-0.54,0.93l0.66,0.59c-0.01,0.13 -0.01,0.25 0,0.37l-0.66,0.61l0.54,0.93l0.86,-0.27c0.1,0.07 0.2,0.13 0.31,0.18L16.96,15h1.07l0.19,-0.87c0.11,-0.05 0.22,-0.11 0.32,-0.18l0.85,0.27l0.54,-0.93l-0.66,-0.61c0.01,-0.13 0.01,-0.25 0,-0.37l0.66,-0.59L19.4,10.79zM17.5,13.39c-0.49,0 -0.89,-0.4 -0.89,-0.89c0,-0.49 0.4,-0.89 0.89,-0.89s0.89,0.4 0.89,0.89C18.39,12.99 17.99,13.39 17.5,13.39z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/enhanced_encryption.xml b/compose/material/material/icons/generator/raw-icons/rounded/enhanced_encryption.xml
index 9cda7e3..799df72 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/enhanced_encryption.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/enhanced_encryption.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10C20,8.9 19.1,8 18,8zM8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2H8.9V6zM15,16h-2v2c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v2h2c0.55,0 1,0.45 1,1l0,0C16,15.55 15.55,16 15,16z"/>
+ android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10c0,-1.1 -0.9,-2 -2,-2zM8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2H8.9V6zM15,16h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/equalizer.xml b/compose/material/material/icons/generator/raw-icons/rounded/equalizer.xml
index 8971152..e219b8c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/equalizer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/equalizer.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,20L12,20c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2l0,0c-1.1,0 -2,0.9 -2,2v12C10,19.1 10.9,20 12,20zM6,20L6,20c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2l0,0c-1.1,0 -2,0.9 -2,2v4C4,19.1 4.9,20 6,20zM16,11v7c0,1.1 0.9,2 2,2l0,0c1.1,0 2,-0.9 2,-2v-7c0,-1.1 -0.9,-2 -2,-2l0,0C16.9,9 16,9.9 16,11z"/>
+ android:pathData="M12,20c1.1,0 2,-0.9 2,-2L14,6c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v12c0,1.1 0.9,2 2,2zM6,20c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v4c0,1.1 0.9,2 2,2zM16,11v7c0,1.1 0.9,2 2,2s2,-0.9 2,-2v-7c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/error.xml b/compose/material/material/icons/generator/raw-icons/rounded/error.xml
index 52c0b58..4d5ca68 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/error.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/error.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,13L12,13c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v4C13,12.55 12.55,13 12,13zM12,17L12,17c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,16.55 12.55,17 12,17z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,13c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1zM13,17h-2v-2h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/error_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/error_outline.xml
index 52c0b58..53237a2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/error_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/error_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,13L12,13c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v4C13,12.55 12.55,13 12,13zM12,17L12,17c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,16.55 12.55,17 12,17z"/>
+ android:pathData="M12,7c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM13,17h-2v-2h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/euro.xml b/compose/material/material/icons/generator/raw-icons/rounded/euro.xml
index a5da757..b3af22e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/euro.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/euro.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,18.5c-2.51,0 -4.68,-1.42 -5.76,-3.5h5.14c0.38,0 0.73,-0.21 0.89,-0.55l0,0C15.6,13.79 15.12,13 14.38,13h-5.8c-0.05,-0.33 -0.08,-0.66 -0.08,-1s0.03,-0.67 0.08,-1h5.8c0.38,0 0.73,-0.21 0.89,-0.55l0,0C15.61,9.78 15.13,9 14.38,9H9.24C10.32,6.92 12.5,5.5 15,5.5c1.25,0 2.42,0.36 3.42,0.97c0.5,0.31 1.15,0.26 1.57,-0.16l0,0c0.58,-0.58 0.45,-1.53 -0.25,-1.96C18.36,3.5 16.73,3 15,3c-3.92,0 -7.24,2.51 -8.48,6h-2.9c-0.38,0 -0.73,0.21 -0.9,0.55l0,0C2.39,10.22 2.87,11 3.62,11h2.44C6.02,11.33 6,11.66 6,12s0.02,0.67 0.06,1H3.62c-0.38,0 -0.73,0.21 -0.89,0.55l0,0C2.39,14.22 2.87,15 3.62,15h2.9c1.24,3.49 4.56,6 8.48,6c1.74,0 3.36,-0.49 4.74,-1.35c0.69,-0.43 0.82,-1.39 0.24,-1.97l0,0c-0.42,-0.42 -1.07,-0.47 -1.57,-0.15C17.42,18.15 16.26,18.5 15,18.5z"/>
+ android:pathData="M15,18.5c-2.51,0 -4.68,-1.42 -5.76,-3.5h5.14c0.38,0 0.73,-0.21 0.89,-0.55l0,0c0.33,-0.66 -0.15,-1.45 -0.89,-1.45h-5.8c-0.05,-0.33 -0.08,-0.66 -0.08,-1s0.03,-0.67 0.08,-1h5.8c0.38,0 0.73,-0.21 0.89,-0.55l0,0C15.61,9.78 15.13,9 14.38,9H9.24C10.32,6.92 12.5,5.5 15,5.5c1.25,0 2.42,0.36 3.42,0.97c0.5,0.31 1.15,0.26 1.57,-0.16l0,0c0.58,-0.58 0.45,-1.53 -0.25,-1.96C18.36,3.5 16.73,3 15,3c-3.92,0 -7.24,2.51 -8.48,6h-2.9C3.24,9 2.89,9.21 2.72,9.55l0,0C2.39,10.22 2.87,11 3.62,11h2.44C6.02,11.33 6,11.66 6,12s0.02,0.67 0.06,1H3.62c-0.38,0 -0.73,0.21 -0.89,0.55l0,0C2.39,14.22 2.87,15 3.62,15h2.9c1.24,3.49 4.56,6 8.48,6c1.74,0 3.36,-0.49 4.74,-1.35c0.69,-0.43 0.82,-1.39 0.24,-1.97l0,0c-0.42,-0.42 -1.07,-0.47 -1.57,-0.15C17.42,18.15 16.26,18.5 15,18.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/euro_symbol.xml b/compose/material/material/icons/generator/raw-icons/rounded/euro_symbol.xml
index c8c8e64..eff1213 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/euro_symbol.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/euro_symbol.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,18.5c-2.51,0 -4.68,-1.42 -5.76,-3.5H14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8.58c-0.05,-0.33 -0.08,-0.66 -0.08,-1s0.03,-0.67 0.08,-1H14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H9.24C10.32,6.92 12.5,5.5 15,5.5c1.25,0 2.42,0.36 3.42,0.97c0.5,0.31 1.15,0.26 1.57,-0.16c0.58,-0.58 0.45,-1.53 -0.25,-1.96C18.36,3.5 16.73,3 15,3c-3.92,0 -7.24,2.51 -8.48,6H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2.06C6.02,11.33 6,11.66 6,12s0.02,0.67 0.06,1H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2.52c1.24,3.49 4.56,6 8.48,6c1.74,0 3.36,-0.49 4.74,-1.35c0.69,-0.43 0.82,-1.39 0.24,-1.97c-0.42,-0.42 -1.07,-0.47 -1.57,-0.15C17.42,18.15 16.26,18.5 15,18.5z"/>
+ android:pathData="M15,18.5c-2.51,0 -4.68,-1.42 -5.76,-3.5H14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8.58c-0.05,-0.33 -0.08,-0.66 -0.08,-1s0.03,-0.67 0.08,-1H14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H9.24C10.32,6.92 12.5,5.5 15,5.5c1.25,0 2.42,0.36 3.42,0.97 0.5,0.31 1.15,0.26 1.57,-0.16 0.58,-0.58 0.45,-1.53 -0.25,-1.96C18.36,3.5 16.73,3 15,3c-3.92,0 -7.24,2.51 -8.48,6H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2.06c-0.04,0.33 -0.06,0.66 -0.06,1s0.02,0.67 0.06,1H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2.52c1.24,3.49 4.56,6 8.48,6 1.74,0 3.36,-0.49 4.74,-1.35 0.69,-0.43 0.82,-1.39 0.24,-1.97 -0.42,-0.42 -1.07,-0.47 -1.57,-0.15 -0.99,0.62 -2.15,0.97 -3.41,0.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/ev_station.xml b/compose/material/material/icons/generator/raw-icons/rounded/ev_station.xml
index 20033fc..850b522 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/ev_station.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/ev_station.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.77,7.23l0.01,-0.01l-3.19,-3.19c-0.29,-0.29 -0.77,-0.29 -1.06,0l0,0c-0.29,0.29 -0.29,0.77 0,1.06l1.58,1.58c-1.05,0.4 -1.76,1.47 -1.58,2.71c0.16,1.1 1.1,1.99 2.2,2.11c0.47,0.05 0.88,-0.03 1.27,-0.2v7.21c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V14c0,-1.1 -0.9,-2 -2,-2h-1V5c0,-1.1 -0.9,-2 -2,-2H6C4.9,3 4,3.9 4,5v15c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-6.5h1.5v4.86c0,1.31 0.94,2.5 2.24,2.63c1.5,0.15 2.76,-1.02 2.76,-2.49V9C20.5,8.31 20.22,7.68 19.77,7.23zM18,10c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S18.55,10 18,10zM8,16.11V13.5H6.83c-0.38,0 -0.62,-0.4 -0.44,-0.74l2.67,-5C9.3,7.3 10,7.48 10,8v3h1.14c0.38,0 0.62,0.41 0.43,0.75l-2.64,4.61C8.68,16.81 8,16.63 8,16.11z"/>
+ android:pathData="M19.77,7.23l0.01,-0.01 -3.19,-3.19c-0.29,-0.29 -0.77,-0.29 -1.06,0 -0.29,0.29 -0.29,0.77 0,1.06l1.58,1.58c-1.05,0.4 -1.76,1.47 -1.58,2.71 0.16,1.1 1.1,1.99 2.2,2.11 0.47,0.05 0.88,-0.03 1.27,-0.2v7.21c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V14c0,-1.1 -0.9,-2 -2,-2h-1V5c0,-1.1 -0.9,-2 -2,-2H6c-1.1,0 -2,0.9 -2,2v15c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-6.5h1.5v4.86c0,1.31 0.94,2.5 2.24,2.63 1.5,0.15 2.76,-1.02 2.76,-2.49V9c0,-0.69 -0.28,-1.32 -0.73,-1.77zM18,10c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM8,16.12V13.5H6.83c-0.38,0 -0.62,-0.4 -0.44,-0.74l2.67,-5c0.24,-0.45 0.94,-0.28 0.94,0.24v3h1.14c0.38,0 0.62,0.41 0.43,0.75l-2.64,4.62c-0.25,0.44 -0.93,0.26 -0.93,-0.25z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/event.xml b/compose/material/material/icons/generator/raw-icons/rounded/event.xml
index 3f46299..9f6db11 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/event.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/event.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,13h-3c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3C17,13.45 16.55,13 16,13zM16,3v1H8V3c0,-0.55 -0.45,-1 -1,-1S6,2.45 6,3v1H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-1V3c0,-0.55 -0.45,-1 -1,-1S16,2.45 16,3zM19,20H5V10h14V20z"/>
+ android:pathData="M16,13h-3c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1zM16,3v1L8,4L8,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,4c-1.11,0 -1.99,0.9 -1.99,2L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2h-1L18,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM18,20L6,20c-0.55,0 -1,-0.45 -1,-1L5,9h14v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/event_available.xml b/compose/material/material/icons/generator/raw-icons/rounded/event_available.xml
index 76ed588..3f5f5fc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/event_available.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/event_available.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4h-1V3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1h0C6.45,2 6,2.45 6,3v1H5C3.89,4 3,4.9 3,6v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V10h14V20zM15.89,11.96L15.89,11.96c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.54,3.54l-1.41,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l2.12,2.12c0.39,0.39 1.02,0.39 1.41,0l4.24,-4.24C16.28,12.98 16.28,12.35 15.89,11.96z"/>
+ android:pathData="M16,10.53c-0.29,-0.29 -0.77,-0.29 -1.06,0l-4.35,4.35L9,13.29c-0.29,-0.29 -0.77,-0.29 -1.06,0 -0.29,0.29 -0.29,0.77 0,1.06l1.94,1.94c0.39,0.39 1.02,0.39 1.41,0l4.7,-4.7c0.3,-0.29 0.3,-0.77 0.01,-1.06zM19,3h-1L18,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L8,3L8,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,3c-1.11,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,8h14v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/event_busy.xml b/compose/material/material/icons/generator/raw-icons/rounded/event_busy.xml
index 83f3e96..b0bda77 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/event_busy.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/event_busy.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4h-1V3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1S6,2.45 6,3v1H5C3.89,4 3,4.9 3,6v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V10h14V20zM9,18L9,18c0.39,0.39 1.02,0.39 1.41,0L12,16.41L13.59,18c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,15L15,13.41c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,13.59L10.41,12c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L10.59,15L9,16.59C8.61,16.98 8.61,17.61 9,18z"/>
+ android:pathData="M9.84,16.47l1.91,-1.91 1.91,1.91c0.29,0.29 0.77,0.29 1.06,0 0.29,-0.29 0.29,-0.77 0,-1.06l-1.91,-1.91 1.91,-1.91c0.29,-0.29 0.29,-0.77 0,-1.06 -0.29,-0.29 -0.77,-0.29 -1.06,0l-1.91,1.91 -1.91,-1.91c-0.29,-0.29 -0.77,-0.29 -1.06,0 -0.29,0.29 -0.29,0.77 0,1.06l1.91,1.91 -1.91,1.91c-0.29,0.29 -0.29,0.77 0,1.06 0.29,0.29 0.77,0.29 1.06,0zM19,3h-1L18,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L8,3L8,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,3c-1.11,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,8h14v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/event_note.xml b/compose/material/material/icons/generator/raw-icons/rounded/event_note.xml
index 31b8126..921aa2a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/event_note.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/event_note.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,11H8c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1l0,0C17,11.45 16.55,11 16,11zM19,4h-1V3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1l0,0C6.45,2 6,2.45 6,3v1H5C3.89,4 3,4.9 3,6v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V9h14V20zM13,15H8c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1l0,0C14,15.45 13.55,15 13,15z"/>
+ android:pathData="M16,10L8,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM19,3h-1L18,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L8,3L8,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,8h14v10c0,0.55 -0.45,1 -1,1zM13,14L8,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/event_seat.xml b/compose/material/material/icons/generator/raw-icons/rounded/event_seat.xml
index 41578f7..0911e97 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/event_seat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/event_seat.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,3H9C7.9,3 7,3.9 7,5v9h10V5C17,3.9 16.1,3 15,3zM18,15H6c-1.1,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-3h12v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-3C20,15.9 19.1,15 18,15zM6,11.5C6,12.33 5.33,13 4.5,13S3,12.33 3,11.5S3.67,10 4.5,10S6,10.67 6,11.5zM21,11.5c0,0.83 -0.67,1.5 -1.5,1.5S18,12.33 18,11.5s0.67,-1.5 1.5,-1.5S21,10.67 21,11.5z"/>
+ android:pathData="M5.5,21c0.83,0 1.5,-0.67 1.5,-1.5L7,18h10v1.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L20,17c0,-1.1 -0.9,-2 -2,-2L6,15c-1.1,0 -2,0.9 -2,2v2.5c0,0.83 0.67,1.5 1.5,1.5zM20,10h1c0.55,0 1,0.45 1,1v1c0,0.55 -0.45,1 -1,1h-1c-0.55,0 -1,-0.45 -1,-1v-1c0,-0.55 0.45,-1 1,-1zM3,10h1c0.55,0 1,0.45 1,1v1c0,0.55 -0.45,1 -1,1L3,13c-0.55,0 -1,-0.45 -1,-1v-1c0,-0.55 0.45,-1 1,-1zM17,13L7,13L7,5c0,-1.1 0.9,-2 2,-2h6c1.1,0 2,0.9 2,2v8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/exit_to_app.xml b/compose/material/material/icons/generator/raw-icons/rounded/exit_to_app.xml
index 65d6be2..2abeff6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/exit_to_app.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/exit_to_app.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.89,3 3,3.9 3,5v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1V5h14v14H5v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM11.85,15.15l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C11.54,8.54 11,8.76 11,9.21V11H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h7v1.79C11,15.24 11.54,15.46 11.85,15.15z"/>
+ android:pathData="M10.79,16.29c0.39,0.39 1.02,0.39 1.41,0l3.59,-3.59c0.39,-0.39 0.39,-1.02 0,-1.41L12.2,7.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L12.67,11H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h8.67l-1.88,1.88c-0.39,0.39 -0.38,1.03 0,1.41zM19,3H5c-1.11,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1H6c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/expand_circle_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/expand_circle_down.xml
new file mode 100644
index 0000000..e085642
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/expand_circle_down.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM15.79,11.71l-3.08,3.08c-0.39,0.39 -1.02,0.39 -1.42,0l-3.08,-3.08c-0.39,-0.39 -0.39,-1.03 0,-1.42c0.39,-0.39 1.02,-0.39 1.41,0L12,12.67l2.38,-2.38c0.39,-0.39 1.02,-0.39 1.41,0C16.18,10.68 16.18,11.32 15.79,11.71z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/expand_less.xml b/compose/material/material/icons/generator/raw-icons/rounded/expand_less.xml
index 2f66467..5e94fae 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/expand_less.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/expand_less.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.71,15.29l3.88,-3.88l3.88,3.88c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-4.59,-4.59c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l0,0C6.68,15.67 7.32,15.68 7.71,15.29z"/>
+ android:pathData="M11.29,8.71L6.7,13.3c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,10.83l3.88,3.88c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L12.7,8.71c-0.38,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/expand_more.xml b/compose/material/material/icons/generator/raw-icons/rounded/expand_more.xml
index 43ad9c4..61e7333 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/expand_more.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/expand_more.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.71,9.29l3.88,3.88l3.88,-3.88c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0L6.29,10.7c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0C6.68,8.91 7.32,8.9 7.71,9.29z"/>
+ android:pathData="M15.88,9.29L12,13.17 8.12,9.29c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.38 -1.03,-0.39 -1.42,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/explicit.xml b/compose/material/material/icons/generator/raw-icons/rounded/explicit.xml
index df571e9..16cf441 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/explicit.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/explicit.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM14,9h-3v2h3c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-3v2h3c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1l0,0C15,8.55 14.55,9 14,9z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM14,9h-3v2h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-3v2h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1L9,8c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/explore.xml b/compose/material/material/icons/generator/raw-icons/rounded/explore.xml
index 9bcfb78..0ac168a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/explore.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/explore.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S12.55,11 12,11zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM13.86,14.34l-6.62,3.08c-0.42,0.2 -0.86,-0.24 -0.66,-0.66l3.08,-6.62c0.1,-0.21 0.27,-0.39 0.48,-0.48l6.62,-3.08c0.42,-0.2 0.86,0.24 0.66,0.66l-3.08,6.62C14.24,14.07 14.07,14.24 13.86,14.34z"/>
+ android:pathData="M12,10.9c-0.61,0 -1.1,0.49 -1.1,1.1s0.49,1.1 1.1,1.1c0.61,0 1.1,-0.49 1.1,-1.1s-0.49,-1.1 -1.1,-1.1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM14.19,14.19L6,18l3.81,-8.19L18,6l-3.81,8.19z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/explore_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/explore_off.xml
index a4ac1f7..81f5d56 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/explore_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/explore_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.74,8.91l5.02,-2.33c0.42,-0.2 0.86,0.24 0.66,0.66l-2.33,5.02l5.25,5.25c1.37,-2.07 2,-4.68 1.48,-7.45c-0.75,-3.95 -3.92,-7.13 -7.88,-7.88c-2.77,-0.52 -5.38,0.1 -7.45,1.48L11.74,8.91z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l1.56,1.56c-1.37,2.07 -2,4.68 -1.48,7.45c0.75,3.95 3.92,7.13 7.88,7.88c2.77,0.52 5.38,-0.1 7.45,-1.48l1.56,1.56c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51zM6.58,16.76l2.33,-5.02l3.35,3.35l-5.02,2.33C6.82,17.62 6.38,17.18 6.58,16.76z"/>
+ android:pathData="M18,6l-2.91,6.26 5.25,5.25C21.39,15.93 22,14.04 22,12c0,-5.52 -4.48,-10 -10,-10 -2.04,0 -3.93,0.61 -5.51,1.66l5.25,5.25L18,6zM2.81,5.64l0.85,0.85c-1.37,2.07 -2,4.68 -1.48,7.45 0.75,3.95 3.92,7.13 7.88,7.88 2.77,0.52 5.38,-0.1 7.45,-1.48l0.85,0.85c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.22,4.22c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.03 0,1.42zM8.91,11.74l3.35,3.35L6,18l2.91,-6.26z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/exposure.xml b/compose/material/material/icons/generator/raw-icons/rounded/exposure.xml
index 5556a0d..558033d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/exposure.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/exposure.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM6.75,7h3.5C10.66,7 11,7.34 11,7.75l0,0c0,0.41 -0.34,0.75 -0.75,0.75h-3.5C6.34,8.5 6,8.16 6,7.75l0,0C6,7.34 6.34,7 6.75,7zM19,19H5L19,5V19zM14.5,16v1.25c0,0.41 0.34,0.75 0.75,0.75l0,0c0.41,0 0.75,-0.34 0.75,-0.75V16h1.25c0.41,0 0.75,-0.34 0.75,-0.75l0,0c0,-0.41 -0.34,-0.75 -0.75,-0.75H16v-1.25c0,-0.41 -0.34,-0.75 -0.75,-0.75l0,0c-0.41,0 -0.75,0.34 -0.75,0.75v1.25h-1.25c-0.41,0 -0.75,0.34 -0.75,0.75l0,0c0,0.41 0.34,0.75 0.75,0.75H14.5z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM6.75,7h3.5c0.41,0 0.75,0.34 0.75,0.75s-0.34,0.75 -0.75,0.75h-3.5c-0.41,0 -0.75,-0.34 -0.75,-0.75S6.34,7 6.75,7zM18,19L5,19L19,5v13c0,0.55 -0.45,1 -1,1zM14.5,16v1.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L16,16h1.25c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75L16,14.5v-1.25c0,-0.41 -0.34,-0.75 -0.75,-0.75s-0.75,0.34 -0.75,0.75v1.25h-1.25c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75h1.25z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_1.xml b/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_1.xml
index d1ef6dc..34bfa2a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_1.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_1.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.81,5c-0.25,0 -0.49,0.08 -0.7,0.23l-2.99,2.16c-0.45,0.33 -0.57,0.95 -0.26,1.42c0.33,0.49 1,0.62 1.48,0.27l1.41,-1.02v9.82c0,0.62 0.5,1.13 1.13,1.13C17.5,19 18,18.5 18,17.87V6.19C18,5.53 17.47,5 16.81,5zM10,12H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c0.55,0 1,-0.45 1,-1S10.55,12 10,12z"/>
+ android:pathData="M4,12c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,11c-0.55,0 -1,0.45 -1,1zM19,18h-2L17,7.38L14,8.4L14,6.7L18.7,5h0.3v13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_2.xml b/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_2.xml
index 582ad6c..95fdd639 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_2.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/exposure_neg_2.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,14h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,13.55 3.45,14 4,14zM15.04,17L15,16.92c1.06,-1.06 3.13,-3.13 3.66,-3.64c1.46,-1.46 2.16,-2.9 2.16,-4.3C20.82,6.85 19.15,5 16.4,5c-1.95,0 -3.18,1 -3.83,2c-0.35,0.53 -0.13,1.23 0.45,1.47l0.16,0.07c0.46,0.19 0.96,0 1.23,-0.42c0.32,-0.5 0.91,-1.04 1.95,-1.04c1.86,0 2.22,1.45 2.22,1.94c0,0.74 -0.04,1.28 -1.46,2.8c-0.45,0.49 -1.4,1.48 -4.59,4.67c-0.28,0.28 -0.43,0.65 -0.43,1.04v0c0,0.81 0.66,1.47 1.47,1.47H20c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H15.04z"/>
+ android:pathData="M15.05,16.29l2.86,-3.07c0.38,-0.39 0.72,-0.79 1.04,-1.18 0.32,-0.39 0.59,-0.78 0.82,-1.17s0.41,-0.78 0.54,-1.17 0.19,-0.79 0.19,-1.18c0,-0.53 -0.09,-1.02 -0.27,-1.46s-0.44,-0.81 -0.78,-1.11c-0.34,-0.31 -0.77,-0.54 -1.26,-0.71 -0.51,-0.16 -1.08,-0.24 -1.72,-0.24 -0.69,0 -1.31,0.11 -1.85,0.32 -0.54,0.21 -1,0.51 -1.36,0.88 -0.37,0.37 -0.65,0.8 -0.84,1.3 -0.18,0.47 -0.27,0.97 -0.28,1.5h2.14c0.01,-0.31 0.05,-0.6 0.13,-0.87 0.09,-0.29 0.23,-0.54 0.4,-0.75 0.18,-0.21 0.41,-0.37 0.68,-0.49s0.6,-0.18 0.96,-0.18c0.31,0 0.58,0.05 0.81,0.15s0.43,0.25 0.59,0.43 0.28,0.4 0.37,0.65c0.08,0.25 0.13,0.52 0.13,0.81 0,0.22 -0.03,0.43 -0.08,0.65 -0.06,0.22 -0.15,0.45 -0.29,0.7 -0.14,0.25 -0.32,0.53 -0.56,0.83 -0.23,0.3 -0.52,0.65 -0.88,1.03l-4.17,4.55V18H21v-1.71h-5.95zM2,12c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_1.xml b/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_1.xml
index ac79cfe..65bd4d0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_1.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_1.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,12H8v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1S10.55,12 10,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.81,5c-0.25,0 -0.49,0.08 -0.7,0.23l-2.99,2.16c-0.45,0.33 -0.57,0.95 -0.26,1.42c0.33,0.49 1,0.62 1.48,0.27l1.41,-1.02v9.82c0,0.62 0.5,1.13 1.13,1.13C17.5,19 18,18.5 18,17.87V6.19C18,5.53 17.47,5 16.81,5z"/>
+ android:pathData="M9,7c-0.55,0 -1,0.45 -1,1v3L5,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L10,8c0,-0.55 -0.45,-1 -1,-1zM20,18h-2L18,7.38L15,8.4L15,6.7L19.7,5h0.3v13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_2.xml b/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_2.xml
index fee65d5..8c82104 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_2.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/exposure_plus_2.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,9L7,9c-0.55,0 -1,0.45 -1,1v2H4c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H8v-2C8,9.45 7.55,9 7,9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.04,17L15,16.92c1.06,-1.06 3.13,-3.13 3.66,-3.64c1.46,-1.46 2.16,-2.9 2.16,-4.3C20.82,6.85 19.15,5 16.4,5c-1.95,0 -3.18,1 -3.83,2c-0.35,0.53 -0.13,1.23 0.45,1.47l0.16,0.07c0.46,0.19 0.96,0 1.23,-0.42c0.32,-0.5 0.91,-1.04 1.95,-1.04c1.86,0 2.22,1.45 2.22,1.94c0,0.74 -0.04,1.28 -1.46,2.8c-0.45,0.49 -1.4,1.48 -4.59,4.67c-0.28,0.28 -0.43,0.65 -0.43,1.04v0c0,0.81 0.66,1.47 1.47,1.47H20c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H15.04z"/>
+ android:pathData="M16.05,16.29l2.86,-3.07c0.38,-0.39 0.72,-0.79 1.04,-1.18 0.32,-0.39 0.59,-0.78 0.82,-1.17s0.41,-0.78 0.54,-1.17c0.13,-0.39 0.19,-0.79 0.19,-1.18 0,-0.53 -0.09,-1.02 -0.27,-1.46s-0.44,-0.81 -0.78,-1.11c-0.34,-0.31 -0.77,-0.54 -1.26,-0.71 -0.51,-0.16 -1.08,-0.24 -1.72,-0.24 -0.69,0 -1.31,0.11 -1.85,0.32 -0.54,0.21 -1,0.51 -1.36,0.88 -0.37,0.37 -0.65,0.8 -0.84,1.3 -0.18,0.47 -0.27,0.97 -0.28,1.5h2.14c0.01,-0.31 0.05,-0.6 0.13,-0.87 0.09,-0.29 0.23,-0.54 0.4,-0.75 0.18,-0.21 0.41,-0.37 0.68,-0.49s0.6,-0.18 0.96,-0.18c0.31,0 0.58,0.05 0.81,0.15s0.43,0.25 0.59,0.43 0.28,0.4 0.37,0.65c0.08,0.25 0.13,0.52 0.13,0.81 0,0.22 -0.03,0.43 -0.08,0.65 -0.06,0.22 -0.15,0.45 -0.29,0.7 -0.14,0.25 -0.32,0.53 -0.56,0.83 -0.23,0.3 -0.52,0.65 -0.88,1.03l-4.17,4.55V18H22v-1.71h-5.95zM7,7c-0.55,0 -1,0.45 -1,1v3H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8V8c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/exposure_zero.xml b/compose/material/material/icons/generator/raw-icons/rounded/exposure_zero.xml
index be8fe22..2df61ed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/exposure_zero.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/exposure_zero.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.52,12c0,-4.03 2.19,-7 5.49,-7c3.32,0 5.47,3.01 5.47,7c0,4.69 -2.76,7 -5.47,7C8.68,19 6.52,15.95 6.52,12zM15.31,12c0,-2.61 -1.12,-4.97 -3.3,-4.97C9.79,7.03 8.7,9.43 8.7,12c0,2.59 1.12,4.97 3.31,4.97C14.19,16.97 15.31,14.59 15.31,12z"/>
+ android:pathData="M16.14,12.5c0,1 -0.1,1.85 -0.3,2.55s-0.48,1.27 -0.83,1.7c-0.36,0.44 -0.79,0.75 -1.3,0.95s-1.07,0.3 -1.7,0.3c-0.62,0 -1.18,-0.1 -1.69,-0.3 -0.51,-0.2 -0.95,-0.51 -1.31,-0.95s-0.65,-1.01 -0.85,-1.7c-0.2,-0.7 -0.3,-1.55 -0.3,-2.55v-2.04c0,-1 0.1,-1.85 0.3,-2.55 0.2,-0.7 0.48,-1.26 0.84,-1.69 0.36,-0.43 0.8,-0.74 1.31,-0.93C10.81,5.1 11.38,5 12,5c0.63,0 1.19,0.1 1.7,0.29 0.51,0.19 0.95,0.5 1.31,0.93 0.36,0.43 0.64,0.99 0.84,1.69 0.2,0.7 0.3,1.54 0.3,2.55v2.04h-0.01zM14.03,10.14c0,-0.64 -0.05,-1.18 -0.13,-1.62 -0.09,-0.44 -0.22,-0.79 -0.4,-1.06 -0.17,-0.27 -0.39,-0.46 -0.64,-0.58 -0.25,-0.13 -0.54,-0.19 -0.86,-0.19s-0.61,0.06 -0.86,0.18 -0.47,0.31 -0.64,0.58 -0.31,0.62 -0.4,1.06 -0.13,0.98 -0.13,1.62v2.67c0,0.64 0.05,1.18 0.14,1.62 0.09,0.45 0.23,0.81 0.4,1.09s0.39,0.48 0.64,0.61 0.54,0.19 0.87,0.19 0.62,-0.06 0.87,-0.19 0.46,-0.33 0.63,-0.61 0.3,-0.64 0.39,-1.09 0.13,-0.99 0.13,-1.62v-2.66h-0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/extension.xml b/compose/material/material/icons/generator/raw-icons/rounded/extension.xml
index c24e5da..91e53c3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/extension.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/extension.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.5,1.5C10.12,1.5 9,2.62 9,4H5.01c-1.1,0 -2,0.9 -2,2v3.8C5.7,9.8 6,11.96 6,12.5c0,0.54 -0.29,2.7 -3,2.7V19c0,1.1 0.9,2 2,2h3.8c0,-2.71 2.16,-3 2.7,-3c0.54,0 2.7,0.29 2.7,3H18c1.1,0 2,-0.9 2,-2v-4c1.38,0 2.5,-1.12 2.5,-2.5S21.38,10 20,10V6c0,-1.1 -0.9,-2 -2,-2h-4C14,2.62 12.88,1.5 11.5,1.5z"/>
+ android:pathData="M20.5,11H19V7c0,-1.1 -0.9,-2 -2,-2h-4V3.5C13,2.12 11.88,1 10.5,1S8,2.12 8,3.5V5H4c-1.1,0 -1.99,0.9 -1.99,2v3.8H3.5c1.49,0 2.7,1.21 2.7,2.7s-1.21,2.7 -2.7,2.7H2V20c0,1.1 0.9,2 2,2h3.8v-1.5c0,-1.49 1.21,-2.7 2.7,-2.7s2.7,1.21 2.7,2.7V22H17c1.1,0 2,-0.9 2,-2v-4h1.5c1.38,0 2.5,-1.12 2.5,-2.5S21.88,11 20.5,11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fast_forward.xml b/compose/material/material/icons/generator/raw-icons/rounded/fast_forward.xml
index d02b639..e59bcda 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fast_forward.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fast_forward.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.55,16.96l6.2,-4.13c0.59,-0.4 0.59,-1.27 0,-1.66l-6.2,-4.13C3.89,6.59 3,7.07 3,7.87v8.26C3,16.93 3.89,17.41 4.55,16.96z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,7.87v8.26c0,0.8 0.89,1.28 1.55,0.83l6.2,-4.13c0.59,-0.4 0.59,-1.27 0,-1.66l-6.2,-4.13C13.89,6.59 13,7.07 13,7.87z"/>
+ android:pathData="M5.58,16.89l5.77,-4.07c0.56,-0.4 0.56,-1.24 0,-1.63L5.58,7.11C4.91,6.65 4,7.12 4,7.93v8.14c0,0.81 0.91,1.28 1.58,0.82zM13,7.93v8.14c0,0.81 0.91,1.28 1.58,0.82l5.77,-4.07c0.56,-0.4 0.56,-1.24 0,-1.63l-5.77,-4.07c-0.67,-0.47 -1.58,0 -1.58,0.81z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fast_rewind.xml b/compose/material/material/icons/generator/raw-icons/rounded/fast_rewind.xml
index 1dc2b7a..e9a799a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fast_rewind.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fast_rewind.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.45,7.04l-6.2,4.13c-0.59,0.4 -0.59,1.27 0,1.66l6.2,4.13c0.66,0.44 1.55,-0.03 1.55,-0.83V7.87C21,7.07 20.11,6.59 19.45,7.04z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,16.13V7.87c0,-0.8 -0.89,-1.28 -1.55,-0.83l-6.2,4.13c-0.59,0.4 -0.59,1.27 0,1.66l6.2,4.13C10.11,17.41 11,16.93 11,16.13z"/>
+ android:pathData="M11,16.07L11,7.93c0,-0.81 -0.91,-1.28 -1.58,-0.82l-5.77,4.07c-0.56,0.4 -0.56,1.24 0,1.63l5.77,4.07c0.67,0.47 1.58,0 1.58,-0.81zM12.66,12.82l5.77,4.07c0.66,0.47 1.58,-0.01 1.58,-0.82L20.01,7.93c0,-0.81 -0.91,-1.28 -1.58,-0.82l-5.77,4.07c-0.57,0.4 -0.57,1.24 0,1.64z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fastfood.xml b/compose/material/material/icons/generator/raw-icons/rounded/fastfood.xml
index b899913..9d42276 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fastfood.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fastfood.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.9,5H18V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-3.9c-0.59,0 -1.05,0.51 -1,1.1l0.12,1.21C14.9,8.16 18,10.77 18,15l0.02,8h1.7c0.84,0 1.53,-0.65 1.63,-1.47L22.89,6.1C22.95,5.51 22.49,5 21.9,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,21H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h13c0.55,0 1,-0.45 1,-1S15.55,21 15,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,15h12.8c0.62,0 1.11,-0.56 0.99,-1.16c-0.65,-3.23 -4.02,-4.85 -7.39,-4.85s-6.73,1.62 -7.39,4.85C0.99,14.44 1.49,15 2.1,15z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,17H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h13c0.55,0 1,-0.45 1,-1S15.55,17 15,17z"/>
+ android:pathData="M21.9,5H18V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-3.9c-0.59,0 -1.05,0.51 -1,1.1l0.12,1.21C14.9,8.16 18,10.77 18,15l0.02,8h1.7c0.84,0 1.53,-0.65 1.63,-1.47L22.89,6.1c0.06,-0.59 -0.4,-1.1 -0.99,-1.1zM15,21H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM2.1,15h12.8c0.62,0 1.11,-0.56 0.99,-1.16 -0.65,-3.23 -4.02,-4.85 -7.39,-4.85s-6.73,1.62 -7.39,4.85c-0.12,0.6 0.38,1.16 0.99,1.16zM15,17H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/favorite.xml b/compose/material/material/icons/generator/raw-icons/rounded/favorite.xml
index 4103842..1a4c5b7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/favorite.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/favorite.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.67,19.8C5.15,14.85 1.95,12.16 2,8.41c0.04,-2.97 2.3,-4.39 2.35,-4.43C7.96,1.52 11.24,4.2 12,5.09c0.75,-0.88 3.99,-3.51 7.56,-1.16c0.52,0.34 2.23,1.65 2.42,4.12c0.32,4.28 -4.14,7.76 -8.65,11.76c-0.38,0.34 -0.86,0.5 -1.34,0.5C11.52,20.31 11.05,20.14 10.67,19.8z"/>
+ android:pathData="M13.35,20.13c-0.76,0.69 -1.93,0.69 -2.69,-0.01l-0.11,-0.1C5.3,15.27 1.87,12.16 2,8.28c0.06,-1.7 0.93,-3.33 2.34,-4.29 2.64,-1.8 5.9,-0.96 7.66,1.1 1.76,-2.06 5.02,-2.91 7.66,-1.1 1.41,0.96 2.28,2.59 2.34,4.29 0.14,3.88 -3.3,6.99 -8.55,11.76l-0.1,0.09z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/featured_play_list.xml b/compose/material/material/icons/generator/raw-icons/rounded/featured_play_list.xml
index 5074299..e1550f4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/featured_play_list.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/featured_play_list.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM14,13H7c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,0.45 1,1v0C15,12.55 14.55,13 14,13zM14,10H7c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,0.45 1,1v0C15,9.55 14.55,10 14,10z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM11,11L4,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h7c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM11,7L4,7c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h7c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/featured_video.xml b/compose/material/material/icons/generator/raw-icons/rounded/featured_video.xml
index 361fd79..fa3d633 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/featured_video.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/featured_video.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM13,14H6c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,0.45 1,1v5C14,13.55 13.55,14 13,14z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM11,12L4,12c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,0.45 1,1v5c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/feedback.xml b/compose/material/material/icons/generator/raw-icons/rounded/feedback.xml
index ac286e6..64592f7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/feedback.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/feedback.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v15.59c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM12,11c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4C13,10.55 12.55,11 12,11zM12,15L12,15c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,14.55 12.55,15 12,15z"/>
+ android:pathData="M20,2L4.01,2c-1.1,0 -2,0.9 -2,2v18L6,18h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM13,14h-2v-2h2v2zM13,9c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,7c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fiber_dvr.xml b/compose/material/material/icons/generator/raw-icons/rounded/fiber_dvr.xml
index 47c25c1..0b2e29a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fiber_dvr.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fiber_dvr.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,4H3C1.89,4 1,4.89 1,6v12c0,1.1 0.89,2 2,2h18c1.11,0 2,-0.9 2,-2V6C23,4.89 22.11,4 21,4zM9,13.5C9,14.33 8.33,15 7.5,15h-3C4.22,15 4,14.78 4,14.5v-5C4,9.22 4.22,9 4.5,9h3C8.33,9 9,9.67 9,10.5V13.5zM14.1,9.92l-1.27,4.36C12.71,14.71 12.31,15 11.87,15s-0.84,-0.29 -0.96,-0.72L9.64,9.92C9.5,9.46 9.85,9 10.33,9c0.32,0 0.6,0.21 0.69,0.52l0.85,2.91l0.85,-2.91C12.81,9.21 13.09,9 13.41,9C13.89,9 14.24,9.46 14.1,9.92zM20,11.5c0,0.6 -0.4,1.15 -0.9,1.4l0.48,1.14c0.19,0.45 -0.14,0.96 -0.63,0.96c-0.28,0 -0.53,-0.16 -0.63,-0.42L17.65,13H16.5v1.31c0,0.38 -0.31,0.69 -0.69,0.69h-0.12C15.31,15 15,14.69 15,14.31V9.64C15,9.29 15.29,9 15.64,9h2.86c0.83,0 1.5,0.67 1.5,1.5V11.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.5,10.5h2v1h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5.5,10.5h2v3h-2z"/>
+ android:pathData="M4.5,10.5h2v3h-2zM17.5,10.5h2v1h-2zM21,3L3,3c-1.11,0 -2,0.89 -2,2v14c0,1.1 0.89,2 2,2h18c1.11,0 2,-0.9 2,-2L23,5c0,-1.11 -0.89,-2 -2,-2zM8,13.5c0,0.83 -0.67,1.5 -1.5,1.5h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5v-5c0,-0.28 0.22,-0.5 0.5,-0.5h3c0.83,0 1.5,0.67 1.5,1.5v3zM14.1,9.92l-1.27,4.36c-0.12,0.43 -0.52,0.72 -0.96,0.72s-0.84,-0.29 -0.96,-0.72L9.64,9.92c-0.14,-0.46 0.21,-0.92 0.69,-0.92 0.32,0 0.6,0.21 0.69,0.52l0.85,2.91 0.85,-2.91c0.09,-0.31 0.37,-0.52 0.69,-0.52 0.48,0 0.83,0.46 0.69,0.92zM21,11.5c0,0.6 -0.4,1.15 -0.9,1.4l0.63,1.48c0.19,0.45 -0.14,0.96 -0.63,0.96 -0.28,0 -0.53,-0.16 -0.63,-0.42L18.65,13L17.5,13v1.31c0,0.38 -0.31,0.69 -0.69,0.69h-0.12c-0.38,0 -0.69,-0.31 -0.69,-0.69L16,9.64c0,-0.35 0.29,-0.64 0.64,-0.64h2.86c0.83,0 1.5,0.67 1.5,1.5v1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fiber_manual_record.xml b/compose/material/material/icons/generator/raw-icons/rounded/fiber_manual_record.xml
index ea07644..d191830 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fiber_manual_record.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fiber_manual_record.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,12m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0"/>
+ android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fiber_new.xml b/compose/material/material/icons/generator/raw-icons/rounded/fiber_new.xml
index bf5edba..6af4156 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fiber_new.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fiber_new.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2.01,4.89 2.01,6L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6C22,4.89 21.11,4 20,4zM8.5,14.21C8.5,14.64 8.14,15 7.71,15l0,0c-0.25,0 -0.49,-0.12 -0.64,-0.33L4.75,11.5v2.88c0,0.35 -0.28,0.62 -0.62,0.62S3.5,14.72 3.5,14.38V9.79C3.5,9.36 3.86,9 4.29,9h0.05c0.26,0 0.5,0.12 0.65,0.33l2.26,3.17V9.62C7.25,9.28 7.53,9 7.88,9C8.23,9 8.5,9.28 8.5,9.62V14.21zM13.5,9.64c0,0.35 -0.28,0.62 -0.62,0.62H11v1.12h1.88c0.35,0 0.62,0.28 0.62,0.62v0.01c0,0.35 -0.28,0.62 -0.62,0.62H11v1.11h1.88c0.35,0 0.62,0.28 0.62,0.62c0,0.35 -0.28,0.62 -0.62,0.62h-2.53c-0.47,0 -0.85,-0.38 -0.85,-0.85v-4.3C9.5,9.38 9.88,9 10.35,9h2.53c0.35,0 0.62,0.28 0.62,0.62V9.64zM20.5,14c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1V9.62C14.5,9.28 14.78,9 15.12,9s0.62,0.28 0.62,0.62v3.89h1.13v-2.9c0,-0.35 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v2.89h1.12V9.62c0,-0.35 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62V14H20.5z"/>
+ android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM8.5,14.21c0,0.43 -0.36,0.79 -0.79,0.79 -0.25,0 -0.49,-0.12 -0.64,-0.33L4.75,11.5v2.88c0,0.35 -0.28,0.62 -0.62,0.62s-0.63,-0.28 -0.63,-0.62L3.5,9.79c0,-0.43 0.36,-0.79 0.79,-0.79h0.05c0.26,0 0.5,0.12 0.65,0.33l2.26,3.17L7.25,9.62c0,-0.34 0.28,-0.62 0.63,-0.62s0.62,0.28 0.62,0.62v4.59zM13.5,9.64c0,0.35 -0.28,0.62 -0.62,0.62L11,10.26v1.12h1.88c0.35,0 0.62,0.28 0.62,0.62v0.01c0,0.35 -0.28,0.62 -0.62,0.62L11,12.63v1.11h1.88c0.35,0 0.62,0.28 0.62,0.62 0,0.35 -0.28,0.62 -0.62,0.62h-2.53c-0.47,0 -0.85,-0.38 -0.85,-0.85v-4.3c0,-0.45 0.38,-0.83 0.85,-0.83h2.53c0.35,0 0.62,0.28 0.62,0.62v0.02zM20.5,14c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1L14.5,9.62c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v3.89h1.13v-2.9c0,-0.35 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v2.89h1.12L19.23,9.62c0,-0.35 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62L20.47,14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fiber_pin.xml b/compose/material/material/icons/generator/raw-icons/rounded/fiber_pin.xml
index bb0bb22..edb90cb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fiber_pin.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fiber_pin.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2.01,4.89 2.01,6L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6C22,4.89 21.11,4 20,4zM10,11.5c0,0.83 -0.67,1.5 -1.5,1.5h-2v1.25C6.5,14.66 6.16,15 5.75,15S5,14.66 5,14.25V10c0,-0.55 0.45,-1 1,-1h2.5C9.33,9 10,9.67 10,10.5V11.5zM12.75,14.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75v-4.5C11.25,9.34 11.59,9 12,9s0.75,0.34 0.75,0.75V14.25zM19,14.21c0,0.44 -0.35,0.79 -0.79,0.79l0,0c-0.25,0 -0.49,-0.12 -0.64,-0.33l-2.31,-3.17v2.88c0,0.34 -0.28,0.62 -0.62,0.62h-0.01C14.28,15 14,14.72 14,14.38V9.83C14,9.37 14.37,9 14.83,9c0.27,0 0.52,0.13 0.67,0.35l2.25,3.15V9.62c0,-0.34 0.28,-0.62 0.62,-0.62h0.01C18.72,9 19,9.28 19,9.62V14.21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.5,10.5h2v1h-2z"/>
+ android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM9,11.5c0,0.83 -0.67,1.5 -1.5,1.5h-2v1.25c0,0.41 -0.34,0.75 -0.75,0.75S4,14.66 4,14.25L4,10c0,-0.55 0.45,-1 1,-1h2.5c0.83,0 1.5,0.67 1.5,1.5v1zM12.5,14.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75v-4.5c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75v4.5zM20,14.21c0,0.44 -0.35,0.79 -0.79,0.79 -0.25,0 -0.49,-0.12 -0.64,-0.33l-2.31,-3.17v2.88c0,0.34 -0.28,0.62 -0.62,0.62h-0.01c-0.35,0 -0.63,-0.28 -0.63,-0.62L15,9.83c0,-0.46 0.37,-0.83 0.83,-0.83 0.27,0 0.52,0.13 0.67,0.35l2.25,3.15L18.75,9.62c0,-0.34 0.28,-0.62 0.62,-0.62h0.01c0.34,0 0.62,0.28 0.62,0.62v4.59zM5.5,10.5h2v1h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fiber_smart_record.xml b/compose/material/material/icons/generator/raw-icons/rounded/fiber_smart_record.xml
index ce9d3dc..87d63a7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fiber_smart_record.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fiber_smart_record.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,12m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0"/>
+ android:pathData="M9,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M16,6.35L16,6.35c0,0.42 0.26,0.79 0.66,0.93C18.6,7.97 20,9.82 20,12s-1.4,4.03 -3.34,4.72c-0.4,0.14 -0.66,0.51 -0.66,0.93v0c0,0.7 0.7,1.17 1.36,0.93C20.06,17.62 22,15.04 22,12s-1.94,-5.62 -4.64,-6.58C16.7,5.18 16,5.65 16,6.35z"/>
+ android:pathData="M17,5.55v0.18c0,0.37 0.23,0.69 0.57,0.85C19.6,7.54 21,9.61 21,12s-1.4,4.46 -3.43,5.42c-0.34,0.16 -0.57,0.47 -0.57,0.84v0.18c0,0.68 0.71,1.11 1.32,0.82C21.08,18.01 23,15.23 23,12s-1.92,-6.01 -4.68,-7.27c-0.61,-0.28 -1.32,0.14 -1.32,0.82z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/file_copy.xml b/compose/material/material/icons/generator/raw-icons/rounded/file_copy.xml
index a048a96..204ccd5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/file_copy.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/file_copy.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,7L3,7C2.45,7 2,7.45 2,8v13c0,1.1 0.9,2 2,2h11c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V8C4,7.45 3.55,7 3,7zM15.59,1.59C15.21,1.21 14.7,1 14.17,1H8C6.9,1 6.01,1.9 6.01,3L6,17c0,1.1 0.89,2 1.99,2H19c1.1,0 2,-0.9 2,-2V7.83c0,-0.53 -0.21,-1.04 -0.59,-1.41L15.59,1.59zM14,7V2.5L19.5,8H15C14.45,8 14,7.55 14,7z"/>
+ android:pathData="M15,1L4,1c-1.1,0 -2,0.9 -2,2v13c0,0.55 0.45,1 1,1s1,-0.45 1,-1L4,4c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM15.59,5.59l4.83,4.83c0.37,0.37 0.58,0.88 0.58,1.41L21,21c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h6.17c0.53,0 1.04,0.21 1.42,0.59zM15,12h4.5L14,6.5L14,11c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter.xml
index f9ae294..538db3d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM9.6,13.2l1.38,-1.83c0.2,-0.27 0.6,-0.27 0.8,0L13,13l2.23,-2.97c0.2,-0.27 0.6,-0.27 0.8,0l2.38,3.17c0.25,0.33 0.01,0.8 -0.4,0.8h-8C9.59,14 9.35,13.53 9.6,13.2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M15.56,10.81l-2.35,3.02 -1.56,-1.88c-0.2,-0.25 -0.58,-0.24 -0.78,0.01l-1.74,2.23c-0.26,0.33 -0.02,0.81 0.39,0.81h8.98c0.41,0 0.65,-0.47 0.4,-0.8l-2.55,-3.39c-0.19,-0.26 -0.59,-0.26 -0.79,0zM2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_1.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_1.xml
index 5e51444..90495d7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_1.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_1.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM16,14c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V7h-1c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1V14z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM15,15c0.55,0 1,-0.45 1,-1L16,6c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v7c0,0.55 0.45,1 1,1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_2.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_2.xml
index b3587cd9..57c4261 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_2.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_2.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,9c0,1.1 -0.9,2 -2,2h-2v2h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1v-3c0,-1.1 0.9,-2 2,-2h2V7h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3c1.1,0 2,0.9 2,2V9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM16,13h-3v-2h2c1.1,0 2,-0.9 2,-2L17,7c0,-1.1 -0.9,-2 -2,-2h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v2h-2c-1.1,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_3.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_3.xml
index f837b8f..a2f1021 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_3.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_3.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,8.5c0,0.83 -0.67,1.5 -1.5,1.5c0.83,0 1.5,0.67 1.5,1.5V13c0,1.1 -0.9,2 -2,2h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3v-2h-1c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h1V7h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3c1.1,0 2,0.9 2,2V8.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM17,13v-1.5c0,-0.83 -0.67,-1.5 -1.5,-1.5 0.83,0 1.5,-0.67 1.5,-1.5L17,7c0,-1.1 -0.9,-2 -2,-2h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v2h-1c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v2h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_4.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_4.xml
index 1e0ff92a..139ebf6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_4.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_4.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,14c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3h-3c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h2V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V14z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM16,15c0.55,0 1,-0.45 1,-1L17,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-2L13,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_5.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_5.xml
index 921317e..ad6b9e1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_5.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_5.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM15,9c1.1,0 2,0.9 2,2v2c0,1.1 -0.9,2 -2,2h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3v-2h-3c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-3v2H15z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM17,13v-2c0,-1.1 -0.9,-2 -2,-2h-2L13,7h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3v2h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_6.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_6.xml
index 7864ae1..b9bb645 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_6.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_6.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,13c0,1.1 -0.9,2 -2,2h-2c-1.1,0 -2,-0.9 -2,-2V7c0,-1.1 0.9,-2 2,-2h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-2v2h2c1.1,0 2,0.9 2,2V13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,11h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM13,15h2c1.1,0 2,-0.9 2,-2v-2c0,-1.1 -0.9,-2 -2,-2h-2L13,7h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-1.1,0 -2,0.9 -2,2v6c0,1.1 0.9,2 2,2zM13,11h2v2h-2v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_7.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_7.xml
index cb88b33..8845479 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_7.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_7.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM16.83,7.34l-3.58,7.16c-0.15,0.3 -0.46,0.49 -0.8,0.49c-0.66,0 -1.1,-0.7 -0.8,-1.29L15,7h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3.38C16.28,5 17,5.72 17,6.62C17,6.87 16.94,7.12 16.83,7.34z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM13.25,14.51l3.58,-7.17c0.11,-0.22 0.17,-0.47 0.17,-0.72 0,-0.9 -0.72,-1.62 -1.62,-1.62L12,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3l-3.36,6.71c-0.3,0.59 0.13,1.29 0.8,1.29h0.01c0.34,0 0.65,-0.19 0.8,-0.49z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_8.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_8.xml
index 2ca4c3f..4756a0b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_8.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_8.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,8.5c0,0.83 -0.67,1.5 -1.5,1.5c0.83,0 1.5,0.67 1.5,1.5V13c0,1.1 -0.9,2 -2,2h-2c-1.1,0 -2,-0.9 -2,-2v-1.5c0,-0.83 0.67,-1.5 1.5,-1.5C11.67,10 11,9.33 11,8.5V7c0,-1.1 0.9,-2 2,-2h2c1.1,0 2,0.9 2,2V8.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,7h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,11h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM13,15h2c1.1,0 2,-0.89 2,-2v-1.5c0,-0.83 -0.67,-1.5 -1.5,-1.5 0.83,0 1.5,-0.67 1.5,-1.5L17,7c0,-1.11 -0.9,-2 -2,-2h-2c-1.1,0 -2,0.89 -2,2v1.5c0,0.83 0.67,1.5 1.5,1.5 -0.83,0 -1.5,0.67 -1.5,1.5L11,13c0,1.11 0.9,2 2,2zM13,7h2v2h-2L13,7zM13,11h2v2h-2v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_9.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_9.xml
index 73f7c0d..f96adbcd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_9.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_9.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,13c0,1.1 -0.9,2 -2,2h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2h-2c-1.1,0 -2,-0.9 -2,-2V7c0,-1.1 0.9,-2 2,-2h2c1.1,0 2,0.9 2,2V13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,7h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM15,5h-2c-1.1,0 -2,0.9 -2,2v2c0,1.1 0.9,2 2,2h2v2h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2L17,7c0,-1.1 -0.9,-2 -2,-2zM15,9h-2L13,7h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_9_plus.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_9_plus.xml
index e628f38..836f9f6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_9_plus.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_9_plus.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,8h1v1h-1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM14,12c0,1.11 -0.9,2 -2,2h-1c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h1v-1h-1c-1.1,0 -2,-0.89 -2,-2V8c0,-1.11 0.9,-2 2,-2h1c1.1,0 2,0.89 2,2V12zM19.5,11h-1v1c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-1h-1c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v1h1c0.55,0 1,0.45 1,1v0C20.5,10.55 20.05,11 19.5,11z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM14,12L14,8c0,-1.1 -0.9,-2 -2,-2h-1c-1.1,0 -2,0.9 -2,2v1c0,1.1 0.9,2 2,2h1v1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2c1.1,0 2,-0.9 2,-2zM11,9L11,8h1v1h-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM21,10c0,-0.55 -0.45,-1 -1,-1h-1L19,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1h-1c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h1c0.55,0 1,-0.45 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_alt.xml
index aba84a7..987fa31 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_alt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.21,5.61C6.23,8.2 10,13 10,13v5c0,1.1 0.9,2 2,2h0c1.1,0 2,-0.9 2,-2v-5c0,0 3.77,-4.8 5.79,-7.39C20.3,4.95 19.83,4 19,4H5C4.17,4 3.7,4.95 4.21,5.61z"/>
+ android:pathData="M4.25,5.61C6.57,8.59 10,13 10,13v5c0,1.1 0.9,2 2,2h0c1.1,0 2,-0.9 2,-2v-5c0,0 3.43,-4.41 5.75,-7.39C20.26,4.95 19.79,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_b_and_w.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_b_and_w.xml
index b0861eb..470a419 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_b_and_w.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_b_and_w.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19l-7,-8v8H5l7,-8V5h7V19z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19l-7,-8v8L5,19l7,-8L12,5h6c0.55,0 1,0.45 1,1v13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_center_focus.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_center_focus.xml
index 9fcb7a2..a6cc2b23 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_center_focus.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_center_focus.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,15L4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5v-3C5,15.45 4.55,15 4,15zM5,5h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5zM19,3h-3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V5C21,3.9 20.1,3 19,3zM19,19h-3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1V19zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S13.66,9 12,9z"/>
+ android:pathData="M4,15c-0.55,0 -1,0.45 -1,1v3c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,19c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 -0.45,-1 -1,-1zM5,6c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,3c-1.1,0 -2,0.9 -2,2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L5,6zM19,3h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2c0.55,0 1,0.45 1,1v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L21,5c0,-1.1 -0.9,-2 -2,-2zM19,18c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_drama.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_drama.xml
index f994e74..a1be208 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_drama.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_drama.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7C8.78,4 6.07,6.18 5.26,9.15C2.82,9.71 1,11.89 1,14.5C1,17.54 3.46,20 6.5,20h12l0,0c2.49,-0.01 4.5,-2.03 4.5,-4.52C23,13.15 21.25,11.26 19,11zM18.5,18h-12C4.57,18 3,16.43 3,14.5S4.57,11 6.5,11c1.65,0 3.04,1.15 3.41,2.7c0.11,0.46 0.5,0.8 0.98,0.8c0.66,0 1.12,-0.62 0.97,-1.26c-0.5,-2.15 -2.27,-3.81 -4.47,-4.16C8.14,7.27 9.92,6 12,6c2.76,0 5,2.24 5,5v2c0,0 1.33,0 1.5,0c1.38,0 2.5,1.12 2.5,2.5C21,16.88 19.88,18 18.5,18z"/>
+ android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.61,5.64 5.36,8.04 2.35,8.36 0,10.9 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM19,18H6.17c-2.09,0 -3.95,-1.53 -4.15,-3.61C1.79,12.01 3.66,10 6,10c1.92,0 3.53,1.36 3.91,3.17 0.1,0.48 0.5,0.83 0.98,0.83 0.61,0 1.11,-0.55 0.99,-1.15 -0.43,-2.24 -2.11,-4.03 -4.29,-4.63 1.1,-1.46 2.89,-2.37 4.89,-2.2 2.88,0.25 5.01,2.82 5.01,5.71V12h1.37c1.45,0 2.79,0.97 3.07,2.4 0.39,1.91 -1.08,3.6 -2.93,3.6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_frames.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_frames.xml
index 9193473..2438375 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_frames.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_frames.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,9v8c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1H7C6.45,8 6,8.45 6,9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,4h-4l-3.29,-3.29c-0.39,-0.39 -1.02,-0.39 -1.41,0L8,4H4C2.9,4 2,4.9 2,6v14c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,20H4V6h4.52l3.52,-3.5L15.52,6H20V20z"/>
+ android:pathData="M20,4h-4L12.71,0.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L8,4L4,4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19,20L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 0.45,-1 1,-1h3.52l3.52,-3.5L15.52,6L19,6c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM17,8L7,8c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1L18,9c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_hdr.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_hdr.xml
index 0b804bb..515fe49 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_hdr.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_hdr.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.2,7.07L10.25,11l2.25,3c0.33,0.44 0.24,1.07 -0.2,1.4l0,0c-0.44,0.33 -1.07,0.25 -1.4,-0.2c-1.05,-1.4 -2.31,-3.07 -3.1,-4.14c-0.4,-0.53 -1.2,-0.53 -1.6,0l-4,5.33C1.71,17.06 2.18,18 3,18h18c0.82,0 1.29,-0.94 0.8,-1.6l-7,-9.33C14.4,6.53 13.6,6.53 13.2,7.07z"/>
+ android:pathData="M13.2,7.07L10.25,11l2.25,3c0.33,0.44 0.24,1.07 -0.2,1.4 -0.44,0.33 -1.07,0.25 -1.4,-0.2 -1.05,-1.4 -2.31,-3.07 -3.1,-4.14 -0.4,-0.53 -1.2,-0.53 -1.6,0l-4,5.33c-0.49,0.67 -0.02,1.61 0.8,1.61h18c0.82,0 1.29,-0.94 0.8,-1.6l-7,-9.33c-0.4,-0.54 -1.2,-0.54 -1.6,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_list.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_list.xml
index dc2a644..32f752b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_list.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_list.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,18h2c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1l0,0C10,17.55 10.45,18 11,18zM3,7L3,7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,6 3,6.45 3,7zM7,13h10c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H7c-0.55,0 -1,0.45 -1,1l0,0C6,12.55 6.45,13 7,13z"/>
+ android:pathData="M11,18h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,6c-0.55,0 -1,0.45 -1,1zM7,13h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L7,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_none.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_none.xml
index 1705af9..9155d39 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_none.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_none.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM20,16H8V4h12V16z"/>
+ android:pathData="M2,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.9,2 2,2h15c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,21c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 -0.45,-1 -1,-1zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM20,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,4c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_tilt_shift.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_tilt_shift.xml
index f39d76b..443a5a0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_tilt_shift.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_tilt_shift.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,3.23L11,3.23c0,-0.64 -0.59,-1.13 -1.21,-0.99c-1.12,0.26 -2.18,0.7 -3.12,1.3c-0.53,0.34 -0.61,1.1 -0.16,1.55l0,0c0.32,0.32 0.83,0.4 1.21,0.16C8.49,4.76 9.34,4.4 10.26,4.2C10.7,4.1 11,3.69 11,3.23zM17.33,3.55c-0.94,-0.6 -2,-1.04 -3.12,-1.3C13.59,2.11 13,2.59 13,3.23l0,0c0,0.45 0.3,0.87 0.74,0.96c0.91,0.2 1.77,0.57 2.53,1.05c0.39,0.24 0.89,0.17 1.21,-0.16l0,0C17.94,4.64 17.87,3.89 17.33,3.55zM20.77,11L20.77,11c0.64,0 1.13,-0.59 0.99,-1.21c-0.26,-1.12 -0.7,-2.18 -1.3,-3.12c-0.34,-0.53 -1.1,-0.61 -1.55,-0.16l0,0c-0.32,0.32 -0.4,0.83 -0.16,1.21c0.49,0.77 0.85,1.62 1.05,2.53C19.9,10.7 20.31,11 20.77,11zM5.1,6.51L5.1,6.51C4.64,6.06 3.89,6.13 3.55,6.67c-0.6,0.94 -1.04,2 -1.3,3.12C2.11,10.41 2.59,11 3.23,11l0,0c0.45,0 0.87,-0.3 0.96,-0.74c0.2,-0.91 0.57,-1.77 1.05,-2.53C5.5,7.34 5.42,6.83 5.1,6.51zM3.23,13L3.23,13c-0.64,0 -1.13,0.59 -0.99,1.21c0.26,1.12 0.7,2.17 1.3,3.12c0.34,0.54 1.1,0.61 1.55,0.16l0,0c0.32,-0.32 0.4,-0.83 0.15,-1.21c-0.49,-0.76 -0.85,-1.61 -1.05,-2.53C4.1,13.3 3.69,13 3.23,13zM15,12c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3s1.34,3 3,3S15,13.66 15,12zM18.9,17.49L18.9,17.49c0.45,0.45 1.21,0.38 1.55,-0.15c0.6,-0.94 1.04,-2 1.3,-3.11c0.14,-0.62 -0.35,-1.21 -0.98,-1.21l0,0c-0.45,0 -0.87,0.3 -0.96,0.74c-0.2,0.91 -0.57,1.76 -1.05,2.53C18.5,16.66 18.58,17.17 18.9,17.49zM13,20.77L13,20.77c0,0.64 0.59,1.13 1.21,0.99c1.12,-0.26 2.17,-0.7 3.12,-1.3c0.54,-0.34 0.61,-1.1 0.16,-1.55l0,0c-0.32,-0.32 -0.83,-0.4 -1.21,-0.15c-0.76,0.49 -1.61,0.85 -2.53,1.05C13.3,19.9 13,20.31 13,20.77zM6.67,20.45c0.95,0.6 2,1.04 3.12,1.3C10.41,21.89 11,21.4 11,20.77l0,0c0,-0.45 -0.3,-0.87 -0.74,-0.96c-0.91,-0.2 -1.77,-0.57 -2.53,-1.05c-0.39,-0.24 -0.89,-0.17 -1.21,0.16l0,0C6.06,19.36 6.13,20.11 6.67,20.45z"/>
+ android:pathData="M11,3.23c0,-0.64 -0.59,-1.13 -1.21,-0.99 -1.12,0.26 -2.18,0.7 -3.12,1.3 -0.53,0.34 -0.61,1.1 -0.16,1.55 0.32,0.32 0.83,0.4 1.21,0.16 0.77,-0.49 1.62,-0.85 2.54,-1.05 0.44,-0.1 0.74,-0.51 0.74,-0.97zM17.33,3.55c-0.94,-0.6 -2,-1.04 -3.12,-1.3 -0.62,-0.14 -1.21,0.34 -1.21,0.98 0,0.45 0.3,0.87 0.74,0.96 0.91,0.2 1.77,0.57 2.53,1.05 0.39,0.24 0.89,0.17 1.21,-0.16 0.46,-0.44 0.39,-1.19 -0.15,-1.53zM20.77,11c0.64,0 1.13,-0.59 0.99,-1.21 -0.26,-1.12 -0.7,-2.18 -1.3,-3.12 -0.34,-0.53 -1.1,-0.61 -1.55,-0.16 -0.32,0.32 -0.4,0.83 -0.16,1.21 0.49,0.77 0.85,1.62 1.05,2.53 0.1,0.45 0.51,0.75 0.97,0.75zM5.1,6.51c-0.46,-0.45 -1.21,-0.38 -1.55,0.16 -0.6,0.94 -1.04,2 -1.3,3.12 -0.14,0.62 0.34,1.21 0.98,1.21 0.45,0 0.87,-0.3 0.96,-0.74 0.2,-0.91 0.57,-1.77 1.05,-2.53 0.26,-0.39 0.18,-0.9 -0.14,-1.22zM3.23,13c-0.64,0 -1.13,0.59 -0.99,1.21 0.26,1.12 0.7,2.17 1.3,3.12 0.34,0.54 1.1,0.61 1.55,0.16 0.32,-0.32 0.4,-0.83 0.15,-1.21 -0.49,-0.76 -0.85,-1.61 -1.05,-2.53 -0.09,-0.45 -0.5,-0.75 -0.96,-0.75zM15,12c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3 1.34,3 3,3 3,-1.34 3,-3zM18.9,17.49c0.45,0.45 1.21,0.38 1.55,-0.15 0.6,-0.94 1.04,-2 1.3,-3.11 0.14,-0.62 -0.35,-1.21 -0.98,-1.21 -0.45,0 -0.87,0.3 -0.96,0.74 -0.2,0.91 -0.57,1.76 -1.05,2.53 -0.26,0.37 -0.18,0.88 0.14,1.2zM13,20.77c0,0.64 0.59,1.13 1.21,0.99 1.12,-0.26 2.17,-0.7 3.12,-1.3 0.54,-0.34 0.61,-1.1 0.16,-1.55 -0.32,-0.32 -0.83,-0.4 -1.21,-0.15 -0.76,0.49 -1.61,0.85 -2.53,1.05 -0.45,0.09 -0.75,0.5 -0.75,0.96zM6.67,20.45c0.95,0.6 2,1.04 3.12,1.3 0.62,0.14 1.21,-0.35 1.21,-0.98 0,-0.45 -0.3,-0.87 -0.74,-0.96 -0.91,-0.2 -1.77,-0.57 -2.53,-1.05 -0.39,-0.24 -0.89,-0.17 -1.21,0.16 -0.46,0.44 -0.39,1.19 0.15,1.53z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/filter_vintage.xml b/compose/material/material/icons/generator/raw-icons/rounded/filter_vintage.xml
index fc6b90c..8233677 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/filter_vintage.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/filter_vintage.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.84,12c2.27,-2.01 1.08,-4.57 0.82,-5.01c-0.26,-0.44 -1.88,-2.74 -4.75,-1.78C15.31,2.25 12.51,2 12,2c-0.51,0 -3.31,0.25 -3.92,3.21C7.6,5.05 4.87,4.34 3.33,6.99C3.08,7.43 1.89,9.99 4.16,12c-2.27,2.01 -1.08,4.57 -0.82,5.01c0.26,0.44 1.88,2.74 4.75,1.78C8.69,21.75 11.49,22 12,22c0.51,0 3.31,-0.25 3.92,-3.21c2.87,0.96 4.49,-1.34 4.75,-1.78C20.92,16.57 22.11,14.01 19.84,12zM12,16c-2.21,0 -4,-1.79 -4,-4c0,-2.21 1.79,-4 4,-4s4,1.79 4,4C16,14.21 14.21,16 12,16z"/>
+ android:pathData="M18.7,12.4c-0.28,-0.16 -0.57,-0.29 -0.86,-0.4 0.29,-0.11 0.58,-0.24 0.86,-0.4 1.92,-1.11 2.99,-3.12 3,-5.19 -1.79,-1.03 -4.07,-1.11 -6,0 -0.28,0.16 -0.54,0.35 -0.78,0.54 0.05,-0.31 0.08,-0.63 0.08,-0.95 0,-2.22 -1.21,-4.15 -3,-5.19C10.21,1.85 9,3.78 9,6c0,0.32 0.03,0.64 0.08,0.95 -0.24,-0.2 -0.5,-0.39 -0.78,-0.55 -1.92,-1.11 -4.2,-1.03 -6,0 0,2.07 1.07,4.08 3,5.19 0.28,0.16 0.57,0.29 0.86,0.4 -0.29,0.11 -0.58,0.24 -0.86,0.4 -1.92,1.11 -2.99,3.12 -3,5.19 1.79,1.03 4.07,1.11 6,0 0.28,-0.16 0.54,-0.35 0.78,-0.54 -0.05,0.32 -0.08,0.64 -0.08,0.96 0,2.22 1.21,4.15 3,5.19 1.79,-1.04 3,-2.97 3,-5.19 0,-0.32 -0.03,-0.64 -0.08,-0.95 0.24,0.2 0.5,0.38 0.78,0.54 1.92,1.11 4.2,1.03 6,0 -0.01,-2.07 -1.08,-4.08 -3,-5.19zM12,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/find_in_page.xml b/compose/material/material/icons/generator/raw-icons/rounded/find_in_page.xml
index cebb8c0..9480c91 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/find_in_page.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/find_in_page.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.02,16.43c-0.8,0.47 -1.77,0.7 -2.82,0.48c-1.64,-0.34 -2.95,-1.72 -3.17,-3.38c-0.34,-2.63 1.87,-4.85 4.5,-4.5c1.66,0.22 3.04,1.52 3.38,3.17c0.22,1.05 -0.01,2.02 -0.48,2.82L20,19.59V8.72c0,-0.47 -0.16,-0.92 -0.46,-1.28L15.6,2.72C15.22,2.26 14.66,2 14.06,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c0.45,0 0.85,-0.15 1.19,-0.4L14.02,16.43z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,13m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M20,19.59V8.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.83,-4.83c-0.37,-0.38 -0.88,-0.59 -1.41,-0.59H6c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2H18c0.45,0 0.85,-0.15 1.19,-0.4l-4.43,-4.43c-0.86,0.56 -1.89,0.88 -3,0.82 -2.37,-0.11 -4.4,-1.96 -4.72,-4.31 -0.44,-3.35 2.45,-6.18 5.83,-5.61 1.95,0.33 3.57,1.85 4,3.78 0.33,1.46 0.01,2.82 -0.7,3.9L20,19.59zM9,13c0,1.66 1.34,3 3,3s3,-1.34 3,-3 -1.34,-3 -3,-3 -3,1.34 -3,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/find_replace.xml b/compose/material/material/icons/generator/raw-icons/rounded/find_replace.xml
index 25af6ed..78f8eed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/find_replace.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/find_replace.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.6,15.18c0.41,-0.56 0.75,-1.17 0.99,-1.84c0.23,-0.65 -0.24,-1.34 -0.94,-1.34h0c-0.42,0 -0.79,0.26 -0.93,0.66C15.03,14.6 13.18,16 11,16c-1.38,0 -2.62,-0.57 -3.52,-1.48l1.67,-1.67C9.46,12.54 9.24,12 8.79,12H4.5C4.22,12 4,12.22 4,12.5v4.29c0,0.45 0.54,0.67 0.85,0.35l1.2,-1.2C7.32,17.21 9.07,18 11,18c1.57,0 3.02,-0.52 4.19,-1.4l3.69,3.69c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L16.6,15.18zM11,6c1.38,0 2.62,0.57 3.52,1.48l-1.67,1.67C12.54,9.46 12.76,10 13.21,10h4.29c0.28,0 0.5,-0.22 0.5,-0.5V5.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.2,1.2C14.68,4.79 12.93,4 11,4C7.96,4 5.38,5.94 4.42,8.64C4.18,9.3 4.65,10 5.35,10h0c0.42,0 0.79,-0.26 0.93,-0.66C6.97,7.4 8.82,6 11,6z"/>
+ android:pathData="M11,6c1.38,0 2.63,0.56 3.54,1.46l-1.69,1.69c-0.31,0.31 -0.09,0.85 0.36,0.85h4.29c0.28,0 0.5,-0.22 0.5,-0.5L18,5.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.2,1.2C14.68,4.78 12.93,4 11,4 7.96,4 5.38,5.94 4.42,8.64c-0.24,0.66 0.23,1.36 0.93,1.36 0.42,0 0.79,-0.26 0.93,-0.66C6.96,7.4 8.82,6 11,6zM16.64,15.14c0.4,-0.54 0.72,-1.15 0.95,-1.8 0.23,-0.65 -0.25,-1.34 -0.94,-1.34 -0.42,0 -0.79,0.26 -0.93,0.66C15.04,14.6 13.18,16 11,16c-1.38,0 -2.63,-0.56 -3.54,-1.46l1.69,-1.69c0.31,-0.31 0.09,-0.85 -0.36,-0.85L4.5,12c-0.28,0 -0.5,0.22 -0.5,0.5v4.29c0,0.45 0.54,0.67 0.85,0.35l1.2,-1.2C7.32,17.22 9.07,18 11,18c1.55,0 2.98,-0.51 4.14,-1.36l4.11,4.11c0.41,0.41 1.08,0.41 1.49,0 0.41,-0.41 0.41,-1.08 0,-1.49l-4.1,-4.12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fingerprint.xml b/compose/material/material/icons/generator/raw-icons/rounded/fingerprint.xml
index 03c5ed5..2dfd992 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fingerprint.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fingerprint.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.82,4.47c-0.08,0 -0.16,-0.02 -0.23,-0.06C15.67,3.42 14.01,3 12.02,3c-1.98,0 -3.86,0.47 -5.57,1.41C6.2,4.54 5.9,4.45 5.76,4.21c-0.13,-0.24 -0.04,-0.55 0.2,-0.68C7.82,2.52 9.86,2 12.02,2c2.13,0 3.99,0.47 6.03,1.52c0.25,0.13 0.34,0.43 0.21,0.67C18.17,4.37 18,4.47 17.82,4.47zM3.5,9.72c-0.1,0 -0.2,-0.03 -0.29,-0.09c-0.23,-0.16 -0.28,-0.47 -0.12,-0.7c0.99,-1.4 2.25,-2.5 3.75,-3.27c3.14,-1.62 7.16,-1.63 10.31,-0.01c1.5,0.77 2.76,1.86 3.75,3.25c0.16,0.22 0.11,0.54 -0.12,0.7c-0.23,0.16 -0.54,0.11 -0.7,-0.12c-0.9,-1.26 -2.04,-2.25 -3.39,-2.94c-2.87,-1.47 -6.54,-1.47 -9.4,0.01c-1.36,0.7 -2.5,1.7 -3.4,2.96C3.81,9.65 3.66,9.72 3.5,9.72zM9.75,21.79c-0.13,0 -0.26,-0.05 -0.35,-0.15C8.53,20.77 8.06,20.21 7.39,19c-0.69,-1.23 -1.05,-2.73 -1.05,-4.34c0,-2.97 2.54,-5.39 5.66,-5.39s5.66,2.42 5.66,5.39c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5c0,-2.42 -2.09,-4.39 -4.66,-4.39s-4.66,1.97 -4.66,4.39c0,1.44 0.32,2.77 0.93,3.85c0.64,1.15 1.08,1.64 1.85,2.42c0.19,0.2 0.19,0.51 0,0.71C10.01,21.74 9.88,21.79 9.75,21.79zM16.93,19.94c-1.19,0 -2.24,-0.3 -3.1,-0.89c-1.49,-1.01 -2.38,-2.65 -2.38,-4.39c0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5c0,1.41 0.72,2.74 1.94,3.56c0.71,0.48 1.54,0.71 2.54,0.71c0.24,0 0.64,-0.03 1.04,-0.1c0.27,-0.05 0.53,0.13 0.58,0.41c0.05,0.27 -0.13,0.53 -0.41,0.58C17.57,19.93 17.07,19.94 16.93,19.94zM14.92,22c-0.04,0 -0.09,-0.01 -0.13,-0.02c-1.59,-0.44 -2.63,-1.03 -3.72,-2.1c-1.4,-1.39 -2.17,-3.24 -2.17,-5.22c0,-1.62 1.38,-2.94 3.08,-2.94s3.08,1.32 3.08,2.94c0,1.07 0.93,1.94 2.08,1.94c1.15,0 2.08,-0.87 2.08,-1.94c0,-3.77 -3.25,-6.83 -7.25,-6.83c-2.84,0 -5.44,1.58 -6.61,4.03c-0.39,0.81 -0.59,1.76 -0.59,2.8c0,0.78 0.07,2.01 0.67,3.61c0.1,0.26 -0.03,0.55 -0.29,0.64c-0.26,0.1 -0.55,-0.04 -0.64,-0.29c-0.49,-1.31 -0.73,-2.61 -0.73,-3.96c0,-1.2 0.23,-2.29 0.68,-3.24c1.33,-2.79 4.28,-4.6 7.51,-4.6c4.55,0 8.25,3.51 8.25,7.83c0,1.62 -1.38,2.94 -3.08,2.94c-1.7,0 -3.08,-1.32 -3.08,-2.94c0,-1.07 -0.93,-1.94 -2.08,-1.94s-2.08,0.87 -2.08,1.94c0,1.71 0.66,3.31 1.87,4.51c0.95,0.94 1.86,1.46 3.27,1.85c0.27,0.07 0.42,0.35 0.35,0.61C15.34,21.85 15.13,22 14.92,22z"/>
+ android:pathData="M17.81,4.47c-0.08,0 -0.16,-0.02 -0.23,-0.06C15.66,3.42 14,3 12.01,3c-1.98,0 -3.86,0.47 -5.57,1.41 -0.24,0.13 -0.54,0.04 -0.68,-0.2 -0.13,-0.24 -0.04,-0.55 0.2,-0.68C7.82,2.52 9.86,2 12.01,2c2.13,0 3.99,0.47 6.03,1.52 0.25,0.13 0.34,0.43 0.21,0.67 -0.09,0.18 -0.26,0.28 -0.44,0.28zM3.5,9.72c-0.1,0 -0.2,-0.03 -0.29,-0.09 -0.23,-0.16 -0.28,-0.47 -0.12,-0.7 0.99,-1.4 2.25,-2.5 3.75,-3.27C9.98,4.04 14,4.03 17.15,5.65c1.5,0.77 2.76,1.86 3.75,3.25 0.16,0.22 0.11,0.54 -0.12,0.7 -0.23,0.16 -0.54,0.11 -0.7,-0.12 -0.9,-1.26 -2.04,-2.25 -3.39,-2.94 -2.87,-1.47 -6.54,-1.47 -9.4,0.01 -1.36,0.7 -2.5,1.7 -3.4,2.96 -0.08,0.14 -0.23,0.21 -0.39,0.21zM9.75,21.79c-0.13,0 -0.26,-0.05 -0.35,-0.15 -0.87,-0.87 -1.34,-1.43 -2.01,-2.64 -0.69,-1.23 -1.05,-2.73 -1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66,2.42 5.66,5.39c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5c0,-2.42 -2.09,-4.39 -4.66,-4.39s-4.66,1.97 -4.66,4.39c0,1.44 0.32,2.77 0.93,3.85 0.64,1.15 1.08,1.64 1.85,2.42 0.19,0.2 0.19,0.51 0,0.71 -0.11,0.1 -0.24,0.15 -0.37,0.15zM16.92,19.94c-1.19,0 -2.24,-0.3 -3.1,-0.89 -1.49,-1.01 -2.38,-2.65 -2.38,-4.39 0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5c0,1.41 0.72,2.74 1.94,3.56 0.71,0.48 1.54,0.71 2.54,0.71 0.24,0 0.64,-0.03 1.04,-0.1 0.27,-0.05 0.53,0.13 0.58,0.41 0.05,0.27 -0.13,0.53 -0.41,0.58 -0.57,0.11 -1.07,0.12 -1.21,0.12zM14.91,22c-0.04,0 -0.09,-0.01 -0.13,-0.02 -1.59,-0.44 -2.63,-1.03 -3.72,-2.1 -1.4,-1.39 -2.17,-3.24 -2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94s3.08,1.32 3.08,2.94c0,1.07 0.93,1.94 2.08,1.94s2.08,-0.87 2.08,-1.94c0,-3.77 -3.25,-6.83 -7.25,-6.83 -2.84,0 -5.44,1.58 -6.61,4.03 -0.39,0.81 -0.59,1.76 -0.59,2.8 0,0.78 0.07,2.01 0.67,3.61 0.1,0.26 -0.03,0.55 -0.29,0.64 -0.26,0.1 -0.55,-0.04 -0.64,-0.29 -0.49,-1.31 -0.73,-2.61 -0.73,-3.96 0,-1.2 0.23,-2.29 0.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55,0 8.25,3.51 8.25,7.83 0,1.62 -1.38,2.94 -3.08,2.94s-3.08,-1.32 -3.08,-2.94c0,-1.07 -0.93,-1.94 -2.08,-1.94s-2.08,0.87 -2.08,1.94c0,1.71 0.66,3.31 1.87,4.51 0.95,0.94 1.86,1.46 3.27,1.85 0.27,0.07 0.42,0.35 0.35,0.61 -0.05,0.23 -0.26,0.38 -0.47,0.38z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fireplace.xml b/compose/material/material/icons/generator/raw-icons/rounded/fireplace.xml
index 73ab18ca..0cc823e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fireplace.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fireplace.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM10.6,16.97c0.76,-0.25 1.4,-1.04 1.53,-1.63c0.13,-0.56 -0.1,-1.05 -0.2,-1.6c-0.07,-0.46 -0.07,-0.86 0.08,-1.28c0.54,1.21 2.15,1.65 1.98,3.19C13.8,17.34 11.88,18.02 10.6,16.97zM20,20h-2v-1c0,-0.55 -0.45,-1 -1,-1h-1.15c0.71,-0.85 1.15,-1.89 1.15,-3c0,-1.89 -1.09,-2.84 -1.85,-3.36c-1.86,-1.27 -2.23,-2.78 -2.25,-3.72c-0.01,-0.4 -0.43,-0.63 -0.77,-0.43c-5.8,3.43 -5.15,7 -5.13,7.51c0.03,0.96 0.49,2.07 1.24,3H7c-0.55,0 -1,0.45 -1,1v1H4V4h16V20z"/>
+ android:pathData="M20,2H4C2.9,2 2,2.9 2,4v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM20,19c0,0.55 -0.45,1 -1,1h-1v-1c0,-0.55 -0.45,-1 -1,-1h-1.15c0.71,-0.85 1.15,-1.89 1.15,-3c0,-1.89 -1.09,-2.84 -1.85,-3.36c-1.86,-1.27 -2.23,-2.78 -2.25,-3.72c-0.01,-0.4 -0.43,-0.63 -0.77,-0.43c-5.8,3.43 -5.15,7 -5.13,7.51c0.03,0.96 0.49,2.07 1.24,3H7c-0.55,0 -1,0.45 -1,1v1H5c-0.55,0 -1,-0.45 -1,-1V5c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1V19zM13.2,13.74c-0.08,-0.46 -0.07,-0.85 0.08,-1.28c0.54,1.21 2.15,1.64 1.98,3.18c-0.19,1.69 -2.11,2.37 -3.39,1.32c0.76,-0.24 1.4,-1.04 1.53,-1.63C13.52,14.78 13.29,14.29 13.2,13.74z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/first_page.xml b/compose/material/material/icons/generator/raw-icons/rounded/first_page.xml
index a172184..af85c87 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/first_page.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/first_page.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.7,15.89L13.82,12l3.89,-3.89c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l0,0C18.09,16.91 18.09,16.27 17.7,15.89zM7,6L7,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1V7C6,6.45 6.45,6 7,6z"/>
+ android:pathData="M17.7,15.89L13.82,12l3.89,-3.89c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0 0.38,-0.38 0.38,-1.02 -0.01,-1.4zM7,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fitbit.xml b/compose/material/material/icons/generator/raw-icons/rounded/fitbit.xml
new file mode 100644
index 0000000..da71490
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fitbit.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.89,13.89c1.04,0 1.89,-0.85 1.89,-1.89s-0.85,-1.89 -1.89,-1.89C18.85,10.11 18,10.96 18,12S18.85,13.89 19.89,13.89zM15.65,13.68c0.93,0 1.68,-0.75 1.68,-1.68s-0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68S14.72,13.68 15.65,13.68zM15.65,9.42c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,8.67 14.72,9.42 15.65,9.42zM15.65,17.93c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,17.17 14.72,17.93 15.65,17.93zM11.41,13.47c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,13.47 11.41,13.47zM11.41,9.21c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,9.21 11.41,9.21zM11.41,17.73c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,17.07 10.59,17.73 11.41,17.73zM11.41,22c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,21.34 10.59,22 11.41,22zM11.41,4.94c0.81,0 1.47,-0.66 1.47,-1.47S12.22,2 11.41,2c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,4.94 11.41,4.94zM7.16,13.26c0.7,0 1.26,-0.57 1.26,-1.26s-0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26S6.46,13.26 7.16,13.26zM7.16,17.51c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,16.94 6.46,17.51 7.16,17.51zM7.16,9.02c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,8.45 6.46,9.02 7.16,9.02zM3.29,13.05c0.58,0 1.05,-0.47 1.05,-1.05s-0.47,-1.05 -1.05,-1.05c-0.58,0 -1.05,0.47 -1.05,1.05S2.71,13.05 3.29,13.05z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fitness_center.xml b/compose/material/material/icons/generator/raw-icons/rounded/fitness_center.xml
index 9158c1f..3dc5972 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fitness_center.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fitness_center.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.57,14.86l0.72,-0.72c0.39,-0.39 0.39,-1.02 0,-1.41l-0.02,-0.02c-0.39,-0.39 -1.02,-0.39 -1.41,0L17,15.57L8.43,7l2.86,-2.86c0.39,-0.39 0.39,-1.02 0,-1.41l-0.02,-0.02c-0.39,-0.39 -1.02,-0.39 -1.41,0L9.14,3.43L8.42,2.71C8.03,2.32 7.39,2.32 7,2.71L5.57,4.14L4.85,3.42c-0.39,-0.39 -1.04,-0.39 -1.43,0l0,0c-0.39,0.39 -0.39,1.04 0,1.43l0.72,0.72L2.71,7c-0.39,0.39 -0.39,1.02 0,1.41l0.72,0.72L2.71,9.86c-0.39,0.39 -0.39,1.02 0,1.41l0.02,0.02c0.39,0.39 1.02,0.39 1.41,0L7,8.43L15.57,17l-2.86,2.86c-0.39,0.39 -0.39,1.02 0,1.41l0.02,0.02c0.39,0.39 1.02,0.39 1.41,0l0.72,-0.72l0.72,0.72c0.39,0.39 1.02,0.39 1.41,0l1.43,-1.43l0.72,0.72c0.39,0.39 1.04,0.39 1.43,0l0,0c0.39,-0.39 0.39,-1.04 0,-1.43l-0.72,-0.72L21.29,17c0.39,-0.39 0.39,-1.02 0,-1.41L20.57,14.86z"/>
+ android:pathData="M20.57,14.86l0.72,-0.72c0.39,-0.39 0.39,-1.02 0,-1.41l-0.02,-0.02c-0.39,-0.39 -1.02,-0.39 -1.41,0L17,15.57 8.43,7l2.86,-2.86c0.39,-0.39 0.39,-1.02 0,-1.41l-0.02,-0.02c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.72,0.72 -0.72,-0.72c-0.39,-0.39 -1.03,-0.39 -1.42,0L5.57,4.14l-0.72,-0.72c-0.39,-0.39 -1.04,-0.39 -1.43,0 -0.39,0.39 -0.39,1.04 0,1.43l0.72,0.72L2.71,7c-0.39,0.39 -0.39,1.02 0,1.41l0.72,0.72 -0.72,0.73c-0.39,0.39 -0.39,1.02 0,1.41l0.02,0.02c0.39,0.39 1.02,0.39 1.41,0L7,8.43 15.57,17l-2.86,2.86c-0.39,0.39 -0.39,1.02 0,1.41l0.02,0.02c0.39,0.39 1.02,0.39 1.41,0l0.72,-0.72 0.72,0.72c0.39,0.39 1.02,0.39 1.41,0l1.43,-1.43 0.72,0.72c0.39,0.39 1.04,0.39 1.43,0 0.39,-0.39 0.39,-1.04 0,-1.43l-0.72,-0.72L21.29,17c0.39,-0.39 0.39,-1.02 0,-1.41l-0.72,-0.73z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flag.xml b/compose/material/material/icons/generator/raw-icons/rounded/flag.xml
index dabb708..863a757 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flag.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flag.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.4,6l-0.24,-1.2C14.07,4.34 13.66,4 13.18,4H6C5.45,4 5,4.45 5,5v15c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-6h5.6l0.24,1.2c0.09,0.47 0.5,0.8 0.98,0.8H19c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1H14.4z"/>
+ android:pathData="M14.4,6l-0.24,-1.2c-0.09,-0.46 -0.5,-0.8 -0.98,-0.8H6c-0.55,0 -1,0.45 -1,1v15c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-6h5.6l0.24,1.2c0.09,0.47 0.5,0.8 0.98,0.8H19c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1h-4.6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flare.xml b/compose/material/material/icons/generator/raw-icons/rounded/flare.xml
index bc03848..8d4c68d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flare.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flare.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,11H2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1l0,0C7,11.45 6.55,11 6,11zM8.47,7.06L7.75,6.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l0.71,0.71c0.39,0.39 1.02,0.39 1.41,0l0,0C8.85,8.08 8.85,7.44 8.47,7.06zM12,1L12,1c-0.56,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V2C13,1.45 12.55,1 12,1zM17.66,6.35L17.66,6.35c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l0.71,-0.71C18.04,7.37 18.04,6.73 17.66,6.35zM17,12L17,12c0,0.56 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-4C17.45,11 17,11.45 17,12zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S13.66,9 12,9zM15.53,16.94l0.71,0.71c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-0.71,-0.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C15.15,15.92 15.15,16.56 15.53,16.94zM6.34,17.65L6.34,17.65c0.39,0.39 1.02,0.39 1.41,0l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71C5.96,16.63 5.96,17.27 6.34,17.65zM12,23L12,23c0.56,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v4C11,22.55 11.45,23 12,23z"/>
+ android:pathData="M6,11L2,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM8.47,7.06l-0.72,-0.72c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l0.71,0.71c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.38 0.39,-1.02 0.01,-1.4zM12,1c-0.56,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1L13,2c0,-0.55 -0.45,-1 -1,-1zM17.66,6.35c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l0.71,-0.71c0.38,-0.39 0.38,-1.03 0,-1.41zM17,12c0,0.56 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM15.53,16.94l0.71,0.71c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41l-0.71,-0.71c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.38,0.39 -0.38,1.03 0,1.41zM6.34,17.65c0.39,0.39 1.02,0.39 1.41,0l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71c-0.38,0.39 -0.38,1.03 0,1.41zM12,23c0.56,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flash_auto.xml b/compose/material/material/icons/generator/raw-icons/rounded/flash_auto.xml
index a3de8bf..4272c8b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flash_auto.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flash_auto.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,3v10c0,0.55 0.45,1 1,1h2v7.15c0,0.51 0.67,0.69 0.93,0.25l5.19,-8.9c0.39,-0.67 -0.09,-1.5 -0.86,-1.5H9l3.38,-7.59C12.67,2.74 12.18,2 11.46,2H4C3.45,2 3,2.45 3,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.81,2L17.81,2c-0.48,0 -0.92,0.3 -1.09,0.75L14,10.02C13.82,10.49 14.17,11 14.67,11h0c0.31,0 0.58,-0.19 0.68,-0.48L16,8.7h3.63l0.64,1.82c0.1,0.29 0.38,0.48 0.68,0.48l0,0c0.51,0 0.86,-0.51 0.68,-0.98L18.9,2.75C18.73,2.3 18.3,2 17.81,2zM16.47,7.39l1.31,-3.72h0.08l1.31,3.72H16.47z"/>
+ android:pathData="M3,3v10c0,0.55 0.45,1 1,1h2v7.15c0,0.51 0.67,0.69 0.93,0.25l5.19,-8.9c0.39,-0.67 -0.09,-1.5 -0.86,-1.5L9,11l3.38,-7.59c0.29,-0.67 -0.2,-1.41 -0.92,-1.41L4,2c-0.55,0 -1,0.45 -1,1zM18,2c-0.6,0 -1.13,0.38 -1.34,0.94L14.22,9.8c-0.2,0.59 0.23,1.2 0.85,1.2 0.38,0 0.72,-0.24 0.84,-0.6L16.4,9h3.2l0.49,1.4c0.13,0.36 0.46,0.6 0.84,0.6 0.62,0 1.05,-0.61 0.84,-1.19l-2.44,-6.86C19.13,2.38 18.6,2 18,2zM16.85,7.65L18,4l1.15,3.65h-2.3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flash_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/flash_off.xml
index 61b37ea..fe9f5bb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flash_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flash_off.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.83,11l2,2l0.29,-0.5c0.39,-0.67 -0.09,-1.5 -0.86,-1.5H13.83z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.38,3.41C16.67,2.74 16.18,2 15.46,2H8C7.45,2 7,2.45 7,3v1.17l6.26,6.26L16.38,3.41z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.49,20.48L3.52,3.52c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.03 0,1.42L7,9.83V13c0,0.55 0.45,1 1,1h2v7.15c0,0.51 0.67,0.69 0.93,0.25l2.82,-4.83l5.32,5.32c0.39,0.39 1.03,0.39 1.42,0C20.88,21.51 20.88,20.87 20.49,20.48z"/>
+ android:pathData="M16.12,11.5c0.39,-0.67 -0.09,-1.5 -0.86,-1.5h-1.87l2.28,2.28 0.45,-0.78zM16.28,3.45c0.33,-0.67 -0.15,-1.45 -0.9,-1.45L8,2c-0.55,0 -1,0.45 -1,1v0.61l6.13,6.13 3.15,-6.29zM18.44,17.88L4.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L7,9.27L7,12c0,0.55 0.45,1 1,1h2v7.15c0,0.51 0.67,0.69 0.93,0.25l2.65,-4.55 3.44,3.44c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.39 0.4,-1.02 0.01,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flash_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/flash_on.xml
index 3c0c4a3..f56467f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flash_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flash_on.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,3v10c0,0.55 0.45,1 1,1h2v7.15c0,0.51 0.67,0.69 0.93,0.25l5.19,-8.9c0.39,-0.67 -0.09,-1.5 -0.86,-1.5H13l3.38,-7.59C16.67,2.74 16.18,2 15.46,2H8C7.45,2 7,2.45 7,3z"/>
+ android:pathData="M7,3v9c0,0.55 0.45,1 1,1h2v7.15c0,0.51 0.67,0.69 0.93,0.25l5.19,-8.9c0.39,-0.67 -0.09,-1.5 -0.86,-1.5H13l2.49,-6.65c0.25,-0.65 -0.23,-1.35 -0.93,-1.35H8c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flight.xml b/compose/material/material/icons/generator/raw-icons/rounded/flight.xml
index 7a6c65f..48dd4b4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flight.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flight.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,14.6L22,14.6c0,-0.37 -0.2,-0.72 -0.52,-0.9L13.5,9l0,-5.42c0,-0.81 -0.61,-1.54 -1.42,-1.58c-0.87,-0.04 -1.58,0.64 -1.58,1.5V9l-7.98,4.7C2.2,13.88 2,14.23 2,14.6v0c0,0.7 0.67,1.2 1.34,1.01l7.16,-2.1V19l-1.67,1.25c-0.21,0.16 -0.33,0.4 -0.33,0.66l0,0c0,0.55 0.52,0.94 1.05,0.79L12,21l2.45,0.7c0.52,0.15 1.05,-0.24 1.05,-0.79l0,0c0,-0.26 -0.12,-0.5 -0.33,-0.66L13.5,19v-5.5l7.16,2.1C21.33,15.8 22,15.3 22,14.6z"/>
+ android:pathData="M21,14.58c0,-0.36 -0.19,-0.69 -0.49,-0.89L13,9V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5V9l-7.51,4.69c-0.3,0.19 -0.49,0.53 -0.49,0.89 0,0.7 0.68,1.21 1.36,1L10,13.5V19l-1.8,1.35c-0.13,0.09 -0.2,0.24 -0.2,0.4v0.59c0,0.33 0.32,0.57 0.64,0.48L11.5,21l2.86,0.82c0.32,0.09 0.64,-0.15 0.64,-0.48v-0.59c0,-0.16 -0.07,-0.31 -0.2,-0.4L13,19v-5.5l6.64,2.08c0.68,0.21 1.36,-0.3 1.36,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flight_class.xml b/compose/material/material/icons/generator/raw-icons/rounded/flight_class.xml
new file mode 100644
index 0000000..c670b0c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flight_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,4h-2c-1.1,0 -2,0.9 -2,2v5c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2V6C18,4.9 17.1,4 16,4zM6,4c0.55,0 1,0.45 1,1v3l2.5,8H17c0.55,0 1,0.45 1,1s-0.45,1 -1,1H9.49c-0.88,0 -1.66,-0.58 -1.92,-1.43L5.08,8.28C5.03,8.09 5,7.9 5,7.71V5C5,4.45 5.45,4 6,4zM18,20c0,0.55 -0.45,1 -1,1H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8C17.55,19 18,19.45 18,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flight_land.xml b/compose/material/material/icons/generator/raw-icons/rounded/flight_land.xml
index bfa1a0d..b5500c7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flight_land.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flight_land.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,20.55 3.45,21 4,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.99,14.1c-0.07,-0.71 -0.62,-1.28 -1.3,-1.47l-4.92,-1.37L12.19,3.1c-0.12,-0.37 -0.42,-0.66 -0.8,-0.75l0,0C10.68,2.17 10,2.71 10,3.43v6.51L5.2,8.61L4.63,6.9C4.55,6.65 4.35,6.45 4.1,6.37l0,0C3.56,6.19 3,6.59 3,7.16v3.58c0,0.45 0.3,0.84 0.73,0.96l15.13,4.2C19.99,16.22 21.11,15.31 20.99,14.1z"/>
+ android:pathData="M20.5,19h-17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM3.51,11.61l15.83,4.24c0.8,0.21 1.62,-0.26 1.84,-1.06 0.21,-0.8 -0.26,-1.62 -1.06,-1.84l-5.31,-1.42 -2.58,-8.45c-0.11,-0.36 -0.39,-0.63 -0.75,-0.73 -0.68,-0.18 -1.35,0.33 -1.35,1.04v6.88L5.15,8.95 4.4,7.09c-0.12,-0.29 -0.36,-0.51 -0.67,-0.59l-0.33,-0.09c-0.32,-0.09 -0.63,0.15 -0.63,0.48v3.75c0,0.46 0.3,0.85 0.74,0.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flight_takeoff.xml b/compose/material/material/icons/generator/raw-icons/rounded/flight_takeoff.xml
index 055d7ca..aecbc77 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flight_takeoff.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flight_takeoff.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,20.55 3.45,21 4,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.78,9.24c-0.39,-0.68 -1.23,-0.97 -1.99,-0.77L14.87,9.8L8.48,4.09C8.19,3.83 7.79,3.74 7.42,3.85l0,0C6.72,4.06 6.4,4.87 6.77,5.49l3.32,5.6l-4.81,1.3l-1.42,-1.26c-0.2,-0.18 -0.47,-0.25 -0.73,-0.19h0c-0.56,0.12 -0.83,0.75 -0.54,1.24l1.88,3.17c0.23,0.39 0.69,0.57 1.12,0.46l15.16,-4.09C21.82,11.42 22.32,10.2 21.78,9.24z"/>
+ android:pathData="M20.5,19h-17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM22.07,9.64c-0.22,-0.8 -1.04,-1.27 -1.84,-1.06L14.92,10 8.46,3.98c-0.27,-0.26 -0.66,-0.35 -1.02,-0.25 -0.68,0.19 -1,0.97 -0.65,1.58l3.44,5.96 -4.97,1.33 -1.57,-1.24c-0.25,-0.19 -0.57,-0.26 -0.88,-0.18l-0.33,0.09c-0.32,0.08 -0.47,0.45 -0.3,0.73l1.88,3.25c0.23,0.39 0.69,0.58 1.12,0.47L21,11.48c0.8,-0.22 1.28,-1.04 1.07,-1.84z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flip.xml b/compose/material/material/icons/generator/raw-icons/rounded/flip.xml
index 54a7a86..56f4ae9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flip.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flip.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,21h2v-2h-2V21zM19,9h2V7h-2V9zM3,5v14c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5V5h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5zM19,3v2h2C21,3.9 20.1,3 19,3zM12,23L12,23c0.55,0 1,-0.45 1,-1V2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v20C11,22.55 11.45,23 12,23zM19,17h2v-2h-2V17zM15,5h2V3h-2V5zM19,13h2v-2h-2V13zM19,21c1.1,0 2,-0.9 2,-2h-2V21z"/>
+ android:pathData="M15,21h2v-2h-2v2zM19,9h2L21,7h-2v2zM3,5v14c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,3c-1.1,0 -2,0.9 -2,2zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM12,23c0.55,0 1,-0.45 1,-1L13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v20c0,0.55 0.45,1 1,1zM19,17h2v-2h-2v2zM15,5h2L17,3h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_android.xml b/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_android.xml
index 1036f78..c6326e9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_android.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_android.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,12c0,1.66 1.34,3 3,3s3,-1.34 3,-3c0,-1.66 -1.34,-3 -3,-3S9,10.34 9,12zM21.5,14h-4.29c-0.45,0 -0.67,0.54 -0.35,0.85l1.69,1.69C17.1,18.63 14.72,20 12,20c-3.49,0 -6.45,-2.24 -7.54,-5.36C4.32,14.25 3.93,14 3.52,14c-0.68,0 -1.18,0.67 -0.96,1.31C3.93,19.21 7.64,22 12,22c3.27,0 6.18,-1.58 8,-4l1.15,1.15c0.32,0.32 0.85,0.09 0.85,-0.35V14.5C22,14.22 21.78,14 21.5,14zM7.15,9.15L5.45,7.45C6.9,5.37 9.28,4 12,4c3.49,0 6.45,2.24 7.54,5.36C19.68,9.75 20.07,10 20.48,10c0.68,0 1.18,-0.67 0.96,-1.31C20.07,4.79 16.36,2 12,2C8.73,2 5.82,3.58 4,6L2.85,4.85C2.54,4.54 2,4.76 2,5.21V9.5C2,9.78 2.22,10 2.5,10h4.29C7.24,10 7.46,9.46 7.15,9.15z"/>
+ android:pathData="M9,12c0,1.66 1.34,3 3,3s3,-1.34 3,-3s-1.34,-3 -3,-3S9,10.34 9,12z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,9L8,9c0,-0.55 -0.45,-1 -1,-1H5.09C6.47,5.61 9.05,4 12,4c3.49,0 6.45,2.24 7.54,5.36C19.68,9.75 20.07,10 20.48,10h0c0.68,0 1.18,-0.67 0.96,-1.31C20.07,4.79 16.36,2 12,2C8.73,2 5.82,3.58 4,6.01V5c0,-0.55 -0.45,-1 -1,-1h0C2.45,4 2,4.45 2,5v4c0,0.55 0.45,1 1,1h4C7.55,10 8,9.55 8,9z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,15L16,15c0,0.55 0.45,1 1,1h1.91c-1.38,2.39 -3.96,4 -6.91,4c-3.49,0 -6.45,-2.24 -7.54,-5.36C4.32,14.25 3.93,14 3.52,14h0c-0.68,0 -1.18,0.67 -0.96,1.31C3.93,19.21 7.64,22 12,22c3.27,0 6.18,-1.58 8,-4.01V19c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-4C16.45,14 16,14.45 16,15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_ios.xml b/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_ios.xml
index a0490ad..cd7043e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_ios.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flip_camera_ios.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2h-3.17l-1.38,-1.51C15.16,3.18 14.76,3 14.34,3H9.66C9.24,3 8.84,3.18 8.55,3.49L7.17,5H4C2.9,5 2,5.9 2,7zM10.75,17.83c-0.55,-0.15 -0.74,-0.85 -0.33,-1.25l0,0c0.19,-0.19 0.45,-0.26 0.71,-0.19c0.28,0.07 0.57,0.12 0.87,0.12c1.93,0 3.5,-1.57 3.5,-3.5h-0.54c-0.45,0 -0.67,-0.54 -0.35,-0.85l1.29,-1.29c0.2,-0.2 0.51,-0.2 0.71,0l1.29,1.29c0.31,0.31 0.09,0.85 -0.35,0.85H17c0,2.76 -2.24,5 -5,5C11.57,18 11.15,17.94 10.75,17.83zM7.4,15.15L6.1,13.85C5.79,13.54 6.01,13 6.46,13H7c0,-2.76 2.24,-5 5,-5c0.43,0 0.85,0.06 1.25,0.17c0.55,0.15 0.74,0.85 0.33,1.25l0,0c-0.19,0.19 -0.45,0.26 -0.71,0.19C12.59,9.54 12.3,9.5 12,9.5c-1.93,0 -3.5,1.57 -3.5,3.5h0.54c0.45,0 0.67,0.54 0.35,0.85L8.1,15.15C7.91,15.34 7.59,15.34 7.4,15.15z"/>
+ android:pathData="M20,5h-3.17l-1.24,-1.35C15.22,3.24 14.68,3 14.12,3H9.88c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM13.67,17.7C13.15,17.89 12.59,18 12,18c-2.76,0 -5,-2.24 -5,-5H5l2.5,-2.5L10,13H8c0,2.21 1.79,4 4,4c0.46,0 0.91,-0.08 1.32,-0.23c0.19,-0.07 0.39,-0.03 0.53,0.11C14.11,17.14 14.01,17.57 13.67,17.7zM16.5,15.5L14,13h2c0,-2.21 -1.79,-4 -4,-4c-0.46,0 -0.91,0.08 -1.32,0.23c-0.19,0.07 -0.39,0.03 -0.53,-0.11C9.89,8.86 9.99,8.43 10.33,8.3C10.85,8.11 11.41,8 12,8c2.76,0 5,2.24 5,5h2L16.5,15.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flip_to_back.xml b/compose/material/material/icons/generator/raw-icons/rounded/flip_to_back.xml
index 9e69e53e..7228a79 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flip_to_back.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flip_to_back.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,7H7v2h2V7zM9,11H7v2h2V11zM9,3C7.89,3 7,3.9 7,5h2V3zM13,15h-2v2h2V15zM19,3v2h2C21,3.9 20.1,3 19,3zM13,3h-2v2h2V3zM9,17v-2H7C7,16.1 7.89,17 9,17zM19,13h2v-2h-2V13zM19,9h2V7h-2V9zM19,17c1.1,0 2,-0.9 2,-2h-2V17zM4,7C3.45,7 3,7.45 3,8v11c0,1.1 0.9,2 2,2h11c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5V8C5,7.45 4.55,7 4,7zM15,5h2V3h-2V5zM15,17h2v-2h-2V17z"/>
+ android:pathData="M9,7L7,7v2h2L9,7zM9,11L7,11v2h2v-2zM9,3c-1.11,0 -2,0.9 -2,2h2L9,3zM13,15h-2v2h2v-2zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM13,3h-2v2h2L13,3zM9,17v-2L7,15c0,1.1 0.89,2 2,2zM19,13h2v-2h-2v2zM19,9h2L21,7h-2v2zM19,17c1.1,0 2,-0.9 2,-2h-2v2zM4,7c-0.55,0 -1,0.45 -1,1v11c0,1.1 0.9,2 2,2h11c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,19c-0.55,0 -1,-0.45 -1,-1L5,8c0,-0.55 -0.45,-1 -1,-1zM15,5h2L17,3h-2v2zM15,17h2v-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/flip_to_front.xml b/compose/material/material/icons/generator/raw-icons/rounded/flip_to_front.xml
index a6f9ee6..05c8520 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/flip_to_front.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/flip_to_front.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,13h2v-2H3V13zM3,17h2v-2H3V17zM5,21v-2H3C3,20.1 3.89,21 5,21zM3,9h2V7H3V9zM15,21h2v-2h-2V21zM19,3H9C7.89,3 7,3.9 7,5v10c0,1.1 0.89,2 2,2h10c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,15H9V5h10V15zM11,21h2v-2h-2V21zM7,21h2v-2H7V21z"/>
+ android:pathData="M3,13h2v-2L3,11v2zM3,17h2v-2L3,15v2zM5,21v-2L3,19c0,1.1 0.89,2 2,2zM3,9h2L5,7L3,7v2zM15,21h2v-2h-2v2zM19,3L9,3c-1.11,0 -2,0.9 -2,2v10c0,1.1 0.89,2 2,2h10c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,15h-8c-0.55,0 -1,-0.45 -1,-1L9,6c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1zM11,21h2v-2h-2v2zM7,21h2v-2L7,19v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/folder.xml b/compose/material/material/icons/generator/raw-icons/rounded/folder.xml
index b2f2e81..8500b83 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/folder.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/folder.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.59,4.59C10.21,4.21 9.7,4 9.17,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8L10.59,4.59z"/>
+ android:pathData="M10.59,4.59C10.21,4.21 9.7,4 9.17,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-1.41,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/folder_open.xml b/compose/material/material/icons/generator/raw-icons/rounded/folder_open.xml
index b2f2e81..2a9b64e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/folder_open.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/folder_open.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.59,4.59C10.21,4.21 9.7,4 9.17,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8L10.59,4.59z"/>
+ android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM19,18L5,18c-0.55,0 -1,-0.45 -1,-1L4,9c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/folder_shared.xml b/compose/material/material/icons/generator/raw-icons/rounded/folder_shared.xml
index 211b2a7..f02befc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/folder_shared.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/folder_shared.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM15,9c1.1,0 2,0.9 2,2c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2C13,9.9 13.9,9 15,9zM19,17h-8v-0.57c0,-0.81 0.48,-1.53 1.22,-1.85C13.07,14.21 14.01,14 15,14c0.99,0 1.93,0.21 2.78,0.58C18.52,14.9 19,15.62 19,16.43V17z"/>
+ android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM15,9c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2zM19,17h-8v-1c0,-1.33 2.67,-2 4,-2s4,0.67 4,2v1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/folder_special.xml b/compose/material/material/icons/generator/raw-icons/rounded/folder_special.xml
index c20d9bb..be21c18 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/folder_special.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/folder_special.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM15.98,15.74l-1.07,-0.82l-1.07,0.82c-0.39,0.29 -0.92,-0.08 -0.78,-0.55l0.42,-1.36l-1.2,-0.95C11.91,12.6 12.12,12 12.59,12H14l0.43,-1.34c0.15,-0.46 0.8,-0.46 0.95,0L15.82,12h1.41c0.47,0 0.68,0.6 0.31,0.89l-1.2,0.95l0.42,1.36C16.91,15.66 16.37,16.04 15.98,15.74z"/>
+ android:pathData="M20,6h-8l-1.41,-1.41C10.21,4.21 9.7,4 9.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM16.94,16.41L15,15.28l-1.94,1.13c-0.38,0.22 -0.84,-0.12 -0.74,-0.55l0.51,-2.2 -1.69,-1.46c-0.33,-0.29 -0.16,-0.84 0.28,-0.88l2.23,-0.19 0.88,-2.06c0.17,-0.4 0.75,-0.4 0.92,0l0.88,2.06 2.23,0.19c0.44,0.04 0.62,0.59 0.28,0.88l-1.69,1.46 0.51,2.2c0.11,0.43 -0.35,0.77 -0.72,0.55z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/font_download.xml b/compose/material/material/icons/generator/raw-icons/rounded/font_download.xml
index a6519b5..e437cc5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/font_download.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/font_download.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.05,8.23l-0.1,0l-1.75,4.96l3.59,0z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM16.19,18h-0.01c-0.41,0 -0.77,-0.26 -0.91,-0.64l-0.85,-2.42H9.58l-0.86,2.43C8.58,17.74 8.22,18 7.82,18H7.8c-0.67,0 -1.13,-0.67 -0.9,-1.3L10.55,7c0.23,-0.6 0.8,-1 1.45,-1s1.22,0.4 1.45,1l3.64,9.7C17.33,17.33 16.86,18 16.19,18z"/>
+ android:pathData="M9.93,13.5h4.14L12,7.98 9.93,13.5zM20,2L4,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM15.71,17.88l-0.9,-2.38L9.17,15.5l-0.89,2.37c-0.14,0.38 -0.5,0.63 -0.91,0.63 -0.68,0 -1.15,-0.69 -0.9,-1.32l4.25,-10.81c0.22,-0.53 0.72,-0.87 1.28,-0.87s1.06,0.34 1.27,0.87l4.25,10.81c0.25,0.63 -0.22,1.32 -0.9,1.32 -0.4,0 -0.76,-0.25 -0.91,-0.62z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_align_center.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_align_center.xml
index e58f3fe..434dbe4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_align_center.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_align_center.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,16L7,16c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C7.45,15 7,15.45 7,16zM4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM4,13h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13zM7,8L7,8c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C7.45,7 7,7.45 7,8zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4z"/>
+ android:pathData="M7,16c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,15c-0.55,0 -1,0.45 -1,1zM4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,13h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM7,8c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,7c-0.55,0 -1,0.45 -1,1zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_align_justify.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_align_justify.xml
index 53202d7..5b8e97d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_align_justify.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_align_justify.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM4,17h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,16.55 3.45,17 4,17zM4,13h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13zM4,9h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,7 3,7.45 3,8l0,0C3,8.55 3.45,9 4,9zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4z"/>
+ android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,17h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,13h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,9h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_align_left.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_align_left.xml
index 5912e0c..58b804b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_align_left.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_align_left.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,15H4c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1l0,0C15,15.45 14.55,15 14,15zM14,7H4C3.45,7 3,7.45 3,8l0,0c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1l0,0C15,7.45 14.55,7 14,7zM4,13h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13zM4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4z"/>
+ android:pathData="M14,15L4,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM14,7L4,7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM4,13h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_align_right.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_align_right.xml
index 0a40aae..e3ef7f3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_align_right.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_align_right.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM10,17h10c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H10c-0.55,0 -1,0.45 -1,1l0,0C9,16.55 9.45,17 10,17zM4,13h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13zM10,9h10c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H10C9.45,7 9,7.45 9,8l0,0C9,8.55 9.45,9 10,9zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4z"/>
+ android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM10,17h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L10,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,13h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM10,9h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L10,7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_bold.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_bold.xml
index 4492efd..4abc63c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_bold.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_bold.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,6c0,-1.1 0.9,-2 2,-2h3.48c1.95,0 4.28,1.28 4.28,3.66c0,1.8 -1.18,2.67 -1.88,3.01v0.16c0.54,0.19 2.39,0.98 2.39,3.28c0,3.01 -2.95,3.89 -4.6,3.89H9c-1.1,0 -2,-0.9 -2,-2V6zM12.28,9.71c1.34,0 1.9,-0.9 1.9,-1.68c0,-0.9 -0.68,-1.66 -1.82,-1.66H9.64v3.34H12.28zM12.57,15.59c1.99,0 2.03,-1.59 2.03,-1.8c0,-0.23 -0.05,-1.82 -2.11,-1.82H9.64v3.62H12.57z"/>
+ android:pathData="M15.6,10.79c0.97,-0.67 1.65,-1.77 1.65,-2.79 0,-2.26 -1.75,-4 -4,-4L8,4c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h5.78c2.07,0 3.96,-1.69 3.97,-3.77 0.01,-1.53 -0.85,-2.84 -2.15,-3.44zM10,6.5h3c0.83,0 1.5,0.67 1.5,1.5s-0.67,1.5 -1.5,1.5h-3v-3zM13.5,15.5L10,15.5v-3h3.5c0.83,0 1.5,0.67 1.5,1.5s-0.67,1.5 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_clear.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_clear.xml
index 7e93ff1..8f8b64b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_clear.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_clear.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.2,10.37L14.21,8h4.29C19.33,8 20,7.33 20,6.5v0C20,5.67 19.33,5 18.5,5H7.83L13.2,10.37zM2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l7.3,7.3l-2.08,4.85C6.93,17.99 7.6,19 8.59,19h0c0.55,0 1.05,-0.33 1.27,-0.84l1.64,-3.84l7.57,7.57c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M18.5,8c0.83,0 1.5,-0.67 1.5,-1.5S19.33,5 18.5,5L6.39,5l3,3h1.83l-0.55,1.28 2.09,2.09L14.21,8h4.29zM17.44,18.88L4.12,5.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l6.26,6.26 -1.65,3.84c-0.39,0.92 0.28,1.93 1.27,1.93 0.55,0 1.05,-0.33 1.27,-0.84l1.21,-2.83 4.95,4.95c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.38 0.4,-1.01 0.01,-1.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_color_reset.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_color_reset.xml
index 0648063..3606ed7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_color_reset.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_color_reset.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,13.13c0,-2.17 -0.9,-4.14 -2.35,-5.57l0,0L12,2L8.38,5.56l10.87,10.87C19.73,15.42 20,14.31 20,13.13zM2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l3.5,3.5c-1,1.31 -1.6,2.94 -1.6,4.7C4,17.48 7.58,21 12,21c1.75,0 3.36,-0.56 4.68,-1.49l2.39,2.39c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M18,14c0,-3.09 -3.6,-7.88 -5.23,-9.87 -0.4,-0.49 -1.15,-0.49 -1.55,0 -0.46,0.57 -1.08,1.36 -1.73,2.27l8.44,8.44c0.04,-0.28 0.07,-0.56 0.07,-0.84zM19.29,19.01L6.12,5.84c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.61,2.61C6.55,11.33 6,12.79 6,14c0,3.31 2.69,6 6,6 1.52,0 2.9,-0.57 3.95,-1.5l1.92,1.92c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.38 0.4,-1.02 0.01,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_indent_decrease.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_indent_decrease.xml
index 94e8b4a..6d5599c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_indent_decrease.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_indent_decrease.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,17h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1l0,0C11,16.55 11.45,17 12,17zM3.35,12.35l2.79,2.79C6.46,15.46 7,15.24 7,14.79V9.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79C3.16,11.84 3.16,12.16 3.35,12.35zM4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4zM12,9h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1l0,0C11,8.55 11.45,9 12,9zM12,13h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1l0,0C11,12.55 11.45,13 12,13z"/>
+ android:pathData="M12,17h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3.35,12.35l2.79,2.79c0.32,0.32 0.86,0.1 0.86,-0.35L7,9.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.19 -0.2,0.51 -0.01,0.7zM4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1zM12,9h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM12,13h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_indent_increase.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_indent_increase.xml
index 116c9e7..36cfa36 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_indent_increase.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_indent_increase.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,20.55 3.45,21 4,21zM3,9.21v5.59c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.8C3.54,8.54 3,8.76 3,9.21zM12,17h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1l0,0C11,16.55 11.45,17 12,17zM3,4L3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4zM12,9h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1l0,0C11,8.55 11.45,9 12,9zM12,13h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1l0,0C11,12.55 11.45,13 12,13z"/>
+ android:pathData="M4,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,9.21v5.59c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.8c-0.31,-0.31 -0.85,-0.09 -0.85,0.36zM12,17h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1zM12,9h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM12,13h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_italic.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_italic.xml
index 122fa08..5bfd2df 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_italic.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_italic.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,5.5L9,5.5C9,6.33 9.67,7 10.5,7h2l-4,10h-2C5.67,17 5,17.67 5,18.5v0C5,19.33 5.67,20 6.5,20h7c0.83,0 1.5,-0.67 1.5,-1.5v0c0,-0.83 -0.67,-1.5 -1.5,-1.5h-2l4,-10h2C18.33,7 19,6.33 19,5.5v0C19,4.67 18.33,4 17.5,4h-7C9.67,4 9,4.67 9,5.5z"/>
+ android:pathData="M10,5.5c0,0.83 0.67,1.5 1.5,1.5h0.71l-3.42,8H7.5c-0.83,0 -1.5,0.67 -1.5,1.5S6.67,18 7.5,18h5c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5h-0.71l3.42,-8h1.29c0.83,0 1.5,-0.67 1.5,-1.5S17.33,4 16.5,4h-5c-0.83,0 -1.5,0.67 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_line_spacing.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_line_spacing.xml
index bfd1cc1..59e38044 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_line_spacing.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_line_spacing.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.88,19h8.24c0.49,0 0.88,-0.39 0.88,-0.88v-0.24c0,-0.49 -0.39,-0.88 -0.88,-0.88H13c-0.55,0 -1,0.45 -1,1v0.12C12,18.61 12.39,19 12.88,19zM12,12c0,0.55 0.45,1 1,1h8.12c0.49,0 0.88,-0.39 0.88,-0.88v-0.24c0,-0.49 -0.39,-0.88 -0.88,-0.88H13C12.45,11 12,11.45 12,12L12,12zM12,6L12,6c0,0.55 0.45,1 1,1h8.12C21.61,7 22,6.61 22,6.12V5.88C22,5.39 21.61,5 21.12,5H13C12.45,5 12,5.45 12,6zM9.15,7.15L6.62,4.62c-0.34,-0.34 -0.9,-0.34 -1.24,0L2.85,7.15C2.54,7.46 2.76,8 3.21,8H5v8H3.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.53,2.53c0.34,0.34 0.9,0.34 1.24,0l2.53,-2.53C9.46,16.54 9.24,16 8.79,16H7V8h1.79C9.24,8 9.46,7.46 9.15,7.15z"/>
+ android:pathData="M7.29,7c0.45,0 0.67,-0.54 0.35,-0.85l-2.29,-2.3c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.29,2.3c-0.31,0.31 -0.09,0.85 0.36,0.85L4,7v10L2.71,17c-0.45,0 -0.67,0.54 -0.35,0.85l2.29,2.29c0.2,0.2 0.51,0.2 0.71,0l2.29,-2.29c0.31,-0.31 0.09,-0.85 -0.36,-0.85L6,17L6,7h1.29zM11,7h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L11,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM21,17L11,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM21,11L11,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_list_bulleted.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_list_bulleted.xml
index fde65c0..aab3265 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_list_bulleted.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_list_bulleted.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,10.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5S4.83,10.5 4,10.5zM4,4.5C3.17,4.5 2.5,5.17 2.5,6S3.17,7.5 4,7.5S5.5,6.83 5.5,6S4.83,4.5 4,4.5zM4,16.5c-0.83,0 -1.5,0.68 -1.5,1.5s0.68,1.5 1.5,1.5s1.5,-0.68 1.5,-1.5S4.83,16.5 4,16.5zM8,19h12c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8c-0.55,0 -1,0.45 -1,1l0,0C7,18.55 7.45,19 8,19zM8,13h12c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8c-0.55,0 -1,0.45 -1,1l0,0C7,12.55 7.45,13 8,13zM7,6L7,6c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C7.45,5 7,5.45 7,6z"/>
+ android:pathData="M4,10.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM4,4.5c-0.83,0 -1.5,0.67 -1.5,1.5S3.17,7.5 4,7.5 5.5,6.83 5.5,6 4.83,4.5 4,4.5zM4,16.5c-0.83,0 -1.5,0.68 -1.5,1.5s0.68,1.5 1.5,1.5 1.5,-0.68 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM8,19h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM8,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM7,6c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered.xml
index a39ac7e..4ca3578 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,7h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8C7.45,5 7,5.45 7,6S7.45,7 8,7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,17H8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1S20.55,17 20,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,11H8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1S20.55,11 20,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4.5,16h-2C2.22,16 2,16.22 2,16.5l0,0C2,16.78 2.22,17 2.5,17H4v0.5H3.5C3.22,17.5 3,17.72 3,18l0,0c0,0.28 0.22,0.5 0.5,0.5H4V19H2.5C2.22,19 2,19.22 2,19.5l0,0C2,19.78 2.22,20 2.5,20h2C4.78,20 5,19.78 5,19.5v-3C5,16.22 4.78,16 4.5,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.5,5H3v2.5C3,7.78 3.22,8 3.5,8l0,0C3.78,8 4,7.78 4,7.5v-3C4,4.22 3.78,4 3.5,4h-1C2.22,4 2,4.22 2,4.5l0,0C2,4.78 2.22,5 2.5,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4.5,10h-2C2.22,10 2,10.22 2,10.5l0,0C2,10.78 2.22,11 2.5,11h1.3l-1.68,1.96C2.04,13.05 2,13.17 2,13.28v0.22C2,13.78 2.22,14 2.5,14h2C4.78,14 5,13.78 5,13.5l0,0C5,13.22 4.78,13 4.5,13H3.2l1.68,-1.96C4.96,10.95 5,10.83 5,10.72V10.5C5,10.22 4.78,10 4.5,10z"/>
+ android:pathData="M8,7h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM20,17L8,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM20,11L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM4.5,16h-2c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5L4,17v0.5h-0.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5L4,18.5v0.5L2.5,19c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5v-3c0,-0.28 -0.22,-0.5 -0.5,-0.5zM2.5,5L3,5v2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5v-3c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5zM4.5,10h-2c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h1.3l-1.68,1.96c-0.08,0.09 -0.12,0.21 -0.12,0.32v0.22c0,0.28 0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5L3.2,13l1.68,-1.96c0.08,-0.09 0.12,-0.21 0.12,-0.32v-0.22c0,-0.28 -0.22,-0.5 -0.5,-0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered_rtl.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered_rtl.xml
index 4a299c5..091bd25 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered_rtl.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_list_numbered_rtl.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.5,16h-2c-0.28,0 -0.5,0.22 -0.5,0.5l0,0c0,0.28 0.22,0.5 0.5,0.5H20v0.5h-0.5c-0.28,0 -0.5,0.22 -0.5,0.5l0,0c0,0.28 0.22,0.5 0.5,0.5H20V19h-1.5c-0.28,0 -0.5,0.22 -0.5,0.5l0,0c0,0.28 0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5v-3C21,16.22 20.78,16 20.5,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.5,5H19v2.5C19,7.78 19.22,8 19.5,8l0,0C19.78,8 20,7.78 20,7.5v-3C20,4.22 19.78,4 19.5,4h-1C18.22,4 18,4.22 18,4.5l0,0C18,4.78 18.22,5 18.5,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,10.72V10.5c0,-0.28 -0.22,-0.5 -0.5,-0.5h-2c-0.28,0 -0.5,0.22 -0.5,0.5l0,0c0,0.28 0.22,0.5 0.5,0.5h1.3l-1.68,1.96C18.04,13.05 18,13.17 18,13.28v0.22c0,0.28 0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5l0,0c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1.3l1.68,-1.96C20.96,10.95 21,10.83 21,10.72z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,5H3C2.45,5 2,5.45 2,6s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1S15.55,5 15,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,17H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1S15.55,17 15,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,11H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1S15.55,11 15,11z"/>
+ android:pathData="M20.5,16h-2c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5L20,17v0.5h-0.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h0.5v0.5h-1.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5v-3c0,-0.28 -0.22,-0.5 -0.5,-0.5zM18.5,5h0.5v2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5v-3c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5zM21,10.72v-0.22c0,-0.28 -0.22,-0.5 -0.5,-0.5h-2c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h1.3l-1.68,1.96c-0.08,0.09 -0.12,0.21 -0.12,0.32v0.22c0,0.28 0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5h-1.3l1.68,-1.96c0.08,-0.09 0.12,-0.21 0.12,-0.32zM15,5L3,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM15,17L3,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM15,11L3,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_paint.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_paint.xml
index 2b96dea..533274b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_paint.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_paint.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,4V3c0,-0.55 -0.45,-1 -1,-1H5C4.45,2 4,2.45 4,3v4c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1V6h1v4h-9c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-9h7c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1H18z"/>
+ android:pathData="M18,4V3c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1V6h1v4h-9c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-9h7c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_quote.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_quote.xml
index 53624b1..0e95e5e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_quote.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_quote.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.17,17L8.17,17c0.51,0 0.98,-0.29 1.2,-0.74l1.42,-2.84c0.14,-0.28 0.21,-0.58 0.21,-0.89V8c0,-1.1 -0.9,-2 -2,-2H5.34C4.6,6 4,6.6 4,7.34v4.32C4,12.4 4.6,13 5.34,13H8l-1.03,2.06C6.52,15.95 7.17,17 8.17,17zM17.17,17L17.17,17c0.51,0 0.98,-0.29 1.2,-0.74l1.42,-2.84c0.14,-0.28 0.21,-0.58 0.21,-0.89V7.34C20,6.6 19.4,6 18.66,6h-4.32C13.6,6 13,6.6 13,7.34v4.32C13,12.4 13.6,13 14.34,13H17l-1.03,2.06C15.52,15.95 16.17,17 17.17,17z"/>
+ android:pathData="M7.17,17c0.51,0 0.98,-0.29 1.2,-0.74l1.42,-2.84c0.14,-0.28 0.21,-0.58 0.21,-0.89L10,8c0,-0.55 -0.45,-1 -1,-1L5,7c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h2l-1.03,2.06c-0.45,0.89 0.2,1.94 1.2,1.94zM17.17,17c0.51,0 0.98,-0.29 1.2,-0.74l1.42,-2.84c0.14,-0.28 0.21,-0.58 0.21,-0.89L20,8c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h2l-1.03,2.06c-0.45,0.89 0.2,1.94 1.2,1.94z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_shapes.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_shapes.xml
index e99e2f2..1577268 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_shapes.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_shapes.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,7c0.55,0 1,-0.45 1,-1V2c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v1H7V2c0,-0.55 -0.45,-1 -1,-1H2C1.45,1 1,1.45 1,2v4c0,0.55 0.45,1 1,1h1v10H2c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-1h10v1c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-1V7H22zM3,3h2v2H3V3zM5,21H3v-2h2V21zM17,18v1H7v-1c0,-0.55 -0.45,-1 -1,-1H5V7h1c0.55,0 1,-0.45 1,-1V5h10v1c0,0.55 0.45,1 1,1h1v10h-1C17.45,17 17,17.45 17,18zM21,21h-2v-2h2V21zM19,5V3h2v2H19zM12,7c-0.48,0 -0.92,0.3 -1.09,0.75l-2.73,7.27C8.01,15.49 8.36,16 8.86,16h0c0.31,0 0.58,-0.19 0.68,-0.48l0.65,-1.82h3.63l0.64,1.82c0.1,0.29 0.38,0.48 0.68,0.48h0c0.51,0 0.86,-0.51 0.68,-0.98l-2.73,-7.27C12.92,7.3 12.49,7 12,7L12,7zM10.66,12.39l1.31,-3.72h0.08l1.31,3.72H10.66z"/>
+ android:pathData="M23,6L23,2c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v1L7,3L7,2c0,-0.55 -0.45,-1 -1,-1L2,1c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h1v10L2,17c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-1h10v1c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-1L21,7h1c0.55,0 1,-0.45 1,-1zM3,3h2v2L3,5L3,3zM5,21L3,21v-2h2v2zM17,19L7,19v-1c0,-0.55 -0.45,-1 -1,-1L5,17L5,7h1c0.55,0 1,-0.45 1,-1L7,5h10v1c0,0.55 0.45,1 1,1h1v10h-1c-0.55,0 -1,0.45 -1,1v1zM21,21h-2v-2h2v2zM19,5L19,3h2v2h-2zM12.94,7.65c-0.15,-0.39 -0.53,-0.65 -0.95,-0.65 -0.42,0 -0.8,0.26 -0.94,0.65l-2.77,7.33c-0.19,0.49 0.17,1.02 0.7,1.02 0.32,0 0.6,-0.2 0.71,-0.5l0.55,-1.5h3.49l0.56,1.51c0.11,0.29 0.39,0.49 0.71,0.49h0.01c0.53,0 0.89,-0.53 0.71,-1.02l-2.78,-7.33zM10.69,12.74L12,8.91l1.3,3.83h-2.61z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_size.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_size.xml
index 8263ae2..90e46a3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_size.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_size.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,5.5L9,5.5C9,6.33 9.67,7 10.5,7H14v11.5c0,0.83 0.67,1.5 1.5,1.5h0c0.83,0 1.5,-0.67 1.5,-1.5V7h3.5C21.33,7 22,6.33 22,5.5v0C22,4.67 21.33,4 20.5,4h-10C9.67,4 9,4.67 9,5.5zM3.5,12H5v6.5C5,19.33 5.67,20 6.5,20h0C7.33,20 8,19.33 8,18.5V12h1.5c0.83,0 1.5,-0.67 1.5,-1.5v0C11,9.67 10.33,9 9.5,9h-6C2.67,9 2,9.67 2,10.5v0C2,11.33 2.67,12 3.5,12z"/>
+ android:pathData="M9,5.5c0,0.83 0.67,1.5 1.5,1.5H14v10.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5V7h3.5c0.83,0 1.5,-0.67 1.5,-1.5S21.33,4 20.5,4h-10C9.67,4 9,4.67 9,5.5zM4.5,12H6v5.5c0,0.83 0.67,1.5 1.5,1.5S9,18.33 9,17.5V12h1.5c0.83,0 1.5,-0.67 1.5,-1.5S11.33,9 10.5,9h-6C3.67,9 3,9.67 3,10.5S3.67,12 4.5,12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_strikethrough.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_strikethrough.xml
index 21f68d8..c9bd399 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_strikethrough.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_strikethrough.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,20L12,20c1.1,0 2,-0.9 2,-2v-2h-4v2C10,19.1 10.9,20 12,20zM5,5.5L5,5.5C5,6.33 5.67,7 6.5,7H10v3h4V7h3.5C18.33,7 19,6.33 19,5.5l0,0C19,4.67 18.33,4 17.5,4h-11C5.67,4 5,4.67 5,5.5zM3,14h18c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1l0,0C2,13.55 2.45,14 3,14z"/>
+ android:pathData="M12,19c1.1,0 2,-0.9 2,-2v-1h-4v1c0,1.1 0.9,2 2,2zM5,5.5C5,6.33 5.67,7 6.5,7H10v3h4V7h3.5c0.83,0 1.5,-0.67 1.5,-1.5S18.33,4 17.5,4h-11C5.67,4 5,4.67 5,5.5zM4,14h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_l_to_r.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_l_to_r.xml
index 6ce941a..2b3269b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_l_to_r.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_l_to_r.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,10v4c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V4h2v10c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V4h1c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H9.17C7.08,2 5.22,3.53 5.02,5.61C4.79,7.99 6.66,10 9,10zM20.65,17.65l-2.79,-2.79c-0.32,-0.32 -0.86,-0.1 -0.86,0.35V17H4c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h13v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79C20.84,18.16 20.84,17.84 20.65,17.65z"/>
+ android:pathData="M9,10v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1L11,4h2v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1L15,4h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L9.17,2C7.08,2 5.22,3.53 5.02,5.61 4.79,7.99 6.66,10 9,10zM20.65,17.65l-2.79,-2.79c-0.32,-0.32 -0.86,-0.1 -0.86,0.35L17,17L6,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h11v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.19 0.2,-0.51 0.01,-0.7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_r_to_l.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_r_to_l.xml
index 409eff8..b70c772 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_r_to_l.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_textdirection_r_to_l.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,10v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4h2v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H9.17C7.08,2 5.22,3.53 5.02,5.61C4.79,7.99 6.66,10 9,10zM19.79,17h-13v-1.79c0,-0.45 -0.54,-0.67 -0.86,-0.35l-2.79,2.79c-0.19,0.19 -0.19,0.51 0.01,0.7l2.79,2.79c0.31,0.32 0.85,0.1 0.85,-0.35V19h13c0.55,0 1,-0.45 1,-1S20.34,17 19.79,17z"/>
+ android:pathData="M10,10v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1L12,4h2v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1L16,4h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-6.83C8.08,2 6.22,3.53 6.02,5.61 5.79,7.99 7.66,10 10,10zM8,17v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.36L8,19h11c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/format_underlined.xml b/compose/material/material/icons/generator/raw-icons/rounded/format_underlined.xml
index 1c6bf89..38af3d9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/format_underlined.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/format_underlined.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.79,16.95c3.03,-0.39 5.21,-3.11 5.21,-6.16V4.25C18,3.56 17.44,3 16.75,3l0,0c-0.69,0 -1.25,0.56 -1.25,1.25v6.65c0,1.67 -1.13,3.19 -2.77,3.52C10.48,14.89 8.5,13.17 8.5,11V4.25C8.5,3.56 7.94,3 7.25,3l0,0C6.56,3 6,3.56 6,4.25V11C6,14.57 9.13,17.42 12.79,16.95zM5,20L5,20c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H6C5.45,19 5,19.45 5,20z"/>
+ android:pathData="M12.79,16.95c3.03,-0.39 5.21,-3.11 5.21,-6.16V4.25C18,3.56 17.44,3 16.75,3s-1.25,0.56 -1.25,1.25v6.65c0,1.67 -1.13,3.19 -2.77,3.52 -2.25,0.47 -4.23,-1.25 -4.23,-3.42V4.25C8.5,3.56 7.94,3 7.25,3S6,3.56 6,4.25V11c0,3.57 3.13,6.42 6.79,5.95zM5,20c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/forum.xml b/compose/material/material/icons/generator/raw-icons/rounded/forum.xml
index aa4a202..e63e167 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/forum.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/forum.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-1v9H6v1c0,1.1 0.9,2 2,2h10l3.15,3.15c0.31,0.31 0.85,0.09 0.85,-0.35V8C22,6.9 21.1,6 20,6zM17,11V4c0,-1.1 -0.9,-2 -2,-2H4C2.9,2 2,2.9 2,4v11.79c0,0.45 0.54,0.67 0.85,0.35L6,13h9C16.1,13 17,12.1 17,11z"/>
+ android:pathData="M20,6h-1v8c0,0.55 -0.45,1 -1,1L6,15v1c0,1.1 0.9,2 2,2h10l4,4L22,8c0,-1.1 -0.9,-2 -2,-2zM17,11L17,4c0,-1.1 -0.9,-2 -2,-2L4,2c-1.1,0 -2,0.9 -2,2v13l4,-4h9c1.1,0 2,-0.9 2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/forward.xml b/compose/material/material/icons/generator/raw-icons/rounded/forward.xml
index cf5a256..5ed2775 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/forward.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/forward.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.29,10.29l-3.59,-3.59C16.08,6.08 15,6.52 15,7.41V10H8c-2.76,0 -5,2.24 -5,5v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-3c0,-1.65 1.35,-3 3,-3h7v2.59c0,0.89 1.08,1.34 1.71,0.71l3.59,-3.59C20.68,11.32 20.68,10.68 20.29,10.29z"/>
+ android:pathData="M12,8V6.41c0,-0.89 1.08,-1.34 1.71,-0.71l5.59,5.59c0.39,0.39 0.39,1.02 0,1.41l-5.59,5.59c-0.63,0.63 -1.71,0.19 -1.71,-0.7V16H5c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1h7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/forward_10.xml b/compose/material/material/icons/generator/raw-icons/rounded/forward_10.xml
index 1307d80..dcc3c45 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/forward_10.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/forward_10.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.25,16L10.25,16c-0.41,0 -0.75,-0.34 -0.75,-0.75V11.5H8.75C8.34,11.5 8,11.16 8,10.75v0C8,10.34 8.34,10 8.75,10H10c0.55,0 1,0.45 1,1v4.25C11,15.66 10.66,16 10.25,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,10h-2c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-4C16,10.45 15.55,10 15,10zM14.5,14.5h-1v-3h1V14.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,4V2.21c0,-0.45 0.54,-0.67 0.85,-0.35l2.79,2.79c0.2,0.2 0.2,0.51 0,0.71l-2.79,2.79C12.54,8.46 12,8.24 12,7.79V6c-3.89,0 -7.06,3.2 -7,7.1c0.05,3.71 3.18,6.84 6.9,6.9c3.62,0.05 6.62,-2.65 7.05,-6.14c0.06,-0.49 0.49,-0.86 0.98,-0.86h0c0.6,0 1.07,0.53 1,1.12c-0.56,4.52 -4.48,8 -9.19,7.87c-4.7,-0.13 -8.61,-4.05 -8.74,-8.74C2.86,8.17 6.94,4 12,4z"/>
+ android:pathData="M18.92,13c-0.5,0 -0.91,0.37 -0.98,0.86 -0.48,3.37 -3.77,5.84 -7.42,4.96 -2.25,-0.54 -3.91,-2.27 -4.39,-4.53C5.32,10.42 8.27,7 12,7v2.79c0,0.45 0.54,0.67 0.85,0.35l3.79,-3.79c0.2,-0.2 0.2,-0.51 0,-0.71l-3.79,-3.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L12,5c-4.94,0 -8.84,4.48 -7.84,9.6 0.6,3.11 2.9,5.5 5.99,6.19 4.83,1.08 9.15,-2.2 9.77,-6.67 0.09,-0.59 -0.4,-1.12 -1,-1.12zM10.9,16v-4.27h-0.09l-1.77,0.63v0.69l1.01,-0.31L10.05,16zM14.32,11.78c-0.18,-0.07 -0.37,-0.1 -0.59,-0.1s-0.41,0.03 -0.59,0.1 -0.33,0.18 -0.45,0.33 -0.23,0.34 -0.29,0.57 -0.1,0.5 -0.1,0.82v0.74c0,0.32 0.04,0.6 0.11,0.82s0.17,0.42 0.3,0.57 0.28,0.26 0.46,0.33 0.37,0.1 0.59,0.1 0.41,-0.03 0.59,-0.1 0.33,-0.18 0.45,-0.33 0.22,-0.34 0.29,-0.57 0.1,-0.5 0.1,-0.82v-0.74c0,-0.32 -0.04,-0.6 -0.11,-0.82s-0.17,-0.42 -0.3,-0.57 -0.29,-0.26 -0.46,-0.33zM14.33,14.35c0,0.19 -0.01,0.35 -0.04,0.48s-0.06,0.24 -0.11,0.32 -0.11,0.14 -0.19,0.17 -0.16,0.05 -0.25,0.05 -0.18,-0.02 -0.25,-0.05 -0.14,-0.09 -0.19,-0.17 -0.09,-0.19 -0.12,-0.32 -0.04,-0.29 -0.04,-0.48v-0.97c0,-0.19 0.01,-0.35 0.04,-0.48s0.06,-0.23 0.12,-0.31 0.11,-0.14 0.19,-0.17 0.16,-0.05 0.25,-0.05 0.18,0.02 0.25,0.05 0.14,0.09 0.19,0.17 0.09,0.18 0.12,0.31 0.04,0.29 0.04,0.48v0.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/forward_30.xml b/compose/material/material/icons/generator/raw-icons/rounded/forward_30.xml
index c75d49a..409ef88 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/forward_30.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/forward_30.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.93,13c-0.5,0 -0.92,0.36 -0.98,0.86c-0.43,3.49 -3.44,6.19 -7.05,6.14c-3.71,-0.05 -6.84,-3.18 -6.9,-6.9C4.94,9.2 8.11,6 12,6v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C12.54,1.54 12,1.76 12,2.21V4c-5.06,0 -9.14,4.17 -9,9.25c0.13,4.7 4.04,8.61 8.74,8.74c4.7,0.13 8.62,-3.35 9.19,-7.87C21,13.53 20.53,13 19.93,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.5,10c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1H13.5zM15,14.5h-1v-3h1V14.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8.25,14.5c-0.41,0 -0.75,0.34 -0.75,0.75C7.5,15.66 7.84,16 8.25,16h2.25c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1H8.25c-0.41,0 -0.75,0.34 -0.75,0.75c0,0.41 0.34,0.75 0.75,0.75H10v1H9c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.28 0.22,0.5 0.5,0.5h1v1H8.25z"/>
+ android:pathData="M18.92,13c-0.5,0 -0.91,0.37 -0.98,0.86 -0.48,3.37 -3.77,5.84 -7.42,4.96 -2.25,-0.54 -3.91,-2.27 -4.39,-4.53C5.32,10.42 8.27,7 12,7v2.79c0,0.45 0.54,0.67 0.85,0.35l3.79,-3.79c0.2,-0.2 0.2,-0.51 0,-0.71l-3.79,-3.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L12,5c-4.94,0 -8.84,4.48 -7.84,9.6 0.6,3.11 2.9,5.5 5.99,6.19 4.83,1.08 9.15,-2.2 9.77,-6.67 0.09,-0.59 -0.4,-1.12 -1,-1.12zM10.54,15.22c-0.06,0.05 -0.12,0.09 -0.2,0.12s-0.17,0.04 -0.27,0.04c-0.09,0 -0.17,-0.01 -0.25,-0.04s-0.14,-0.06 -0.2,-0.11 -0.1,-0.1 -0.13,-0.17 -0.05,-0.14 -0.05,-0.22h-0.85c0,0.21 0.04,0.39 0.12,0.55s0.19,0.28 0.33,0.38 0.29,0.18 0.46,0.23 0.35,0.07 0.53,0.07c0.21,0 0.41,-0.03 0.6,-0.08s0.34,-0.14 0.48,-0.24 0.24,-0.24 0.32,-0.39 0.12,-0.33 0.12,-0.53c0,-0.23 -0.06,-0.44 -0.18,-0.61s-0.3,-0.3 -0.54,-0.39c0.1,-0.05 0.2,-0.1 0.28,-0.17s0.15,-0.14 0.2,-0.22 0.1,-0.16 0.13,-0.25 0.04,-0.18 0.04,-0.27c0,-0.2 -0.04,-0.37 -0.11,-0.53s-0.17,-0.28 -0.3,-0.38 -0.28,-0.18 -0.46,-0.23 -0.37,-0.08 -0.59,-0.08c-0.19,0 -0.38,0.03 -0.54,0.08s-0.32,0.13 -0.44,0.23 -0.23,0.22 -0.3,0.37 -0.11,0.3 -0.11,0.48h0.85c0,-0.07 0.02,-0.14 0.05,-0.2s0.07,-0.11 0.12,-0.15 0.11,-0.07 0.18,-0.1 0.14,-0.03 0.22,-0.03c0.1,0 0.18,0.01 0.25,0.04s0.13,0.06 0.18,0.11 0.08,0.11 0.11,0.17 0.04,0.14 0.04,0.22c0,0.18 -0.05,0.32 -0.16,0.43s-0.26,0.16 -0.48,0.16h-0.43v0.66h0.45c0.11,0 0.2,0.01 0.29,0.04s0.16,0.06 0.22,0.11 0.11,0.12 0.14,0.2 0.05,0.18 0.05,0.29c0,0.09 -0.01,0.17 -0.04,0.24s-0.08,0.11 -0.13,0.17zM14.44,11.78c-0.18,-0.07 -0.37,-0.1 -0.59,-0.1s-0.41,0.03 -0.59,0.1 -0.33,0.18 -0.45,0.33 -0.23,0.34 -0.29,0.57 -0.1,0.5 -0.1,0.82v0.74c0,0.32 0.04,0.6 0.11,0.82s0.17,0.42 0.3,0.57 0.28,0.26 0.46,0.33 0.37,0.1 0.59,0.1 0.41,-0.03 0.59,-0.1 0.33,-0.18 0.45,-0.33 0.22,-0.34 0.29,-0.57 0.1,-0.5 0.1,-0.82v-0.74c0,-0.32 -0.04,-0.6 -0.11,-0.82s-0.17,-0.42 -0.3,-0.57 -0.28,-0.26 -0.46,-0.33zM14.45,14.35c0,0.19 -0.01,0.35 -0.04,0.48s-0.06,0.24 -0.11,0.32 -0.11,0.14 -0.19,0.17 -0.16,0.05 -0.25,0.05 -0.18,-0.02 -0.25,-0.05 -0.14,-0.09 -0.19,-0.17 -0.09,-0.19 -0.12,-0.32 -0.04,-0.29 -0.04,-0.48v-0.97c0,-0.19 0.01,-0.35 0.04,-0.48s0.06,-0.23 0.12,-0.31 0.11,-0.14 0.19,-0.17 0.16,-0.05 0.25,-0.05 0.18,0.02 0.25,0.05 0.14,0.09 0.19,0.17 0.09,0.18 0.12,0.31 0.04,0.29 0.04,0.48v0.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/forward_5.xml b/compose/material/material/icons/generator/raw-icons/rounded/forward_5.xml
index fe7b82a..6aaa552 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/forward_5.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/forward_5.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.93,13c-0.5,0 -0.92,0.36 -0.98,0.86c-0.43,3.49 -3.44,6.19 -7.05,6.14c-3.71,-0.05 -6.84,-3.18 -6.9,-6.9C4.94,9.2 8.11,6 12,6v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C12.54,1.54 12,1.76 12,2.21V4c-5.06,0 -9.14,4.17 -9,9.25c0.13,4.7 4.04,8.61 8.74,8.74c4.7,0.13 8.62,-3.35 9.19,-7.87C21,13.53 20.53,13 19.93,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.25,11.5c0.41,0 0.75,-0.34 0.75,-0.75c0,-0.41 -0.34,-0.75 -0.75,-0.75H10.5c-0.55,0 -1,0.45 -1,1v1.5c0,0.55 0.45,1 1,1h2v1h-2.25c-0.41,0 -0.75,0.34 -0.75,0.75c0,0.41 0.34,0.75 0.75,0.75H13c0.55,0 1,-0.45 1,-1v-1.5c0,-0.55 -0.45,-1 -1,-1h-2v-1H13.25z"/>
+ android:pathData="M18.87,13c-0.5,0 -0.91,0.37 -0.98,0.86 -0.48,3.37 -3.77,5.84 -7.42,4.96 -2.25,-0.54 -3.91,-2.27 -4.39,-4.53C5.27,10.42 8.22,7 11.95,7v2.79c0,0.45 0.54,0.67 0.85,0.35l3.79,-3.79c0.2,-0.2 0.2,-0.51 0,-0.71L12.8,1.85c-0.31,-0.31 -0.85,-0.09 -0.85,0.35L11.95,5c-4.94,0 -8.84,4.48 -7.84,9.6 0.6,3.11 2.9,5.5 5.99,6.19 4.83,1.08 9.15,-2.2 9.77,-6.67 0.09,-0.59 -0.4,-1.12 -1,-1.12zM12.43,15.15c-0.05,0.07 -0.11,0.13 -0.18,0.17s-0.17,0.06 -0.27,0.06c-0.17,0 -0.31,-0.05 -0.42,-0.15s-0.17,-0.24 -0.19,-0.41h-0.84c0.01,0.2 0.05,0.37 0.13,0.53s0.19,0.28 0.32,0.39 0.29,0.19 0.46,0.24 0.35,0.08 0.53,0.08c0.24,0 0.46,-0.04 0.64,-0.12s0.33,-0.18 0.45,-0.31 0.21,-0.28 0.27,-0.45 0.09,-0.35 0.09,-0.54c0,-0.22 -0.03,-0.43 -0.09,-0.6s-0.14,-0.33 -0.25,-0.45 -0.25,-0.22 -0.41,-0.28 -0.34,-0.1 -0.55,-0.1c-0.07,0 -0.14,0.01 -0.2,0.02s-0.13,0.02 -0.18,0.04 -0.1,0.03 -0.15,0.05 -0.08,0.04 -0.11,0.05l0.11,-0.92h1.7v-0.71L10.9,11.74l-0.25,2.17 0.67,0.17c0.03,-0.03 0.06,-0.06 0.1,-0.09s0.07,-0.05 0.12,-0.07 0.1,-0.04 0.15,-0.05 0.13,-0.02 0.2,-0.02c0.12,0 0.22,0.02 0.3,0.05s0.16,0.09 0.21,0.15 0.1,0.14 0.13,0.24 0.04,0.19 0.04,0.31 -0.01,0.22 -0.03,0.31 -0.06,0.17 -0.11,0.24z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/free_breakfast.xml b/compose/material/material/icons/generator/raw-icons/rounded/free_breakfast.xml
index 5d4447e..b4bb9e0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/free_breakfast.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/free_breakfast.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H6C4.9,3 4,3.9 4,5v8c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.11,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3zM20,8h-2V5h2V8zM5,19h14c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1l0,0C4,19.45 4.45,19 5,19z"/>
+ android:pathData="M20,3L6,3c-1.1,0 -2,0.9 -2,2v8c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.11,0 2,-0.9 2,-2L22,5c0,-1.1 -0.9,-2 -2,-2zM20,8h-2L18,5h2v3zM5,19h14c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,21c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/free_cancellation.xml b/compose/material/material/icons/generator/raw-icons/rounded/free_cancellation.xml
new file mode 100644
index 0000000..c5cd582
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/free_cancellation.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10.79,20H5V10h14v2.96c0,0.89 1.08,1.34 1.71,0.71l0,0c0.19,-0.19 0.29,-0.44 0.29,-0.71V6c0,-1.1 -0.9,-2 -2,-2h-1V3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1h0C6.45,2 6,2.45 6,3v1H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h5.79c0.89,0 1.34,-1.08 0.71,-1.71l0,0C11.31,20.11 11.06,20 10.79,20zM13.71,18.26c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0c0.39,0.39 0.39,1.02 0,1.41l-4.24,4.24c-0.39,0.39 -1.02,0.39 -1.41,0l-2.12,-2.12C13.32,19.28 13.32,18.65 13.71,18.26zM11.29,16.29c-0.39,0.39 -1.02,0.39 -1.41,0L9,15.41l-0.88,0.88c-0.39,0.39 -1.02,0.39 -1.41,0s-0.39,-1.02 0,-1.41L7.59,14l-0.88,-0.88c-0.39,-0.39 -0.39,-1.02 0,-1.41s1.02,-0.39 1.41,0L9,12.59l0.88,-0.88c0.39,-0.39 1.02,-0.39 1.41,0s0.39,1.02 0,1.41L10.41,14l0.88,0.88C11.68,15.27 11.68,15.9 11.29,16.29z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/front_hand.xml b/compose/material/material/icons/generator/raw-icons/rounded/front_hand.xml
new file mode 100644
index 0000000..593e0a6
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/front_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.5,14.5c0,0.28 -0.22,0.5 -0.5,0.5l0,0c-1.51,0 -2.77,1.12 -2.97,2.58C15,17.82 14.78,18 14.54,18c-0.3,0 -0.54,-0.27 -0.5,-0.57c0.26,-1.77 1.68,-3.17 3.46,-3.4l0,-10.78C17.5,2.56 16.94,2 16.25,2C15.56,2 15,2.56 15,3.25v7.25c0,0.28 -0.22,0.5 -0.5,0.5S14,10.78 14,10.5V1.25C14,0.56 13.44,0 12.75,0S11.5,0.56 11.5,1.25v9.25c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5V2.75c0,-0.69 -0.56,-1.25 -1.25,-1.25S8,2.06 8,2.75v8.75C8,11.78 7.78,12 7.5,12S7,11.78 7,11.5V5.75C7,5.06 6.44,4.5 5.75,4.5S4.5,5.06 4.5,5.75v10c0,4.56 3.69,8.25 8.25,8.25S21,20.31 21,15.75v-6.5C21,8.56 20.44,8 19.75,8S18.5,8.56 18.5,9.25V14.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fullscreen.xml b/compose/material/material/icons/generator/raw-icons/rounded/fullscreen.xml
index f58093e..65ba585 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fullscreen.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fullscreen.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,14L6,14c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H7v-2C7,14.45 6.55,14 6,14zM6,10L6,10c0.55,0 1,-0.45 1,-1V7h2c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H6C5.45,5 5,5.45 5,6v3C5,9.55 5.45,10 6,10zM17,17h-2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1V17zM14,6L14,6c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-3C14.45,5 14,5.45 14,6z"/>
+ android:pathData="M6,14c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L7,17v-2c0,-0.55 -0.45,-1 -1,-1zM6,10c0.55,0 1,-0.45 1,-1L7,7h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,5c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1zM17,17h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2zM14,6c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L19,6c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/fullscreen_exit.xml b/compose/material/material/icons/generator/raw-icons/rounded/fullscreen_exit.xml
index a505d5f..beaab64 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/fullscreen_exit.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/fullscreen_exit.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,16h2v2c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1l0,0C5,15.55 5.45,16 6,16zM8,8H6C5.45,8 5,8.45 5,9l0,0c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1l0,0C8.45,5 8,5.45 8,6V8zM15,19L15,19c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v3C14,18.55 14.45,19 15,19zM16,8V6c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H16z"/>
+ android:pathData="M6,16h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1L6,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM8,8L6,8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c0.55,0 1,-0.45 1,-1L10,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2zM15,19c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1zM16,8L16,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/functions.xml b/compose/material/material/icons/generator/raw-icons/rounded/functions.xml
index 7804e66..6874109 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/functions.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/functions.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.5,4H7.56C6.7,4 6,4.7 6,5.56l0,0C6,5.84 6.12,6.11 6.32,6.3L12.5,12l-6.18,5.7C6.12,17.89 6,18.16 6,18.44l0,0C6,19.3 6.7,20 7.56,20h8.94c0.83,0 1.5,-0.67 1.5,-1.5l0,0c0,-0.83 -0.67,-1.5 -1.5,-1.5H11l3.59,-3.59c0.78,-0.78 0.78,-2.05 0,-2.83L11,7h5.5C17.33,7 18,6.33 18,5.5l0,0C18,4.67 17.33,4 16.5,4z"/>
+ android:pathData="M16.5,4H7.56C6.7,4 6,4.7 6,5.56c0,0.28 0.12,0.55 0.32,0.74L12.5,12l-6.18,5.7c-0.2,0.19 -0.32,0.46 -0.32,0.74C6,19.3 6.7,20 7.56,20h8.94c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5H11l3.59,-3.59c0.78,-0.78 0.78,-2.05 0,-2.83L11,7h5.5c0.83,0 1.5,-0.67 1.5,-1.5S17.33,4 16.5,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/g_translate.xml b/compose/material/material/icons/generator/raw-icons/rounded/g_translate.xml
index 5bfc96c..ad112be 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/g_translate.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/g_translate.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-9.12L10,2H4C2.9,2 2,2.9 2,4v13c0,1.1 0.9,2 2,2h7l1,3h8c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM7.17,14.59c-2.25,0 -4.09,-1.83 -4.09,-4.09s1.83,-4.09 4.09,-4.09c1.04,0 1.99,0.37 2.74,1.07l0.07,0.06L8.75,8.72L8.69,8.67C8.4,8.4 7.91,8.08 7.17,8.08c-1.31,0 -2.38,1.09 -2.38,2.42s1.07,2.42 2.38,2.42c1.37,0 1.96,-0.87 2.12,-1.46H7.08V9.91h3.95l0.01,0.07c0.04,0.21 0.05,0.4 0.05,0.61C11.09,12.94 9.48,14.59 7.17,14.59zM13.2,12.88c0.33,0.6 0.74,1.18 1.19,1.7l-0.54,0.53L13.2,12.88zM13.97,12.12h-0.99l-0.31,-1.04h3.99c0,0 -0.34,1.31 -1.56,2.74C14.58,13.2 14.21,12.59 13.97,12.12zM21,20c0,0.55 -0.45,1 -1,1h-7l2,-2l-0.81,-2.77l0.92,-0.92L17.79,18l0.73,-0.73l-2.71,-2.68c0.9,-1.03 1.6,-2.25 1.92,-3.51H19v-1.04h-3.64V9h-1.04v1.04h-1.96L11.18,6H20c0.55,0 1,0.45 1,1V20z"/>
+ android:pathData="M20,5h-9.12L10,2L4,2c-1.1,0 -2,0.9 -2,2v13c0,1.1 0.9,2 2,2h7l1,3h8c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM7.17,14.59c-2.25,0 -4.09,-1.83 -4.09,-4.09s1.83,-4.09 4.09,-4.09c1.04,0 1.99,0.37 2.74,1.07l0.07,0.06 -1.23,1.18 -0.06,-0.05c-0.29,-0.27 -0.78,-0.59 -1.52,-0.59 -1.31,0 -2.38,1.09 -2.38,2.42s1.07,2.42 2.38,2.42c1.37,0 1.96,-0.87 2.12,-1.46L7.08,11.46L7.08,9.91h3.95l0.01,0.07c0.04,0.21 0.05,0.4 0.05,0.61 0,2.35 -1.61,4 -3.92,4zM13.2,12.88c0.33,0.6 0.74,1.18 1.19,1.7l-0.54,0.53 -0.65,-2.23zM13.97,12.12h-0.99l-0.31,-1.04h3.99s-0.34,1.31 -1.56,2.74c-0.52,-0.62 -0.89,-1.23 -1.13,-1.7zM21,20c0,0.55 -0.45,1 -1,1h-7l2,-2 -0.81,-2.77 0.92,-0.92L17.79,18l0.73,-0.73 -2.71,-2.68c0.9,-1.03 1.6,-2.25 1.92,-3.51L19,11.08v-1.04h-3.64L15.36,9h-1.04v1.04h-1.96L11.18,6L20,6c0.55,0 1,0.45 1,1v13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gamepad.xml b/compose/material/material/icons/generator/raw-icons/rounded/gamepad.xml
index e889221..b14b757 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gamepad.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gamepad.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,7.09V3c0,-0.55 -0.45,-1 -1,-1h-4C9.45,2 9,2.45 9,3v4.09c0,0.27 0.11,0.52 0.29,0.71l2,2c0.39,0.39 1.02,0.39 1.41,0l2,-2C14.89,7.61 15,7.35 15,7.09zM7.09,9H3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4.09c0.27,0 0.52,-0.11 0.71,-0.29l2,-2c0.39,-0.39 0.39,-1.02 0,-1.41l-2,-2C7.61,9.11 7.35,9 7.09,9zM9,16.91V21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4.09c0,-0.27 -0.11,-0.52 -0.29,-0.71l-2,-2c-0.39,-0.39 -1.02,-0.39 -1.41,0l-2,2C9.11,16.39 9,16.65 9,16.91zM16.21,9.29l-2,2c-0.39,0.39 -0.39,1.02 0,1.41l2,2c0.19,0.19 0.44,0.29 0.71,0.29H21c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-4.09C16.65,9 16.39,9.11 16.21,9.29z"/>
+ android:pathData="M15,7.29L15,3c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v4.29c0,0.13 0.05,0.26 0.15,0.35l2.5,2.5c0.2,0.2 0.51,0.2 0.71,0l2.5,-2.5c0.09,-0.09 0.14,-0.21 0.14,-0.35zM7.29,9L3,9c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4.29c0.13,0 0.26,-0.05 0.35,-0.15l2.5,-2.5c0.2,-0.2 0.2,-0.51 0,-0.71l-2.5,-2.5C7.55,9.05 7.43,9 7.29,9zM9,16.71L9,21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4.29c0,-0.13 -0.05,-0.26 -0.15,-0.35l-2.5,-2.5c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.5,2.5c-0.09,0.09 -0.14,0.21 -0.14,0.35zM16.35,9.15l-2.5,2.5c-0.2,0.2 -0.2,0.51 0,0.71l2.5,2.5c0.09,0.09 0.22,0.15 0.35,0.15L21,15.01c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-4.29c-0.14,-0.01 -0.26,0.04 -0.36,0.14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/games.xml b/compose/material/material/icons/generator/raw-icons/rounded/games.xml
index e889221..b14b757 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/games.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/games.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,7.09V3c0,-0.55 -0.45,-1 -1,-1h-4C9.45,2 9,2.45 9,3v4.09c0,0.27 0.11,0.52 0.29,0.71l2,2c0.39,0.39 1.02,0.39 1.41,0l2,-2C14.89,7.61 15,7.35 15,7.09zM7.09,9H3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4.09c0.27,0 0.52,-0.11 0.71,-0.29l2,-2c0.39,-0.39 0.39,-1.02 0,-1.41l-2,-2C7.61,9.11 7.35,9 7.09,9zM9,16.91V21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4.09c0,-0.27 -0.11,-0.52 -0.29,-0.71l-2,-2c-0.39,-0.39 -1.02,-0.39 -1.41,0l-2,2C9.11,16.39 9,16.65 9,16.91zM16.21,9.29l-2,2c-0.39,0.39 -0.39,1.02 0,1.41l2,2c0.19,0.19 0.44,0.29 0.71,0.29H21c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-4.09C16.65,9 16.39,9.11 16.21,9.29z"/>
+ android:pathData="M15,7.29L15,3c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v4.29c0,0.13 0.05,0.26 0.15,0.35l2.5,2.5c0.2,0.2 0.51,0.2 0.71,0l2.5,-2.5c0.09,-0.09 0.14,-0.21 0.14,-0.35zM7.29,9L3,9c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4.29c0.13,0 0.26,-0.05 0.35,-0.15l2.5,-2.5c0.2,-0.2 0.2,-0.51 0,-0.71l-2.5,-2.5C7.55,9.05 7.43,9 7.29,9zM9,16.71L9,21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4.29c0,-0.13 -0.05,-0.26 -0.15,-0.35l-2.5,-2.5c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.5,2.5c-0.09,0.09 -0.14,0.21 -0.14,0.35zM16.35,9.15l-2.5,2.5c-0.2,0.2 -0.2,0.51 0,0.71l2.5,2.5c0.09,0.09 0.22,0.15 0.35,0.15L21,15.01c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-4.29c-0.14,-0.01 -0.26,0.04 -0.36,0.14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gavel.xml b/compose/material/material/icons/generator/raw-icons/rounded/gavel.xml
index 53658d9..3ae8797 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gavel.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gavel.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,21h10c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v0C4,20.55 4.45,21 5,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.78,14.02L6.12,8.36L5.41,9.07c-0.78,0.78 -0.78,2.05 0,2.83l2.83,2.83c0.78,0.78 2.05,0.78 2.83,0L11.78,14.02z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.73,6.24L13.9,3.41c-0.78,-0.78 -2.05,-0.78 -2.83,0l-0.71,0.71l5.66,5.66l0.71,-0.71C17.51,8.29 17.51,7.02 16.73,6.24z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8.95,5.54L7.54,6.95l12.34,12.34c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L8.95,5.54z"/>
+ android:pathData="M2,21h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1L2,23c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM5.24,8.07l2.83,-2.83L20.8,17.97c0.78,0.78 0.78,2.05 0,2.83 -0.78,0.78 -2.05,0.78 -2.83,0L5.24,8.07zM13.73,2.41l2.83,2.83c0.78,0.78 0.78,2.05 0,2.83l-1.42,1.42 -5.65,-5.66 1.41,-1.41c0.78,-0.79 2.05,-0.79 2.83,-0.01zM3.83,9.48l5.66,5.66 -1.41,1.41c-0.78,0.78 -2.05,0.78 -2.83,0l-2.83,-2.83c-0.78,-0.78 -0.78,-2.05 0,-2.83l1.41,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/generating_tokens.xml b/compose/material/material/icons/generator/raw-icons/rounded/generating_tokens.xml
new file mode 100644
index 0000000..e9190cd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/generating_tokens.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8C17,7.58 13.42,4 9,4zM9,15.5c-0.55,0 -1,-0.45 -1,-1v-4H6.75C6.34,10.5 6,10.16 6,9.75S6.34,9 6.75,9h4.5C11.66,9 12,9.34 12,9.75s-0.34,0.75 -0.75,0.75H10v4C10,15.05 9.55,15.5 9,15.5zM20.25,3.75L22,4.54c0.39,0.18 0.39,0.73 0,0.91l-1.75,0.79L19.46,8c-0.18,0.39 -0.73,0.39 -0.91,0l-0.79,-1.75L16,5.46c-0.39,-0.18 -0.39,-0.73 0,-0.91l1.75,-0.79L18.54,2c0.18,-0.39 0.73,-0.39 0.91,0L20.25,3.75zM20.25,17.75L22,18.54c0.39,0.18 0.39,0.73 0,0.91l-1.75,0.79L19.46,22c-0.18,0.39 -0.73,0.39 -0.91,0l-0.79,-1.75L16,19.46c-0.39,-0.18 -0.39,-0.73 0,-0.91l1.75,-0.79L18.54,16c0.18,-0.39 0.73,-0.39 0.91,0L20.25,17.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gesture.xml b/compose/material/material/icons/generator/raw-icons/rounded/gesture.xml
index 94a84ce..16a630c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gesture.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gesture.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3.87,6.03C4.34,6.49 5.1,6.49 5.59,6.04C5.89,5.76 6.13,5.6 6.3,5.67c0.5,0.2 0,1.03 -0.3,1.52c-0.53,0.89 -5.23,6.65 -1.68,9.29c2.55,1.9 4.77,-0.96 5.86,-2.31c1.21,-1.49 2.83,-3.44 4.08,-3.44c1.63,0 1.65,1.01 1.76,1.79c-3.78,0.64 -5.38,3.67 -5.38,5.37c0,1.7 1.44,3.11 3.21,3.11c1.63,0 4.29,-1.35 4.69,-6.12h1.21c0.69,0 1.25,-0.56 1.25,-1.25v0c0,-0.69 -0.56,-1.25 -1.25,-1.25h-1.22c-0.15,-1.65 -1.09,-4.2 -4.03,-4.2c-2.25,0 -4.18,1.91 -4.94,2.84C6.88,14.4 6.35,14.58 6,14.58c-0.45,0 -0.72,-0.83 -0.36,-1.92c1.04,-3.24 3.31,-4.27 3.31,-6.8C8.95,3.69 7.31,3 6.44,3c-0.77,0 -1.6,0.34 -2.53,1.2C3.38,4.69 3.35,5.52 3.87,6.03L3.87,6.03zM13.88,18.55c-1.45,0 -0.69,-2.74 2.13,-3.48C15.71,17.76 14.58,18.55 13.88,18.55z"/>
+ android:pathData="M3.72,6.04c0.47,0.46 1.21,0.48 1.71,0.06 0.37,-0.32 0.69,-0.51 0.87,-0.43 0.5,0.2 0,1.03 -0.3,1.52 -0.25,0.42 -2.86,3.89 -2.86,6.31 0,1.28 0.48,2.34 1.34,2.98 0.75,0.56 1.74,0.73 2.64,0.46 1.07,-0.31 1.95,-1.4 3.06,-2.77 1.21,-1.49 2.83,-3.44 4.08,-3.44 1.63,0 1.65,1.01 1.76,1.79 -3.78,0.64 -5.38,3.67 -5.38,5.37 0,1.7 1.44,3.09 3.21,3.09 1.63,0 4.29,-1.33 4.69,-6.1h1.21c0.69,0 1.25,-0.56 1.25,-1.25s-0.56,-1.25 -1.25,-1.25h-1.22c-0.15,-1.65 -1.09,-4.2 -4.03,-4.2 -2.25,0 -4.18,1.91 -4.94,2.84 -0.58,0.73 -2.06,2.48 -2.29,2.72 -0.25,0.3 -0.68,0.84 -1.11,0.84 -0.45,0 -0.72,-0.83 -0.36,-1.92 0.35,-1.09 1.4,-2.86 1.85,-3.52 0.78,-1.14 1.3,-1.92 1.3,-3.28C8.95,3.69 7.31,3 6.44,3c-1.09,0 -2.04,0.63 -2.7,1.22 -0.53,0.48 -0.53,1.32 -0.02,1.82zM13.88,18.55c-0.31,0 -0.74,-0.26 -0.74,-0.72 0,-0.6 0.73,-2.2 2.87,-2.76 -0.3,2.69 -1.43,3.48 -2.13,3.48z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/get_app.xml b/compose/material/material/icons/generator/raw-icons/rounded/get_app.xml
index 876e1d0..dd79e4c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/get_app.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/get_app.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.59,9H15V4c0,-0.55 -0.45,-1 -1,-1h-4C9.45,3 9,3.45 9,4v5H7.41c-0.89,0 -1.34,1.08 -0.71,1.71l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59C17.92,10.08 17.48,9 16.59,9zM5,19c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6C5.45,18 5,18.45 5,19z"/>
+ android:pathData="M16.59,9H15V4c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v5H7.41c-0.89,0 -1.34,1.08 -0.71,1.71l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.63,-0.63 0.19,-1.71 -0.7,-1.71zM5,19c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gif.xml b/compose/material/material/icons/generator/raw-icons/rounded/gif.xml
index 4402530..c2b5340 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gif.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gif.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.25,9C12.66,9 13,9.34 13,9.75v4.5c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75v-4.5C11.5,9.34 11.84,9 12.25,9zM10,9.75C10,9.34 9.66,9 9.25,9H6c-0.6,0 -1,0.5 -1,1v4c0,0.5 0.4,1 1,1h3c0.6,0 1,-0.5 1,-1v-1.25C10,12.34 9.66,12 9.25,12S8.5,12.34 8.5,12.75v0.75h-2v-3h2.75C9.66,10.5 10,10.16 10,9.75zM19,9.75C19,9.34 18.66,9 18.25,9H15.5c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75S16,14.66 16,14.25V13h1.25c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75H16v-1h2.25C18.66,10.5 19,10.16 19,9.75z"/>
+ android:pathData="M12.25,9c0.41,0 0.75,0.34 0.75,0.75v4.5c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75v-4.5c0,-0.41 0.34,-0.75 0.75,-0.75zM10,9.75c0,-0.41 -0.34,-0.75 -0.75,-0.75L6,9c-0.6,0 -1,0.5 -1,1v4c0,0.5 0.4,1 1,1h3c0.6,0 1,-0.5 1,-1v-1.25c0,-0.41 -0.34,-0.75 -0.75,-0.75s-0.75,0.34 -0.75,0.75v0.75h-2v-3h2.75c0.41,0 0.75,-0.34 0.75,-0.75zM19,9.75c0,-0.41 -0.34,-0.75 -0.75,-0.75L15.5,9c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L16,13h1.25c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75L16,11.5v-1h2.25c0.41,0 0.75,-0.34 0.75,-0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gif_box.xml b/compose/material/material/icons/generator/raw-icons/rounded/gif_box.xml
new file mode 100644
index 0000000..0f09178
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gif_box.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM10.5,10.5c0,0.28 -0.22,0.5 -0.5,0.5H8.5v2h1v-0.5c0,-0.29 0.25,-0.53 0.55,-0.5c0.26,0.02 0.45,0.26 0.45,0.52V13c0,0.55 -0.45,1 -1,1h-1c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1H10C10.28,10 10.5,10.22 10.5,10.5zM12,10c0.28,0 0.5,0.22 0.5,0.5v3c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5v-3C11.5,10.22 11.72,10 12,10zM14,14c-0.28,0 -0.5,-0.22 -0.5,-0.5v-3c0,-0.28 0.22,-0.5 0.5,-0.5h2c0.28,0 0.5,0.22 0.5,0.5S16.28,11 16,11h-1.5v0.5h1c0.28,0 0.5,0.22 0.5,0.5s-0.22,0.5 -0.5,0.5h-1v1C14.5,13.78 14.28,14 14,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/golf_course.xml b/compose/material/material/icons/generator/raw-icons/rounded/golf_course.xml
index 6202274..a394827 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/golf_course.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/golf_course.xml
@@ -9,5 +9,5 @@
android:pathData="M19.5,19.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,18.03V8.98l4.22,-2.15c0.73,-0.37 0.73,-1.43 -0.01,-1.79L10.44,2.7C9.78,2.38 9,2.86 9,3.6V19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-0.73C5.21,18.62 4,19.26 4,20c0,1.1 2.69,2 6,2s6,-0.9 6,-2C16,19.01 13.84,18.19 11,18.03z"/>
+ android:pathData="M11,18.03V8.98l4.22,-2.15c0.73,-0.37 0.73,-1.43 -0.01,-1.79l-4.76,-2.33C9.78,2.38 9,2.86 9,3.6V19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-0.73c-1.79,0.35 -3,0.99 -3,1.73 0,1.1 2.69,2 6,2s6,-0.9 6,-2c0,-0.99 -2.16,-1.81 -5,-1.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gps_fixed.xml b/compose/material/material/icons/generator/raw-icons/rounded/gps_fixed.xml
index 821714e..b861b63 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gps_fixed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gps_fixed.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S14.21,8 12,8zM20.94,11C20.48,6.83 17.17,3.52 13,3.06V2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11H2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94H22c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H20.94zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7s7,3.13 7,7S15.87,19 12,19z"/>
+ android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11L2,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94L11,22c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L22,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gps_not_fixed.xml b/compose/material/material/icons/generator/raw-icons/rounded/gps_not_fixed.xml
index 7d5e2fa..75b73c8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gps_not_fixed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gps_not_fixed.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.94,11C20.48,6.83 17.17,3.52 13,3.06V2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11H2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94H22c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H20.94zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7s7,3.13 7,7S15.87,19 12,19z"/>
+ android:pathData="M20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94H22c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gps_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/gps_off.xml
index c8334d6..09a832e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gps_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gps_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.94,11C20.48,6.83 17.17,3.52 13,3.06V2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1.06C9.62,3.21 8.34,3.68 7.22,4.39l1.45,1.45C10,5.12 11.6,4.82 13.28,5.11c2.82,0.5 5.11,2.78 5.61,5.61c0.3,1.68 0,3.28 -0.73,4.61l1.45,1.45c0.71,-1.12 1.18,-2.4 1.33,-3.78H22c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H20.94zM2.1,4.93l2.29,2.29C3.68,8.34 3.21,9.62 3.06,11H2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-1.06c1.38,-0.15 2.66,-0.62 3.78,-1.33l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.71,3.91 1.71,4.54 2.1,4.93zM5.84,8.67l9.49,9.49C14.34,18.7 13.21,19 12,19c-3.87,0 -7,-3.13 -7,-7C5,10.79 5.3,9.66 5.84,8.67z"/>
+ android:pathData="M22,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.06c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1.06c-0.98,0.11 -1.91,0.38 -2.77,0.78l1.53,1.53C10.46,5.13 11.22,5 12,5c3.87,0 7,3.13 7,7 0,0.79 -0.13,1.54 -0.37,2.24l1.53,1.53c0.4,-0.86 0.67,-1.79 0.78,-2.77L22,13zM20.44,18.88L5.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L5.04,6.3C3.97,7.62 3.26,9.23 3.06,11L2,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94L11,22c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1.06c1.77,-0.2 3.38,-0.91 4.69,-1.98l1.33,1.33c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.39 0.4,-1.02 0.01,-1.41zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-1.61 0.55,-3.09 1.46,-4.27l9.81,9.81C15.09,18.45 13.61,19 12,19z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/grade.xml b/compose/material/material/icons/generator/raw-icons/rounded/grade.xml
index 33ae5d2..405ee01 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/grade.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/grade.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.43,10l-1.95,-6.42c-0.14,-0.47 -0.81,-0.47 -0.96,0L9.57,10H3.56c-0.49,0 -0.69,0.62 -0.29,0.91l4.91,3.51l-1.89,6.1c-0.14,0.46 0.39,0.84 0.78,0.55L12,17.31l4.93,3.75c0.39,0.29 0.92,-0.08 0.78,-0.55l-1.89,-6.1l4.91,-3.51c0.4,-0.28 0.2,-0.91 -0.29,-0.91H14.43z"/>
+ android:pathData="M12,17.27l5.17,3.12c0.38,0.23 0.85,-0.11 0.75,-0.54l-1.37,-5.88 4.56,-3.95c0.33,-0.29 0.16,-0.84 -0.29,-0.88l-6.01,-0.51 -2.35,-5.54c-0.17,-0.41 -0.75,-0.41 -0.92,0L9.19,8.63l-6.01,0.51c-0.44,0.04 -0.62,0.59 -0.28,0.88l4.56,3.95 -1.37,5.88c-0.1,0.43 0.37,0.77 0.75,0.54L12,17.27z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/gradient.xml b/compose/material/material/icons/generator/raw-icons/rounded/gradient.xml
index 7e48af2..3944cf0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/gradient.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/gradient.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,11h2v2h-2V11zM9,13h2v2H9V13zM13,13h2v2h-2V13zM15,11h2v2h-2V11zM7,11h2v2H7V11zM19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM9,19H7v-2h2V19zM13,19h-2v-2h2V19zM17,19h-2v-2h2V19zM19,13h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2H9v-2H7v2H5v-2h2v-2H5V5h14V13z"/>
+ android:pathData="M11,9h2v2h-2L11,9zM9,11h2v2L9,13v-2zM13,11h2v2h-2v-2zM15,9h2v2h-2L15,9zM7,9h2v2L7,11L7,9zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM9,18L7,18v-2h2v2zM13,18h-2v-2h2v2zM17,18h-2v-2h2v2zM19,11h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2L9,15v-2L7,13v2L5,15v-2h2v-2L5,11L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/grading.xml b/compose/material/material/icons/generator/raw-icons/rounded/grading.xml
index 3ba5b75..59c09d3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/grading.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/grading.xml
@@ -7,5 +7,20 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,7H20c0.55,0 1,0.45 1,1V8c0,0.55 -0.45,1 -1,1H4C3.45,9 3,8.55 3,8V8C3,7.45 3.45,7 4,7zM4,13H20c0.55,0 1,-0.45 1,-1V12c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1V12C3,12.55 3.45,13 4,13zM4,17H11c0.55,0 1,-0.45 1,-1V16c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1V16C3,16.55 3.45,17 4,17zM4,21H11c0.55,0 1,-0.45 1,-1V20c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1V20C3,20.55 3.45,21 4,21zM16.41,18.17l-0.71,-0.71c-0.39,-0.39 -1.02,-0.39 -1.41,0h0c-0.39,0.39 -0.39,1.02 0,1.41l1.42,1.43c0.39,0.39 1.02,0.39 1.41,0l3.18,-3.17c0.39,-0.39 0.39,-1.02 0,-1.41l-0.01,-0.01c-0.39,-0.39 -1.02,-0.39 -1.41,0L16.41,18.17zM3,4L3,4c0,0.56 0.45,1 1,1H20c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4z"/>
+ android:pathData="M5,7h14c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H5C4.45,9 4,8.55 4,8v0C4,7.45 4.45,7 5,7z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,13h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v0C4,12.55 4.45,13 5,13z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,17h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v0C4,16.55 4.45,17 5,17z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,21h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v0C4,20.55 4.45,21 5,21z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.41,18.17l-0.71,-0.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l1.42,1.42c0.39,0.39 1.02,0.39 1.41,0l3.17,-3.17c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L15.41,18.17z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4,4L4,4c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C4.45,3 4,3.45 4,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/grain.xml b/compose/material/material/icons/generator/raw-icons/rounded/grain.xml
index 46ffbb8..daf1370 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/grain.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/grain.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,12c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S11.1,12 10,12zM6,8c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S7.1,8 6,8zM6,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S7.1,16 6,16zM18,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S16.9,8 18,8zM14,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S15.1,16 14,16zM18,12c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S19.1,12 18,12zM14,8c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S15.1,8 14,8zM10,4C8.9,4 8,4.9 8,6s0.9,2 2,2s2,-0.9 2,-2S11.1,4 10,4z"/>
+ android:pathData="M10,12c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,8c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM14,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,12c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM14,8c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM10,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/graphic_eq.xml b/compose/material/material/icons/generator/raw-icons/rounded/graphic_eq.xml
index 8f1e039..f77efe1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/graphic_eq.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/graphic_eq.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,18c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1S7,6.45 7,7v10C7,17.55 7.45,18 8,18zM12,22c0.55,0 1,-0.45 1,-1V3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v18C11,21.55 11.45,22 12,22zM4,14c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2C3,13.55 3.45,14 4,14zM16,18c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v10C15,17.55 15.45,18 16,18zM19,11v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1S19,10.45 19,11z"/>
+ android:pathData="M8,18c0.55,0 1,-0.45 1,-1L9,7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v10c0,0.55 0.45,1 1,1zM12,22c0.55,0 1,-0.45 1,-1L13,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v18c0,0.55 0.45,1 1,1zM4,14c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2c0,0.55 0.45,1 1,1zM16,18c0.55,0 1,-0.45 1,-1L17,7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v10c0,0.55 0.45,1 1,1zM19,11v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/grid_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/grid_off.xml
index b2ab916..168a508 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/grid_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/grid_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4.83l2,2H8v1.17l2,2V4h4v4h-3.17l2,2H14v1.17l2,2V10h4v4h-3.17l2,2H20v1.17l2,2V4C22,2.9 21.1,2 20,2zM20,8h-4V4h4V8zM1.39,4.22L2,4.83V20c0,1.1 0.9,2 2,2h15.17l0.61,0.61c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1,3.2 1,3.83 1.39,4.22zM16,18.83L17.17,20H16V18.83zM10,12.83L11.17,14H10V12.83zM10,16h3.17L14,16.83V20h-4V16zM4,6.83L5.17,8H4V6.83zM4,10h3.17L8,10.83V14H4V10zM4,16h4v4H4V16z"/>
+ android:pathData="M8,4v0.89l2,2L10,4h4v4h-2.89l2,2L14,10v0.89l2,2L16,10h4v4h-2.89l2,2L20,16v0.89l2,2L22,4c0,-1.1 -0.9,-2 -2,-2L5.11,2l2,2L8,4zM16,4h3c0.55,0 1,0.45 1,1v3h-4L16,4zM22.16,21.88L2.12,1.84c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L2,4.55L2,20c0,1.1 0.9,2 2,2h15.45l1.3,1.3c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.03 0,-1.42zM10,12.55L11.45,14L10,14v-1.45zM4,6.55L5.45,8L4,8L4,6.55zM8,20L5,20c-0.55,0 -1,-0.45 -1,-1v-3h4v4zM8,14L4,14v-4h3.45l0.55,0.55L8,14zM14,20h-4v-4h3.45l0.55,0.55L14,20zM16,20v-1.45L17.45,20L16,20z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/grid_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/grid_on.xml
index 91ae8d8..542206c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/grid_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/grid_on.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM8,20H4v-4h4V20zM8,14H4v-4h4V14zM8,8H4V4h4V8zM14,20h-4v-4h4V20zM14,14h-4v-4h4V14zM14,8h-4V4h4V8zM20,20h-4v-4h4V20zM20,14h-4v-4h4V14zM20,8h-4V4h4V8z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM8,20L5,20c-0.55,0 -1,-0.45 -1,-1v-3h4v4zM8,14L4,14v-4h4v4zM8,8L4,8L4,5c0,-0.55 0.45,-1 1,-1h3v4zM14,20h-4v-4h4v4zM14,14h-4v-4h4v4zM14,8h-4L10,4h4v4zM19,20h-3v-4h4v3c0,0.55 -0.45,1 -1,1zM20,14h-4v-4h4v4zM20,8h-4L16,4h3c0.55,0 1,0.45 1,1v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/group.xml b/compose/material/material/icons/generator/raw-icons/rounded/group.xml
index 16bfc6b..4ccf41a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/group.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/group.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.43,0 -0.84,-0.09 -1.23,-0.21c-0.03,-0.01 -0.06,-0.02 -0.1,-0.03C14.5,10.73 15,9.42 15,8zM16.66,13.13C18.03,14.06 19,15.32 19,17v3h4v-3C23,14.82 19.42,13.53 16.66,13.13zM9,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4s-4,-1.79 -4,-4S6.79,4 9,4zM9,13c2.67,0 8,1.34 8,4v3H1v-3C1,14.34 6.33,13 9,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.67,13.13C18.04,14.06 19,15.32 19,17v3h4v-3C23,14.82 19.43,13.53 16.67,13.13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9,8m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4c-0.47,0 -0.91,0.1 -1.33,0.24C14.5,5.27 15,6.58 15,8s-0.5,2.73 -1.33,3.76C14.09,11.9 14.53,12 15,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9,13c-2.67,0 -8,1.34 -8,4v3h16v-3C17,14.34 11.67,13 9,13z"/>
+ android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5s-3,1.34 -3,3 1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,18c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-1.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 0.02,0.01 0.03,0.03 0.04,0.04 1.14,0.83 1.93,1.94 1.93,3.41L17,18c0,0.35 -0.07,0.69 -0.18,1L22,19c0.55,0 1,-0.45 1,-1v-1.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/group_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/group_off.xml
new file mode 100644
index 0000000..75730a0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/group_off.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.06,0 -0.12,0 -0.18,0l-0.77,-0.77C14.65,10.29 15,9.18 15,8zM7.24,4.41C7.77,4.15 8.37,4 9,4c2.21,0 4,1.79 4,4c0,0.63 -0.15,1.23 -0.41,1.76L7.24,4.41zM21.19,21.19c0.39,0.39 0.39,1.02 0,1.41s-1.02,0.39 -1.41,0l-2.99,-2.99C16.6,19.85 16.32,20 16,20H2c-0.55,0 -1,-0.45 -1,-1v-2c0,-2.66 5.33,-4 8,-4c0.37,0 0.8,0.03 1.25,0.08L9.17,12C9.11,12 9.06,12 9,12c-2.21,0 -4,-1.79 -4,-4c0,-0.06 0,-0.11 0,-0.17L1.39,4.22C1,3.83 1,3.2 1.39,2.81s1.02,-0.39 1.41,0L21.19,21.19zM18.89,16.07c-0.29,-1.22 -1.13,-2.19 -2.23,-2.94C19.42,13.53 23,14.82 23,17v2c0,0.32 -0.15,0.6 -0.38,0.79L18.89,16.07z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/group_remove.xml b/compose/material/material/icons/generator/raw-icons/rounded/group_remove.xml
new file mode 100644
index 0000000..33dcc78
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/group_remove.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18,10c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-4C18.45,11 18,10.55 18,10zM8,4C5.79,4 4,5.79 4,8s1.79,4 4,4s4,-1.79 4,-4S10.21,4 8,4zM8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13zM12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05zM16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/group_work.xml b/compose/material/material/icons/generator/raw-icons/rounded/group_work.xml
index 04212b0..c4eb7d4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/group_work.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/group_work.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM8,16c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C10,15.1 9.1,16 8,16zM12,10c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C14,9.1 13.1,10 12,10zM16,16c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C18,15.1 17.1,16 16,16z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM8,17.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5zM9.5,8c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5S9.5,9.38 9.5,8zM16,17.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hd.xml b/compose/material/material/icons/generator/raw-icons/rounded/hd.xml
index a756a1f..cdd672f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hd.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hd.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2,4.9 2,6v12c0,1.1 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM10.25,15L10.25,15c-0.41,0 -0.75,-0.34 -0.75,-0.75V13h-2v1.25C7.5,14.66 7.16,15 6.75,15l0,0C6.34,15 6,14.66 6,14.25v-4.5C6,9.34 6.34,9 6.75,9l0,0C7.16,9 7.5,9.34 7.5,9.75v1.75h2V9.75C9.5,9.34 9.84,9 10.25,9l0,0C10.66,9 11,9.34 11,9.75v4.5C11,14.66 10.66,15 10.25,15zM13.5,9H17c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1h-3.5c-0.28,0 -0.5,-0.22 -0.5,-0.5v-5C13,9.22 13.22,9 13.5,9zM14.5,13.5h2v-3h-2V13.5z"/>
+ android:pathData="M19,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM10.25,15c-0.41,0 -0.75,-0.34 -0.75,-0.75L9.5,13h-2v1.25c0,0.41 -0.34,0.75 -0.75,0.75S6,14.66 6,14.25v-4.5c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75v1.75h2L9.5,9.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75v4.5c0,0.41 -0.34,0.75 -0.75,0.75zM13.5,9L17,9c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1h-3.5c-0.28,0 -0.5,-0.22 -0.5,-0.5v-5c0,-0.28 0.22,-0.5 0.5,-0.5zM14.5,13.5h2v-3h-2v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hdr_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/hdr_off.xml
index 589a27c..66d5e9b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hdr_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hdr_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.49,21.9c0.39,-0.39 0.39,-1.02 0,-1.41l-6.21,-6.21L13,13l-2,-2L9.5,9.5L3.52,3.52c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.03 0,1.42l4.4,4.4V11h-2V9.75C4.5,9.34 4.16,9 3.75,9h0C3.34,9 3,9.34 3,9.75v4.5C3,14.66 3.34,15 3.75,15h0c0.41,0 0.75,-0.34 0.75,-0.75V12.5h2v1.75C6.5,14.66 6.84,15 7.25,15h0C7.66,15 8,14.66 8,14.25v-3.42l1.5,1.5v1.92c0,0.41 0.34,0.75 0.75,0.75h1.92l6.9,6.9C19.46,22.29 20.1,22.29 20.49,21.9L20.49,21.9zM14.5,10.5C14.5,9.7 13.8,9 13,9h-1.17l2.67,2.67V10.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,11.5v-1C21,9.67 20.33,9 19.5,9h-2.75C16.34,9 16,9.34 16,9.75v3.42l1.41,1.41c0.05,-0.1 0.09,-0.21 0.09,-0.33V13h1.1l0.72,1.59c0.11,0.25 0.36,0.41 0.63,0.41c0.5,0 0.83,-0.51 0.64,-0.96L20.1,12.9C20.6,12.6 21,12.1 21,11.5zM19.5,11.5h-2v-1h2V11.5z"/>
+ android:pathData="M17.5,14.25L17.5,13h1.1l0.72,1.59c0.11,0.25 0.36,0.41 0.63,0.41 0.5,0 0.83,-0.51 0.64,-0.96l-0.49,-1.14c0.5,-0.3 0.9,-0.8 0.9,-1.4v-1c0,-0.83 -0.67,-1.5 -1.5,-1.5L17,9c-0.55,0 -1,0.45 -1,1v3.9l1.04,1.04c0.27,-0.11 0.46,-0.38 0.46,-0.69zM17.5,10.5h2v1h-2v-1zM13,10.5v0.4l1.5,1.5v-1.9c0,-0.82 -0.68,-1.5 -1.5,-1.5h-1.9l1.5,1.5h0.4zM21.03,21.03l-18,-18c-0.29,-0.29 -0.76,-0.29 -1.05,0 -0.29,0.29 -0.29,0.76 0,1.05l4.98,4.98c-0.27,0.11 -0.46,0.38 -0.46,0.69L6.5,11h-2L4.5,9.75c0,-0.41 -0.34,-0.75 -0.75,-0.75S3,9.34 3,9.75v4.5c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L4.5,12.5h2v1.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L8,10.1l1.5,1.5v2.9c0,0.28 0.22,0.5 0.5,0.5h2.5c0.12,0 0.24,-0.01 0.36,-0.04l7.11,7.11c0.29,0.29 0.76,0.29 1.05,0 0.29,-0.28 0.29,-0.75 0.01,-1.04z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hdr_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/hdr_on.xml
index 9d4bcde..c85aa7c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hdr_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hdr_on.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.25,9C6.84,9 6.5,9.34 6.5,9.75V11h-2V9.75C4.5,9.34 4.16,9 3.75,9S3,9.34 3,9.75v4.5C3,14.66 3.34,15 3.75,15s0.75,-0.34 0.75,-0.75V12.5h2v1.75C6.5,14.66 6.84,15 7.25,15S8,14.66 8,14.25v-4.5C8,9.34 7.66,9 7.25,9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,11.5v-1C21,9.67 20.33,9 19.5,9H17c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75V13h1.1l0.72,1.59c0.11,0.25 0.36,0.41 0.63,0.41l0,0c0.5,0 0.83,-0.51 0.64,-0.96L20.1,12.9C20.6,12.6 21,12.1 21,11.5zM17.5,11.5v-1h2v1H17.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,9h-3C9.72,9 9.5,9.22 9.5,9.5v5c0,0.28 0.22,0.5 0.5,0.5h3c0.82,0 1.5,-0.68 1.5,-1.5v-3C14.5,9.68 13.82,9 13,9zM13,13.5h-2v-3h2V13.5z"/>
+ android:pathData="M7.25,9c-0.41,0 -0.75,0.34 -0.75,0.75L6.5,11h-2L4.5,9.75c0,-0.41 -0.34,-0.75 -0.75,-0.75S3,9.34 3,9.75v4.5c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L4.5,12.5h2v1.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75v-4.5C8,9.34 7.66,9 7.25,9zM21,11.5v-1c0,-0.83 -0.67,-1.5 -1.5,-1.5L17,9c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L17.5,13h1.1l0.72,1.59c0.11,0.25 0.36,0.41 0.63,0.41 0.5,0 0.83,-0.51 0.64,-0.96l-0.49,-1.14c0.5,-0.3 0.9,-0.8 0.9,-1.4zM17.5,11.5v-1h2v1h-2zM13,9h-3c-0.28,0 -0.5,0.22 -0.5,0.5v5c0,0.28 0.22,0.5 0.5,0.5h3c0.82,0 1.5,-0.68 1.5,-1.5v-3c0,-0.82 -0.68,-1.5 -1.5,-1.5zM13,13.5h-2v-3h2v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hdr_strong.xml b/compose/material/material/icons/generator/raw-icons/rounded/hdr_strong.xml
index 7b6ad0b..73e3297 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hdr_strong.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hdr_strong.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6s6,-2.69 6,-6S20.31,6 17,6zM5,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S7.21,8 5,8zM5,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S6.1,14 5,14z"/>
+ android:pathData="M17,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6zM5,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM5,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hdr_weak.xml b/compose/material/material/icons/generator/raw-icons/rounded/hdr_weak.xml
index ba24a380..0a0eb26 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hdr_weak.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hdr_weak.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S7.21,8 5,8zM17,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6s6,-2.69 6,-6S20.31,6 17,6zM17,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4s4,1.79 4,4S19.21,16 17,16z"/>
+ android:pathData="M5,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM17,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6zM17,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/headset.xml b/compose/material/material/icons/generator/raw-icons/rounded/headset.xml
index c84a05c..12967bc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/headset.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/headset.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,12v7c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2H5v-1c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v1h-2c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2v-7c0,-4.97 -4.03,-9 -9,-9S3,7.03 3,12z"/>
+ android:pathData="M11.4,1.02C6.62,1.33 3,5.52 3,10.31V17c0,1.66 1.34,3 3,3h1c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2H5v-1.71C5,6.45 7.96,3.11 11.79,3 15.76,2.89 19,6.06 19,10v2h-2c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h1c1.66,0 3,-1.34 3,-3v-7c0,-5.17 -4.36,-9.32 -9.6,-8.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/headset_mic.xml b/compose/material/material/icons/generator/raw-icons/rounded/headset_mic.xml
index cd5c3aa..e3fb18b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/headset_mic.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/headset_mic.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2c-4.97,0 -9,4.03 -9,9v7c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2H5v-1c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v1h-2c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h2v1h-6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c1.1,0 2,-0.9 2,-2V11C21,6.03 16.97,2 12,2z"/>
+ android:pathData="M11.4,1.02C6.62,1.33 3,5.52 3,10.31V17c0,1.66 1.34,3 3,3h1c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2H5v-1.71C5,6.45 7.96,3.11 11.79,3 15.76,2.89 19,6.06 19,10v2h-2c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h2v1h-6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h5c1.66,0 3,-1.34 3,-3V10c0,-5.17 -4.36,-9.32 -9.6,-8.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/healing.xml b/compose/material/material/icons/generator/raw-icons/rounded/healing.xml
index 0c0b06e..7e1fb8e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/healing.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/healing.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.68,12l3.73,-3.73c0.78,-0.78 0.78,-2.05 0,-2.83l-2.85,-2.85C18.17,2.2 17.66,2 17.15,2s-1.02,0.2 -1.41,0.59L12,6.32L8.27,2.59C7.87,2.2 7.36,2 6.85,2C6.34,2 5.83,2.2 5.44,2.59L2.59,5.44c-0.78,0.78 -0.78,2.05 0,2.83L6.32,12l-3.73,3.73c-0.78,0.78 -0.78,2.05 0,2.83l2.85,2.85C5.83,21.8 6.34,22 6.85,22c0.51,0 1.02,-0.2 1.41,-0.59L12,17.68l3.73,3.73c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l2.85,-2.85c0.78,-0.78 0.78,-2.05 0,-2.83L17.68,12zM12,9c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S11.45,9 12,9zM7.73,10.59L4,6.85L6.85,4l3.73,3.73L7.73,10.59zM10,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S10.55,13 10,13zM12,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,15 12,15zM13,12c0,-0.55 0.45,-1 1,-1s1,0.45 1,1s-0.45,1 -1,1S13,12.55 13,12zM17.15,20l-3.73,-3.73l2.85,-2.85L20,17.15L17.15,20z"/>
+ android:pathData="M17.73,12.02l3.98,-3.98c0.39,-0.39 0.39,-1.02 0,-1.41l-4.34,-4.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.98,3.98L8,2.29C7.8,2.1 7.55,2 7.29,2c-0.25,0 -0.51,0.1 -0.7,0.29L2.25,6.63c-0.39,0.39 -0.39,1.02 0,1.41l3.98,3.98L2.25,16c-0.39,0.39 -0.39,1.02 0,1.41l4.34,4.34c0.39,0.39 1.02,0.39 1.41,0l3.98,-3.98 3.98,3.98c0.2,0.2 0.45,0.29 0.71,0.29 0.26,0 0.51,-0.1 0.71,-0.29l4.34,-4.34c0.39,-0.39 0.39,-1.02 0,-1.41l-3.99,-3.98zM12,9c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM7.29,10.96L3.66,7.34l3.63,-3.63 3.62,3.62 -3.62,3.63zM10,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM12,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM14,11c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM16.66,20.34l-3.63,-3.62 3.63,-3.63 3.62,3.62 -3.62,3.63z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hearing.xml b/compose/material/material/icons/generator/raw-icons/rounded/hearing.xml
index a48d8ed..78c35b5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hearing.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hearing.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15c-0.71,-0.37 -1.21,-0.88 -1.71,-2.38c-0.51,-1.56 -1.47,-2.29 -2.39,-3c-0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5c2.56,0 4.63,1.85 4.95,4.31C19.01,8.71 19.36,9 19.77,9h0.34c0.5,0 0.89,-0.44 0.83,-0.94C20.49,4.59 17.61,2 14,2c-3.93,0 -7,3.07 -7,7c0,1.26 0.38,2.65 1.07,3.9c0.91,1.65 1.98,2.48 2.85,3.15c0.81,0.62 1.39,1.07 1.71,2.05c0.6,1.82 1.37,2.84 2.73,3.55C15.87,21.88 16.43,22 17,22c1.84,0 3.39,-1.24 3.86,-2.93C21,18.53 20.61,18 20.05,18H19.7c-0.38,0 -0.68,0.27 -0.81,0.63C18.63,19.42 17.88,20 17,20zM6.97,1.97L6.97,1.97c-0.43,-0.43 -1.12,-0.39 -1.5,0.07C3.93,3.94 3,6.36 3,9s0.93,5.06 2.47,6.95c0.38,0.46 1.07,0.5 1.49,0.08l0,0c0.36,-0.36 0.39,-0.93 0.07,-1.32C5.77,13.16 5,11.17 5,9s0.77,-4.16 2.04,-5.7C7.37,2.9 7.33,2.33 6.97,1.97zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5S15.38,6.5 14,6.5S11.5,7.62 11.5,9z"/>
+ android:pathData="M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15 -0.71,-0.37 -1.21,-0.88 -1.71,-2.38 -0.51,-1.56 -1.47,-2.29 -2.39,-3 -0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5 2.56,0 4.63,1.85 4.95,4.31 0.06,0.4 0.41,0.69 0.82,0.69h0.34c0.5,0 0.89,-0.44 0.83,-0.94C20.49,4.59 17.61,2 14,2c-3.93,0 -7,3.07 -7,7 0,1.26 0.38,2.65 1.07,3.9 0.91,1.65 1.98,2.48 2.85,3.15 0.81,0.62 1.39,1.07 1.71,2.05 0.6,1.82 1.37,2.84 2.73,3.55 0.51,0.23 1.07,0.35 1.64,0.35 1.84,0 3.39,-1.24 3.86,-2.93 0.14,-0.54 -0.25,-1.07 -0.81,-1.07h-0.35c-0.38,0 -0.68,0.27 -0.81,0.63 -0.26,0.79 -1.01,1.37 -1.89,1.37zM6.97,1.97c-0.43,-0.43 -1.12,-0.39 -1.5,0.07C3.93,3.94 3,6.36 3,9s0.93,5.06 2.47,6.95c0.38,0.46 1.07,0.5 1.49,0.08 0.36,-0.36 0.39,-0.93 0.07,-1.32C5.77,13.16 5,11.17 5,9s0.77,-4.16 2.04,-5.7c0.33,-0.4 0.29,-0.97 -0.07,-1.33zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5 -2.5,1.12 -2.5,2.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/height.xml b/compose/material/material/icons/generator/raw-icons/rounded/height.xml
index 6f9e916..a74ee101 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/height.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/height.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,6.99h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.78c-0.2,-0.19 -0.51,-0.19 -0.71,0L8.86,6.14c-0.32,0.31 -0.1,0.85 0.35,0.85H11v10.02H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.78c0.2,0.19 0.51,0.19 0.71,0l2.79,-2.78c0.32,-0.31 0.09,-0.85 -0.35,-0.85H13V6.99z"/>
+ android:pathData="M13,6.99h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.78c-0.2,-0.19 -0.51,-0.19 -0.71,0L8.86,6.14C8.54,6.45 8.76,6.99 9.21,6.99H11v10.02H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.78c0.2,0.19 0.51,0.19 0.71,0l2.79,-2.78c0.32,-0.31 0.09,-0.85 -0.35,-0.85H13V6.99z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/help.xml b/compose/material/material/icons/generator/raw-icons/rounded/help.xml
index a0b5fc9..aa0598d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/help.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/help.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM11.85,18c-0.7,0 -1.26,-0.56 -1.26,-1.26c0,-0.71 0.56,-1.25 1.26,-1.25c0.71,0 1.25,0.54 1.25,1.25C13.1,17.43 12.56,18 11.85,18zM14.86,10.6c-0.76,1.11 -1.48,1.46 -1.87,2.17c-0.09,0.17 -0.15,0.31 -0.19,0.59c-0.06,0.46 -0.43,0.82 -0.9,0.82h-0.04c-0.53,0 -0.95,-0.45 -0.9,-0.98c0.03,-0.33 0.11,-0.68 0.3,-1c0.49,-0.87 1.42,-1.39 1.96,-2.16c0.57,-0.81 0.25,-2.33 -1.37,-2.33c-0.74,0 -1.21,0.39 -1.51,0.85C10.12,8.9 9.66,9.02 9.27,8.86c-0.5,-0.21 -0.72,-0.83 -0.41,-1.29C9.47,6.66 10.49,6 11.83,6c1.48,0 2.49,0.67 3.01,1.52C15.28,8.24 15.54,9.59 14.86,10.6z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92c-0.5,0.51 -0.86,0.97 -1.04,1.69 -0.08,0.32 -0.13,0.68 -0.13,1.14h-2v-0.5c0,-0.46 0.08,-0.9 0.22,-1.31 0.2,-0.58 0.53,-1.1 0.95,-1.52l1.24,-1.26c0.46,-0.44 0.68,-1.1 0.55,-1.8 -0.13,-0.72 -0.69,-1.33 -1.39,-1.53 -1.11,-0.31 -2.14,0.32 -2.47,1.27 -0.12,0.37 -0.43,0.65 -0.82,0.65h-0.3C8.4,9 8,8.44 8.16,7.88c0.43,-1.47 1.68,-2.59 3.23,-2.83 1.52,-0.24 2.97,0.55 3.87,1.8 1.18,1.63 0.83,3.38 -0.19,4.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/high_quality.xml b/compose/material/material/icons/generator/raw-icons/rounded/high_quality.xml
index 3640f00..6b8275f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/high_quality.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/high_quality.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2,4.9 2,6v12c0,1.1 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM10.25,15L10.25,15c-0.41,0 -0.75,-0.34 -0.75,-0.75V13h-2v1.25C7.5,14.66 7.16,15 6.75,15l0,0C6.34,15 6,14.66 6,14.25v-4.5C6,9.34 6.34,9 6.75,9l0,0C7.16,9 7.5,9.34 7.5,9.75v1.75h2V9.75C9.5,9.34 9.84,9 10.25,9l0,0C10.66,9 11,9.34 11,9.75v4.5C11,14.66 10.66,15 10.25,15zM18,14c0,0.55 -0.45,1 -1,1h-0.75v0.75c0,0.41 -0.34,0.75 -0.75,0.75l0,0c-0.41,0 -0.75,-0.34 -0.75,-0.75V15H14c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1V14zM14.5,13.5h2v-3h-2V13.5z"/>
+ android:pathData="M19,4L5,4c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM10.25,15c-0.41,0 -0.75,-0.34 -0.75,-0.75L9.5,13h-2v1.25c0,0.41 -0.34,0.75 -0.75,0.75S6,14.66 6,14.25v-4.5c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75v1.75h2L9.5,9.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75v4.5c0,0.41 -0.34,0.75 -0.75,0.75zM18,14c0,0.55 -0.45,1 -1,1h-0.75v0.75c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75L14.75,15L14,15c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v4zM14.5,13.5h2v-3h-2v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/highlight.xml b/compose/material/material/icons/generator/raw-icons/rounded/highlight.xml
index 927627f..35b132b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/highlight.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/highlight.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.61,14.59L9.02,17v3c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2v-3l2.41,-2.41c0.38,-0.38 0.59,-0.88 0.59,-1.41V10c0,-0.55 -0.45,-1 -1,-1h-10c-0.55,0 -1,0.45 -1,1v3.17C6.02,13.7 6.23,14.21 6.61,14.59zM12.02,2L12.02,2c0.56,0 1,0.45 1,1V4c0,0.55 -0.45,1 -1,1h-0.01c-0.55,0 -1,-0.45 -1,-1V3C11.02,2.45 11.47,2 12.02,2zM4.2,5.18L4.2,5.18c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l0,0c-0.39,0.39 -1.02,0.39 -1.41,0L4.2,6.58C3.82,6.2 3.82,5.56 4.2,5.18zM17.68,5.88l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71c-0.39,0.39 -1.02,0.39 -1.41,0l0,0C17.29,6.91 17.29,6.27 17.68,5.88z"/>
+ android:pathData="M6.29,14.29L9,17v4c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4l2.71,-2.71c0.19,-0.19 0.29,-0.44 0.29,-0.71L18,10c0,-0.55 -0.45,-1 -1,-1L7,9c-0.55,0 -1,0.45 -1,1v3.59c0,0.26 0.11,0.52 0.29,0.7zM12,2c0.55,0 1,0.45 1,1v1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,3c0,-0.55 0.45,-1 1,-1zM4.21,5.17c0.39,-0.39 1.02,-0.39 1.42,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41 -0.39,0.39 -1.02,0.39 -1.41,0l-0.72,-0.71c-0.39,-0.39 -0.39,-1.02 0,-1.41zM17.67,5.88l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/highlight_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/highlight_alt.xml
index 0a47f70..54ed30e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/highlight_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/highlight_alt.xml
@@ -6,38 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,21v-2H3C3,20.1 3.9,21 5,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,15h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,3h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,3h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,3v2h2C21,3.9 20.1,3 19,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,7h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,7h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,19h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,3h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,11h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,5h2V3C3.9,3 3,3.9 3,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.71,15.29l2.59,-2.59c0.63,-0.63 0.18,-1.71 -0.71,-1.71H12c-0.55,0 -1,0.45 -1,1v6.59c0,0.89 1.08,1.34 1.71,0.71l2.59,-2.59l3.59,3.59c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L16.71,15.29z"/>
+ android:pathData="M17,5h-2V3h2V5zM19,9h2V7h-2V9zM19,13h2v-2h-2V13zM11,21h2v-2h-2V21zM7,5h2V3H7V5zM3,17h2v-2H3V17zM5,21v-2H3C3,20.1 3.9,21 5,21zM19,3v2h2C21,3.9 20.1,3 19,3zM11,5h2V3h-2V5zM3,9h2V7H3V9zM7,21h2v-2H7V21zM3,13h2v-2H3V13zM3,5h2V3C3.9,3 3,3.9 3,5zM18.71,17.29l1.44,-1.44c0.32,-0.32 0.09,-0.85 -0.35,-0.85H16c-0.55,0 -1,0.45 -1,1v3.79c0,0.45 0.54,0.67 0.85,0.35l1.44,-1.44l2,2c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L18.71,17.29z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/highlight_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/highlight_off.xml
index a672d5c..ca3baac 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/highlight_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/highlight_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.47,2 2,6.47 2,12c0,5.53 4.47,10 10,10s10,-4.47 10,-10C22,6.47 17.53,2 12,2zM16.29,14.89c0.39,0.39 0.39,1.02 0,1.41c-0.39,0.39 -1.02,0.39 -1.41,0L12,13.41l-2.89,2.89c-0.39,0.39 -1.02,0.39 -1.41,0c-0.39,-0.39 -0.39,-1.02 0,-1.41L10.59,12L7.71,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41c0.39,-0.39 1.02,-0.39 1.41,0L12,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0c0.39,0.39 0.39,1.02 0,1.41L13.41,12L16.29,14.89z"/>
+ android:pathData="M13.89,8.7L12,10.59 10.11,8.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 8.7,13.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l1.89,1.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l1.89,-1.89c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.38 -1.03,-0.38 -1.41,0zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/history.xml b/compose/material/material/icons/generator/raw-icons/rounded/history.xml
index 0896387..e1905a6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/history.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/history.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8v4c0,0.27 0.11,0.52 0.29,0.71l2.79,2.79c0.39,0.39 1.02,0.39 1.41,0v0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.5,-2.5V8c0,-0.55 -0.45,-1 -1,-1h0C12.45,7 12,7.45 12,8zM13.26,3C8.17,2.86 4,6.94 4,12H2.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.8,-2.79C8.46,12.54 8.24,12 7.79,12H6c0,-3.89 3.2,-7.06 7.1,-7c3.71,0.05 6.84,3.18 6.9,6.9c0.06,3.91 -3.1,7.1 -7,7.1c-1.59,0 -3.05,-0.53 -4.23,-1.43c-0.4,-0.3 -0.96,-0.27 -1.31,0.09l0,0c-0.43,0.43 -0.39,1.14 0.09,1.5C9.06,20.31 10.95,21 13,21c5.06,0 9.14,-4.17 9,-9.25C21.87,7.05 17.95,3.13 13.26,3z"/>
+ android:pathData="M13.26,3C8.17,2.86 4,6.95 4,12L2.21,12c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.8c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.8c0.31,-0.31 0.09,-0.85 -0.36,-0.85L6,12c0,-3.9 3.18,-7.05 7.1,-7 3.72,0.05 6.85,3.18 6.9,6.9 0.05,3.91 -3.1,7.1 -7,7.1 -1.61,0 -3.1,-0.55 -4.28,-1.48 -0.4,-0.31 -0.96,-0.28 -1.32,0.08 -0.42,0.42 -0.39,1.13 0.08,1.49C9,20.29 10.91,21 13,21c5.05,0 9.14,-4.17 9,-9.26 -0.13,-4.69 -4.05,-8.61 -8.74,-8.74zM12.75,8c-0.41,0 -0.75,0.34 -0.75,0.75v3.68c0,0.35 0.19,0.68 0.49,0.86l3.12,1.85c0.36,0.21 0.82,0.09 1.03,-0.26 0.21,-0.36 0.09,-0.82 -0.26,-1.03l-2.88,-1.71v-3.4c0,-0.4 -0.34,-0.74 -0.75,-0.74z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/history_edu.xml b/compose/material/material/icons/generator/raw-icons/rounded/history_edu.xml
index a5aba29..9645ac6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/history_edu.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/history_edu.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,5v0.38c-0.83,-0.33 -1.72,-0.5 -2.61,-0.5c-1.42,0 -2.84,0.43 -4.05,1.29C1.83,6.53 1.77,7.26 2.21,7.7l2.57,2.57h1.11v1.11c0.86,0.86 1.98,1.31 3.11,1.36V15H7c-0.55,0 -1,0.45 -1,1v2c0,1.1 0.9,2 2,2h10c1.66,0 3,-1.34 3,-3V5c0,-0.55 -0.45,-1 -1,-1H10C9.45,4 9,4.45 9,5zM7.89,10.41V8.26H5.61L4.57,7.22C5.14,7 5.76,6.88 6.39,6.88c1.34,0 2.59,0.52 3.54,1.46l1.41,1.41l-0.2,0.2c-0.51,0.51 -1.19,0.8 -1.92,0.8C8.75,10.75 8.29,10.63 7.89,10.41zM19,17c0,0.61 -0.55,1.09 -1.17,0.99C17.34,17.9 17,17.44 17,16.94L17,16c0,-0.55 -0.45,-1 -1,-1h-5v-2.59c0.57,-0.23 1.1,-0.57 1.56,-1.03l0.2,-0.2l2.54,2.53C15.49,13.9 15.74,14 16,14h0c0.55,0 1,-0.45 1,-1v0c0,-0.27 -0.11,-0.52 -0.29,-0.71L11,6.62V6h8V17z"/>
+ android:pathData="M9,5v0.38c-0.83,-0.33 -1.72,-0.5 -2.61,-0.5c-1.42,0 -2.84,0.43 -4.05,1.29C1.83,6.53 1.77,7.26 2.21,7.7l2.57,2.57h1.11v1.11c0.86,0.86 1.98,1.31 3.11,1.36V15H7c-0.55,0 -1,0.45 -1,1v2c0,1.1 0.9,2 2,2h10c1.66,0 3,-1.34 3,-3V5c0,-0.55 -0.45,-1 -1,-1H10C9.45,4 9,4.45 9,5zM7.89,10.41V8.26H5.61L4.57,7.22C5.14,7 5.76,6.88 6.39,6.88c1.34,0 2.59,0.52 3.54,1.46l1.41,1.41l-0.2,0.2c-0.51,0.51 -1.19,0.8 -1.92,0.8C8.75,10.75 8.29,10.63 7.89,10.41zM19,17c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-1c0,-0.55 -0.45,-1 -1,-1h-5v-2.59c0.57,-0.23 1.1,-0.57 1.56,-1.03l0.2,-0.2L15.59,14H17v-1.41l-6,-5.97V6h8V17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/home.xml b/compose/material/material/icons/generator/raw-icons/rounded/home.xml
index ab0b39b..2a8afa8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/home.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/home.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.8,3.9l-6,4.5C4.3,8.78 4,9.37 4,10v9c0,1.1 0.9,2 2,2h4v-7h4v7h4c1.1,0 2,-0.9 2,-2v-9c0,-0.63 -0.3,-1.22 -0.8,-1.6l-6,-4.5C12.49,3.37 11.51,3.37 10.8,3.9z"/>
+ android:pathData="M10,19v-5h4v5c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-7h1.7c0.46,0 0.68,-0.57 0.33,-0.87L12.67,3.6c-0.38,-0.34 -0.96,-0.34 -1.34,0l-8.36,7.53c-0.34,0.3 -0.13,0.87 0.33,0.87H5v7c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/home_work.xml b/compose/material/material/icons/generator/raw-icons/rounded/home_work.xml
index 438a3a0..99793b8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/home_work.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/home_work.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.16,10.4l-5,-3.57c-0.7,-0.5 -1.63,-0.5 -2.32,0l-5,3.57C1.31,10.78 1,11.38 1,12.03V20c0,0.55 0.45,1 1,1h4v-6h4v6h4c0.55,0 1,-0.45 1,-1v-7.97C15,11.38 14.69,10.78 14.16,10.4z"/>
+ android:pathData="M20,3h-8c-0.55,0 -1,0.45 -1,1v1.61c0,0 0,0 0.01,0.01l5,4.5C16.64,10.68 17,11.5 17,12.35V13h2v2h-2v2h2v2h-2v2h3c0.55,0 1,-0.45 1,-1V4C21,3.45 20.55,3 20,3zM15,7h-2V5h2V7zM19,11h-2V9h2V11zM19,7h-2V5h2V7z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M21.03,3h-9.06C10.88,3 10,3.88 10,4.97l0.09,0.09c0.08,0.05 0.16,0.09 0.24,0.14l5,3.57c0.76,0.54 1.3,1.34 1.54,2.23H19v2h-2v2h2v2h-2v3v1h4.03c1.09,0 1.97,-0.88 1.97,-1.97V4.97C23,3.88 22.12,3 21.03,3zM19,9h-2V7h2V9z"/>
+ android:pathData="M15,20v-7.65c0,-0.28 -0.12,-0.55 -0.33,-0.74l-5,-4.5C9.48,6.93 9.24,6.85 9,6.85c-0.24,0 -0.48,0.09 -0.67,0.26l-5,4.5C3.12,11.79 3,12.06 3,12.35V20c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-4h4v4c0,0.55 0.45,1 1,1h2C14.55,21 15,20.55 15,20z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/horizontal_split.xml b/compose/material/material/icons/generator/raw-icons/rounded/horizontal_split.xml
index 5515f0b..5259e4b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/horizontal_split.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/horizontal_split.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,19h16c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v4C3,18.55 3.45,19 4,19zM4,11h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,11 4,11zM3,6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6z"/>
+ android:pathData="M4,19h16c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1L4,13c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM4,11h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hot_tub.xml b/compose/material/material/icons/generator/raw-icons/rounded/hot_tub.xml
index 1b8f6fb..262d525 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hot_tub.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hot_tub.xml
@@ -9,11 +9,5 @@
android:pathData="M7,6m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M21,12h-9.85c-0.31,-0.22 -0.59,-0.46 -0.82,-0.72l-1.4,-1.55C8.74,9.52 8.5,9.35 8.24,9.23C7.95,9.09 7.62,9 7.28,9H7.25C6.01,9 5,10.01 5,11.25V12H3c-0.55,0 -1,0.45 -1,1v7c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-7C22,12.45 21.55,12 21,12zM7,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V19zM11,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V19zM15,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V19zM19,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.06,10c0.5,0 0.93,-0.39 0.94,-0.89c0.04,-1.4 -0.58,-2.48 -1.35,-3.25c-0.65,-0.72 -0.8,-1.27 -0.77,-1.91C13.9,3.43 13.47,3 12.94,3l0,0c-0.5,0 -0.93,0.4 -0.94,0.9c-0.03,1.29 0.5,2.43 1.35,3.25c0.61,0.59 0.78,1.27 0.78,1.89C14.12,9.56 14.53,10 15.06,10L15.06,10z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.06,10c0.5,0 0.93,-0.39 0.94,-0.89c0.04,-1.4 -0.58,-2.48 -1.35,-3.25c-0.65,-0.72 -0.8,-1.27 -0.77,-1.91C17.9,3.43 17.47,3 16.94,3l0,0c-0.5,0 -0.93,0.4 -0.94,0.9c-0.03,1.29 0.5,2.43 1.35,3.25c0.61,0.59 0.78,1.27 0.78,1.89C18.12,9.56 18.53,10 19.06,10L19.06,10z"/>
+ android:pathData="M21,12h-9.85c-0.31,-0.22 -0.59,-0.46 -0.82,-0.72l-1.4,-1.55c-0.19,-0.21 -0.43,-0.38 -0.69,-0.5 -0.29,-0.14 -0.62,-0.23 -0.96,-0.23h-0.03C6.01,9 5,10.01 5,11.25L5,12L3,12c-0.55,0 -1,0.45 -1,1v7c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-7c0,-0.55 -0.45,-1 -1,-1zM7,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4zM11,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4zM15,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4zM19,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4zM15.06,10c0.5,0 0.93,-0.39 0.94,-0.89 0.04,-1.4 -0.58,-2.48 -1.35,-3.25 -0.65,-0.72 -0.8,-1.27 -0.77,-1.91 0.02,-0.52 -0.41,-0.95 -0.94,-0.95 -0.5,0 -0.93,0.4 -0.94,0.9 -0.03,1.29 0.5,2.43 1.35,3.25 0.61,0.59 0.78,1.27 0.78,1.89 -0.01,0.52 0.4,0.96 0.93,0.96zM19.06,10c0.5,0 0.93,-0.39 0.94,-0.89 0.04,-1.4 -0.58,-2.48 -1.35,-3.25 -0.65,-0.72 -0.8,-1.27 -0.77,-1.91 0.02,-0.52 -0.41,-0.95 -0.94,-0.95 -0.5,0 -0.93,0.4 -0.94,0.9 -0.03,1.29 0.5,2.43 1.35,3.25 0.61,0.59 0.78,1.27 0.78,1.89 -0.01,0.52 0.4,0.96 0.93,0.96z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hotel.xml b/compose/material/material/icons/generator/raw-icons/rounded/hotel.xml
index 49ff962..cda81ef 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hotel.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hotel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,14c1.66,0 3,-1.34 3,-3S8.66,8 7,8s-3,1.34 -3,3S5.34,14 7,14zM19,7h-6c-1.1,0 -2,0.9 -2,2v6H3V6c0,-0.55 -0.45,-1 -1,-1l0,0C1.45,5 1,5.45 1,6v13c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-2h18v2c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-8C23,8.79 21.21,7 19,7z"/>
+ android:pathData="M7,13c1.66,0 3,-1.34 3,-3S8.66,7 7,7s-3,1.34 -3,3 1.34,3 3,3zM19,7h-6c-1.1,0 -2,0.9 -2,2v5L3,14L3,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v13c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h18v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-8c0,-2.21 -1.79,-4 -4,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hotel_class.xml b/compose/material/material/icons/generator/raw-icons/rounded/hotel_class.xml
new file mode 100644
index 0000000..37b683e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hotel_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.58,10H2.56c-0.49,0 -0.69,0.62 -0.29,0.91l4.91,3.51l-1.89,6.1c-0.14,0.46 0.39,0.84 0.78,0.55L11,17.31l4.93,3.75c0.39,0.29 0.92,-0.08 0.78,-0.55l-1.89,-6.1l4.91,-3.51c0.4,-0.28 0.2,-0.91 -0.29,-0.91h-6.02l-1.95,-6.42c-0.14,-0.47 -0.81,-0.47 -0.96,0L8.58,10zM20.9,20.51l-1.4,-4.52l2.91,-2.08c0.4,-0.28 0.2,-0.91 -0.29,-0.91h-1.88l-3.08,2.2l1.46,4.72l1.5,1.14C20.51,21.35 21.04,20.97 20.9,20.51zM17,8l-1.34,-4.42c-0.14,-0.47 -0.81,-0.47 -0.96,0l-0.57,1.87L14.91,8H17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_bottom.xml b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_bottom.xml
index 13d1cec..e8d21b8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_bottom.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_bottom.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7V4h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C4.45,2 4,2.45 4,3v0c0,0.55 0.45,1 1,1h1v3c0,2.09 1.07,3.93 2.69,5C7.07,13.07 6,14.91 6,17v3H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1v-3c0,-2.09 -1.07,-3.93 -2.69,-5C16.93,10.93 18,9.09 18,7zM16,7c0,2.21 -1.79,4 -4,4c-2.21,0 -4,-1.79 -4,-4V4h8V7z"/>
+ android:pathData="M16,22c1.1,0 2,-0.9 2,-2l-0.01,-3.18c0,-0.53 -0.21,-1.03 -0.58,-1.41L14,12l3.41,-3.43c0.37,-0.37 0.58,-0.88 0.58,-1.41L18,4c0,-1.1 -0.9,-2 -2,-2H8C6.9,2 6,2.9 6,4v3.16C6,7.69 6.21,8.2 6.58,8.58L10,12l-3.41,3.4C6.21,15.78 6,16.29 6,16.82V20c0,1.1 0.9,2 2,2H16zM8,7.09V5c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v2.09c0,0.27 -0.11,0.52 -0.29,0.71L12,11.5L8.29,7.79C8.11,7.61 8,7.35 8,7.09z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_empty.xml b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_empty.xml
index 00f647b..c61c2da 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_empty.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_empty.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7V4h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C4.45,2 4,2.45 4,3v0c0,0.55 0.45,1 1,1h1v3c0,2.09 1.07,3.93 2.69,5C7.07,13.07 6,14.91 6,17v3H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1v-3c0,-2.09 -1.07,-3.93 -2.69,-5C16.93,10.93 18,9.09 18,7zM16,17v3H8v-3c0,-2.21 1.79,-4 4,-4C14.21,13 16,14.79 16,17zM16,7c0,2.21 -1.79,4 -4,4c-2.21,0 -4,-1.79 -4,-4V4h8V7z"/>
+ android:pathData="M8,2c-1.1,0 -2,0.9 -2,2v3.17c0,0.53 0.21,1.04 0.59,1.42L10,12l-3.42,3.42c-0.37,0.38 -0.58,0.89 -0.58,1.42L6,20c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-3.16c0,-0.53 -0.21,-1.04 -0.58,-1.41L14,12l3.41,-3.4c0.38,-0.38 0.59,-0.89 0.59,-1.42L18,4c0,-1.1 -0.9,-2 -2,-2L8,2zM16,16.5L16,19c0,0.55 -0.45,1 -1,1L9,20c-0.55,0 -1,-0.45 -1,-1v-2.5l4,-4 4,4zM12,11.5l-4,-4L8,5c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v2.5l-4,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_full.xml b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_full.xml
index d8146a9..97d32f5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_full.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_full.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7V4h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C4.45,2 4,2.45 4,3v0c0,0.55 0.45,1 1,1h1v3c0,2.09 1.07,3.93 2.69,5C7.07,13.07 6,14.91 6,17v3H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1v-3c0,-2.09 -1.07,-3.93 -2.69,-5C16.93,10.93 18,9.09 18,7z"/>
+ android:pathData="M6,4v3.17c0,0.53 0.21,1.04 0.59,1.42L10,12l-3.42,3.42c-0.37,0.38 -0.58,0.89 -0.58,1.42V20c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-3.16c0,-0.53 -0.21,-1.04 -0.58,-1.41L14,12l3.41,-3.4c0.38,-0.38 0.59,-0.89 0.59,-1.42V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_top.xml b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_top.xml
index 5be68bb..17f1e7f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/hourglass_top.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hourglass_top.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7V4h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C4.45,2 4,2.45 4,3v0c0,0.55 0.45,1 1,1h1v3c0,2.09 1.07,3.93 2.69,5C7.07,13.07 6,14.91 6,17v3H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1v-3c0,-2.09 -1.07,-3.93 -2.69,-5C16.93,10.93 18,9.09 18,7zM16,17v3H8v-3c0,-2.21 1.79,-4 4,-4C14.21,13 16,14.79 16,17z"/>
+ android:pathData="M8,2C6.9,2 6,2.9 6,4l0.01,3.18c0,0.53 0.21,1.03 0.58,1.41L10,12l-3.41,3.43c-0.37,0.37 -0.58,0.88 -0.58,1.41L6,20c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-3.16c0,-0.53 -0.21,-1.04 -0.58,-1.41L14,12l3.41,-3.4C17.79,8.22 18,7.71 18,7.18V4c0,-1.1 -0.9,-2 -2,-2H8zM16,16.91V19c0,0.55 -0.45,1 -1,1H9c-0.55,0 -1,-0.45 -1,-1v-2.09c0,-0.27 0.11,-0.52 0.29,-0.71L12,12.5l3.71,3.71C15.89,16.39 16,16.65 16,16.91z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/house.xml b/compose/material/material/icons/generator/raw-icons/rounded/house.xml
index 0ba69db..92f58da 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/house.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/house.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,9.3V5c0,-0.55 -0.45,-1 -1,-1h-1c-0.55,0 -1,0.45 -1,1v1.6l-3.33,-3c-0.38,-0.34 -0.96,-0.34 -1.34,0l-8.36,7.53C2.63,11.43 2.84,12 3.3,12H5v7c0,0.55 0.45,1 1,1h4v-5c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1v5h4c0.55,0 1,-0.45 1,-1v-7h1.7c0.46,0 0.68,-0.57 0.33,-0.87L19,9.3zM10,10c0,-1.1 0.9,-2 2,-2s2,0.9 2,2H10z"/>
+ android:pathData="M19,9.3V5c0,-0.55 -0.45,-1 -1,-1h-1c-0.55,0 -1,0.45 -1,1v1.6l-3.33,-3c-0.38,-0.34 -0.96,-0.34 -1.34,0l-8.36,7.53C2.63,11.43 2.84,12 3.3,12H5v7c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-5h4v5c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-7h1.7c0.46,0 0.68,-0.57 0.33,-0.87L19,9.3zM10,10c0,-1.1 0.9,-2 2,-2s2,0.9 2,2H10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/how_to_reg.xml b/compose/material/material/icons/generator/raw-icons/rounded/how_to_reg.xml
index adfbee6..6b8726a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/how_to_reg.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/how_to_reg.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S6,5.79 6,8C6,10.21 7.79,12 10,12zM10.62,15.56l2.25,-2.25C11.97,13.12 11.02,13 10,13c-2.53,0 -4.71,0.7 -6.39,1.56C2.61,15.07 2,16.1 2,17.22L2,19c0,0.55 0.45,1 1,1h9.23l-1.62,-1.62C9.84,17.6 9.84,16.34 10.62,15.56zM19.88,13.24l-4.35,4.35l-1.32,-1.32c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l2.03,2.03c0.39,0.39 1.02,0.39 1.41,0l5.06,-5.06c0.39,-0.39 0.39,-1.02 0,-1.41v0C20.9,12.85 20.27,12.85 19.88,13.24z"/>
+ android:pathData="M12,20l-0.86,-0.86c-1.18,-1.18 -1.17,-3.1 0.02,-4.26l0.84,-0.82c-0.39,-0.04 -0.68,-0.06 -1,-0.06 -2.67,0 -8,1.34 -8,4v2h9zM11,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.18,19.78c-0.39,0.39 -1.03,0.39 -1.42,0l-2.07,-2.09c-0.38,-0.39 -0.38,-1.01 0,-1.39l0.01,-0.01c0.39,-0.39 1.02,-0.39 1.4,0l1.37,1.37 4.43,-4.46c0.39,-0.39 1.02,-0.39 1.41,0l0.01,0.01c0.38,0.39 0.38,1.01 0,1.39l-5.14,5.18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/http.xml b/compose/material/material/icons/generator/raw-icons/rounded/http.xml
index 7184eca..a22ad86 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/http.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/http.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.5,11h-2V9.75C2.5,9.34 2.16,9 1.75,9S1,9.34 1,9.75v4.5C1,14.66 1.34,15 1.75,15s0.75,-0.34 0.75,-0.75V12.5h2v1.75C4.5,14.66 4.84,15 5.25,15S6,14.66 6,14.25v-4.5C6,9.34 5.66,9 5.25,9S4.5,9.34 4.5,9.75V11zM7.75,10.5H8.5v3.75C8.5,14.66 8.84,15 9.25,15S10,14.66 10,14.25V10.5h0.75c0.41,0 0.75,-0.34 0.75,-0.75S11.16,9 10.75,9h-3C7.34,9 7,9.34 7,9.75S7.34,10.5 7.75,10.5zM13.25,10.5H14v3.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75V10.5h0.75c0.41,0 0.75,-0.34 0.75,-0.75S16.66,9 16.25,9h-3c-0.41,0 -0.75,0.34 -0.75,0.75S12.84,10.5 13.25,10.5zM21.5,9H19c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75V13h2c0.83,0 1.5,-0.68 1.5,-1.5v-1C23,9.68 22.33,9 21.5,9zM21.5,11.5h-2v-1h2V11.5z"/>
+ android:pathData="M4.5,11h-2L2.5,9.75c0,-0.41 -0.34,-0.75 -0.75,-0.75S1,9.34 1,9.75v4.5c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L2.5,12.5h2v1.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75v-4.5C6,9.34 5.66,9 5.25,9s-0.75,0.34 -0.75,0.75L4.5,11zM7.75,10.5h0.75v3.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L10,10.5h0.75c0.41,0 0.75,-0.34 0.75,-0.75S11.16,9 10.75,9h-3c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75zM13.25,10.5L14,10.5v3.75c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L15.5,10.5h0.75c0.41,0 0.75,-0.34 0.75,-0.75S16.66,9 16.25,9h-3c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75zM21.5,9L19,9c-0.55,0 -1,0.45 -1,1v4.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L19.5,13h2c0.83,0 1.5,-0.68 1.5,-1.5v-1c0,-0.82 -0.67,-1.5 -1.5,-1.5zM21.5,11.5h-2v-1h2v1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/hub.xml b/compose/material/material/icons/generator/raw-icons/rounded/hub.xml
new file mode 100644
index 0000000..fedb1a7
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/hub.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.4,18.2C8.78,18.7 9,19.32 9,20c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3s1.34,-3 3,-3c0.44,0 0.85,0.09 1.23,0.26l1.41,-1.77c-0.92,-1.03 -1.29,-2.39 -1.09,-3.69l-2.03,-0.68C4.98,11.95 4.06,12.5 3,12.5c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3c0,0.07 0,0.14 -0.01,0.21l2.03,0.68c0.64,-1.21 1.82,-2.09 3.22,-2.32l0,-2.16C9.96,5.57 9,4.4 9,3c0,-1.66 1.34,-3 3,-3s3,1.34 3,3c0,1.4 -0.96,2.57 -2.25,2.91v2.16c1.4,0.23 2.58,1.11 3.22,2.32l2.03,-0.68C18,9.64 18,9.57 18,9.5c0,-1.66 1.34,-3 3,-3s3,1.34 3,3s-1.34,3 -3,3c-1.06,0 -1.98,-0.55 -2.52,-1.37l-2.03,0.68c0.2,1.29 -0.16,2.65 -1.09,3.69l1.41,1.77C17.15,17.09 17.56,17 18,17c1.66,0 3,1.34 3,3s-1.34,3 -3,3s-3,-1.34 -3,-3c0,-0.68 0.22,-1.3 0.6,-1.8l-1.41,-1.77c-1.35,0.75 -3.01,0.76 -4.37,0L8.4,18.2z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/image.xml b/compose/material/material/icons/generator/raw-icons/rounded/image.xml
index 6e55f90..08f6184 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/image.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/image.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM6.6,16.2l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,16l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67c0.25,0.33 0.01,0.8 -0.4,0.8H7C6.59,17 6.35,16.53 6.6,16.2z"/>
+ android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.9,13.98l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8H6.02c-0.42,0 -0.65,-0.48 -0.39,-0.81L8.12,14c0.19,-0.26 0.57,-0.27 0.78,-0.02z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/image_aspect_ratio.xml b/compose/material/material/icons/generator/raw-icons/rounded/image_aspect_ratio.xml
index c6044f1..2838118 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/image_aspect_ratio.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/image_aspect_ratio.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,10h-2v2h2V10zM16,14h-2v2h2V14zM8,10H6v2h2V10zM12,10h-2v2h2V10zM20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,18H4V6h16V18z"/>
+ android:pathData="M16,10h-2v2h2v-2zM16,14h-2v2h2v-2zM8,10L6,10v2h2v-2zM12,10h-2v2h2v-2zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19,18L5,18c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/image_search.xml b/compose/material/material/icons/generator/raw-icons/rounded/image_search.xml
index 7c25654..d1b056e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/image_search.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/image_search.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,19H5V5h5V3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-3.33l-2,-2V19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,17h10c0.41,0 0.65,-0.47 0.4,-0.8l-2.75,-3.67c-0.2,-0.27 -0.6,-0.27 -0.8,0L11.25,16L9.4,13.53c-0.2,-0.27 -0.6,-0.27 -0.8,0l-2,2.67C6.35,16.53 6.59,17 7,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.88,8.89c0.48,-0.77 0.75,-1.67 0.69,-2.66c-0.13,-2.15 -1.84,-3.97 -3.97,-4.2c-2.72,-0.3 -5.02,1.81 -5.02,4.47c0,2.49 2.01,4.5 4.49,4.5c0.88,0 1.7,-0.26 2.39,-0.7l2.41,2.41c0.39,0.39 1.03,0.39 1.42,0l0,0c0.39,-0.39 0.39,-1.03 0,-1.42L19.88,8.89zM16.08,9c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C18.58,7.88 17.46,9 16.08,9z"/>
+ android:pathData="M18,15v4c0,0.55 -0.45,1 -1,1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 0.45,-1 1,-1h3.02c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-5c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM15.5,18L6.52,18c-0.42,0 -0.65,-0.48 -0.39,-0.81l1.74,-2.23c0.2,-0.25 0.58,-0.26 0.78,-0.01l1.56,1.88 2.35,-3.02c0.2,-0.26 0.6,-0.26 0.79,0.01l2.55,3.39c0.25,0.32 0.01,0.79 -0.4,0.79zM19.3,8.89c0.48,-0.77 0.75,-1.67 0.69,-2.66 -0.13,-2.15 -1.84,-3.97 -3.97,-4.2C13.3,1.73 11,3.84 11,6.5c0,2.49 2.01,4.5 4.49,4.5 0.88,0 1.7,-0.26 2.39,-0.7l2.41,2.41c0.39,0.39 1.03,0.39 1.42,0 0.39,-0.39 0.39,-1.03 0,-1.42l-2.41,-2.4zM15.5,9C14.12,9 13,7.88 13,6.5S14.12,4 15.5,4 18,5.12 18,6.5 16.88,9 15.5,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/import_contacts.xml b/compose/material/material/icons/generator/raw-icons/rounded/import_contacts.xml
index ebf22cf..7db5731 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/import_contacts.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/import_contacts.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.5,4.21c-2.59,0 -4.5,0.91 -5.5,1.48c-1,-0.58 -2.91,-1.48 -5.5,-1.48c-2.32,0 -4.06,0.73 -4.98,1.2C0.98,5.68 1,6.26 1,6.28c0,1.02 0,10.24 0,11.89c0,0.71 0.77,1.25 1.48,0.87C4.33,18.06 5.87,18 6.5,18c0.64,0 2.2,0.06 4.06,1.06c1.35,0.72 2.55,0.18 2.88,0c1.86,-1 3.42,-1.06 4.06,-1.06c0.63,0 2.17,0.06 4.02,1.04c0.74,0.39 1.48,-0.19 1.48,-0.87V6.29c0,-0.14 -0.04,-0.64 -0.53,-0.89C21.55,4.93 19.82,4.21 17.5,4.21zM21,16.62C19.86,16.21 18.69,16 17.5,16c-1.9,0 -3.78,0.54 -5.5,1.58V8c1.33,-0.77 2.9,-1.79 5.5,-1.79c1.2,0 2.39,0.25 3.5,0.72V16.62z"/>
+ android:pathData="M17.5,4.5c-1.95,0 -4.05,0.4 -5.5,1.5 -1.45,-1.1 -3.55,-1.5 -5.5,-1.5 -1.45,0 -2.99,0.22 -4.28,0.79C1.49,5.62 1,6.33 1,7.14v11.28c0,1.3 1.22,2.26 2.48,1.94 0.98,-0.25 2.02,-0.36 3.02,-0.36 1.56,0 3.22,0.26 4.56,0.92 0.6,0.3 1.28,0.3 1.87,0 1.34,-0.67 3,-0.92 4.56,-0.92 1,0 2.04,0.11 3.02,0.36 1.26,0.33 2.48,-0.63 2.48,-1.94V7.14c0,-0.81 -0.49,-1.52 -1.22,-1.85 -1.28,-0.57 -2.82,-0.79 -4.27,-0.79zM21,17.23c0,0.63 -0.58,1.09 -1.2,0.98 -0.75,-0.14 -1.53,-0.2 -2.3,-0.2 -1.7,0 -4.15,0.65 -5.5,1.5V8c1.35,-0.85 3.8,-1.5 5.5,-1.5 0.92,0 1.83,0.09 2.7,0.28 0.46,0.1 0.8,0.51 0.8,0.98v9.47z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/import_export.xml b/compose/material/material/icons/generator/raw-icons/rounded/import_export.xml
index bc4cddc..d732ca2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/import_export.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/import_export.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,17.01V11c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6.01h-1.79c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.78c0.2,0.19 0.51,0.19 0.71,0l2.79,-2.78c0.32,-0.31 0.09,-0.85 -0.35,-0.85H16zM8.65,3.35L5.86,6.14c-0.32,0.31 -0.1,0.85 0.35,0.85H8V13c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6.99h1.79c0.45,0 0.67,-0.54 0.35,-0.85L9.35,3.35C9.16,3.16 8.84,3.16 8.65,3.35z"/>
+ android:pathData="M8.65,3.35L5.86,6.14c-0.32,0.31 -0.1,0.85 0.35,0.85H8V13c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6.99h1.79c0.45,0 0.67,-0.54 0.35,-0.85L9.35,3.35c-0.19,-0.19 -0.51,-0.19 -0.7,0zM16,17.01V11c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6.01h-1.79c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.78c0.2,0.19 0.51,0.19 0.71,0l2.79,-2.78c0.32,-0.31 0.09,-0.85 -0.35,-0.85H16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/important_devices.xml b/compose/material/material/icons/generator/raw-icons/rounded/important_devices.xml
index 4c5f666..2deefc8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/important_devices.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/important_devices.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,11.01L17,11c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-8C22,11.45 21.55,11.01 21,11.01zM21,19h-4v-6h4V19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,17h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V5h14v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v10c0,1.1 0.9,2 2,2h6v2H9c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1V17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.91,9.06l-0.91,-2.81l-0.91,2.81l-2.84,0l2.32,1.84l-0.89,2.85l2.32,-1.76l2.32,1.76l-0.89,-2.85l2.32,-1.84z"/>
+ android:pathData="M23,11.01L18,11c-0.55,0 -1,0.45 -1,1v9c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1v-9c0,-0.55 -0.45,-0.99 -1,-0.99zM23,20h-5v-7h5v7zM20,2L2,2C0.9,2 0,2.9 0,4v12c0,1.1 0.9,2 2,2h7v2L8,20c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-2h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,16c-0.55,0 -1,-0.45 -1,-1L2,5c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L22,4c0,-1.1 -0.9,-2 -2,-2zM11.97,9L11,6l-0.97,3L7,9l2.47,1.76 -0.94,2.91 2.47,-1.8 2.47,1.8 -0.94,-2.91L15,9h-3.03z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/incomplete_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/incomplete_circle.xml
new file mode 100644
index 0000000..e7e6e41
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/incomplete_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12c0,5.52 -4.48,10 -10,10S2,17.52 2,12c0,-2.76 1.12,-5.26 2.93,-7.07L12,12V2C17.52,2 22,6.48 22,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/indeterminate_check_box.xml b/compose/material/material/icons/generator/raw-icons/rounded/indeterminate_check_box.xml
index 3c66d73..b9e01d4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/indeterminate_check_box.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/indeterminate_check_box.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM16,13H8c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1l0,0C17,12.55 16.55,13 16,13z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM16,13L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/info.xml b/compose/material/material/icons/generator/raw-icons/rounded/info.xml
index 705401a..0a8acfb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/info.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/info.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,17c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4C13,16.55 12.55,17 12,17zM12,9L12,9c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,8.55 12.55,9 12,9z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,17c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1zM13,9h-2L11,7h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/input.xml b/compose/material/material/icons/generator/raw-icons/rounded/input.xml
index 495cd4c4e..0c31bd5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/input.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/input.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V5.98h16v12.05H4V16c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2.02C2,19.11 2.89,20 3.98,20H20c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM11.85,15.15l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C11.54,8.54 11,8.76 11,9.21V11H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h8v1.79C11,15.24 11.54,15.46 11.85,15.15z"/>
+ android:pathData="M21,3.01L3,3.01c-1.1,0 -2,0.9 -2,2L1,8c0,0.55 0.45,1 1,1s1,-0.45 1,-1L3,5.99c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12.03c0,0.55 -0.45,1 -1,1L4,19.02c-0.55,0 -1,-0.45 -1,-1L3,16c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3.01c0,1.09 0.89,1.98 1.98,1.98L21,20.99c1.1,0 2,-0.9 2,-2L23,5.01c0,-1.1 -0.9,-2 -2,-2zM11.85,15.15l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.32 -0.85,-0.1 -0.85,0.35L11,11L2,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h9v1.79c0,0.45 0.54,0.67 0.85,0.36z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/insert_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/insert_chart.xml
index e5612aa..6899ce1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/insert_chart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/insert_chart.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM8,17c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5C9,16.55 8.55,17 8,17zM12,17c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8C13,16.55 12.55,17 12,17zM16,17c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1c0.55,0 1,0.45 1,1v2C17,16.55 16.55,17 16,17z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM8,17c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5c0,0.55 -0.45,1 -1,1zM12,17c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8c0,0.55 -0.45,1 -1,1zM16,17c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/insert_chart_outlined.xml b/compose/material/material/icons/generator/raw-icons/rounded/insert_chart_outlined.xml
index 3539084..dec9d84 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/insert_chart_outlined.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/insert_chart_outlined.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19zM8,10L8,10c0.55,0 1,0.45 1,1v5c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-5C7,10.45 7.45,10 8,10zM12,7L12,7c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V8C11,7.45 11.45,7 12,7zM16,13L16,13c0.55,0 1,0.45 1,1v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-2C15,13.45 15.45,13 16,13z"/>
+ android:pathData="M8,17c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5c0,0.55 -0.45,1 -1,1zM12,17c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8c0,0.55 -0.45,1 -1,1zM16,17c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/insert_comment.xml b/compose/material/material/icons/generator/raw-icons/rounded/insert_comment.xml
index 51a1b9e..c4c435b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/insert_comment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/insert_comment.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.99,4c0,-1.1 -0.89,-2 -1.99,-2H4C2.9,2 2,2.9 2,4v12c0,1.1 0.9,2 2,2h14l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71L21.99,4zM17,14H7c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1l0,0C18,13.55 17.55,14 17,14zM17,11H7c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1l0,0C18,10.55 17.55,11 17,11zM17,8H7C6.45,8 6,7.55 6,7l0,0c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1l0,0C18,7.55 17.55,8 17,8z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4L22,4c0,-1.1 -0.9,-2 -2,-2zM17,14L7,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,11L7,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,8L7,8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/insert_drive_file.xml b/compose/material/material/icons/generator/raw-icons/rounded/insert_drive_file.xml
index 7b1a5c0..096e3d5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/insert_drive_file.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/insert_drive_file.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,2C4.9,2 4.01,2.9 4.01,4L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.83,-4.83C14.21,2.21 13.7,2 13.17,2H6zM13,8V3.5L18.5,9H14C13.45,9 13,8.55 13,8z"/>
+ android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.83,-4.83c-0.37,-0.38 -0.88,-0.59 -1.41,-0.59L6,2zM13,8L13,3.5L18.5,9L14,9c-0.55,0 -1,-0.45 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/insert_invitation.xml b/compose/material/material/icons/generator/raw-icons/rounded/insert_invitation.xml
index 3f46299..9cece20 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/insert_invitation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/insert_invitation.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,13h-3c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3C17,13.45 16.55,13 16,13zM16,3v1H8V3c0,-0.55 -0.45,-1 -1,-1S6,2.45 6,3v1H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-1V3c0,-0.55 -0.45,-1 -1,-1S16,2.45 16,3zM19,20H5V10h14V20z"/>
+ android:pathData="M16,12h-3c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1zM16,2v1L8,3L8,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,3c-1.11,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2h-1L18,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,8h14v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/insert_link.xml b/compose/material/material/icons/generator/raw-icons/rounded/insert_link.xml
index 66cff79..bf64a9e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/insert_link.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/insert_link.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3.96,11.38C4.24,9.91 5.62,8.9 7.12,8.9h2.93C10.57,8.9 11,8.47 11,7.95l0,0C11,7.43 10.57,7 10.05,7H7.22c-2.61,0 -4.94,1.91 -5.19,4.51C1.74,14.49 4.08,17 7,17h3.05c0.52,0 0.95,-0.43 0.95,-0.95l0,0c0,-0.52 -0.43,-0.95 -0.95,-0.95H7C5.09,15.1 3.58,13.36 3.96,11.38zM9,13h6c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H9c-0.55,0 -1,0.45 -1,1l0,0C8,12.55 8.45,13 9,13zM16.78,7h-2.83C13.43,7 13,7.43 13,7.95l0,0c0,0.52 0.43,0.95 0.95,0.95h2.93c1.5,0 2.88,1.01 3.16,2.48c0.38,1.98 -1.13,3.72 -3.04,3.72h-3.05c-0.52,0 -0.95,0.43 -0.95,0.95l0,0c0,0.52 0.43,0.95 0.95,0.95H17c2.92,0 5.26,-2.51 4.98,-5.49C21.73,8.91 19.39,7 16.78,7z"/>
+ android:pathData="M3.96,11.38C4.24,9.91 5.62,8.9 7.12,8.9h2.93c0.52,0 0.95,-0.43 0.95,-0.95S10.57,7 10.05,7L7.22,7c-2.61,0 -4.94,1.91 -5.19,4.51C1.74,14.49 4.08,17 7,17h3.05c0.52,0 0.95,-0.43 0.95,-0.95s-0.43,-0.95 -0.95,-0.95L7,15.1c-1.91,0 -3.42,-1.74 -3.04,-3.72zM9,13h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L9,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM16.78,7h-2.83c-0.52,0 -0.95,0.43 -0.95,0.95s0.43,0.95 0.95,0.95h2.93c1.5,0 2.88,1.01 3.16,2.48 0.38,1.98 -1.13,3.72 -3.04,3.72h-3.05c-0.52,0 -0.95,0.43 -0.95,0.95s0.43,0.95 0.95,0.95L17,17c2.92,0 5.26,-2.51 4.98,-5.49 -0.25,-2.6 -2.59,-4.51 -5.2,-4.51z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/insert_photo.xml b/compose/material/material/icons/generator/raw-icons/rounded/insert_photo.xml
index 6e55f90..08f6184 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/insert_photo.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/insert_photo.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM6.6,16.2l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,16l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67c0.25,0.33 0.01,0.8 -0.4,0.8H7C6.59,17 6.35,16.53 6.6,16.2z"/>
+ android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.9,13.98l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8H6.02c-0.42,0 -0.65,-0.48 -0.39,-0.81L8.12,14c0.19,-0.26 0.57,-0.27 0.78,-0.02z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/integration_instructions.xml b/compose/material/material/icons/generator/raw-icons/rounded/integration_instructions.xml
index 1302e7f..8fe26a9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/integration_instructions.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/integration_instructions.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM10.29,13.46c0.39,0.39 0.39,1.02 0,1.41c-0.39,0.39 -1.03,0.39 -1.42,0l-2.17,-2.17c-0.39,-0.39 -0.39,-1.02 0,-1.41l2.17,-2.17c0.39,-0.39 1.03,-0.39 1.42,0c0.39,0.39 0.39,1.02 0,1.41L8.83,12L10.29,13.46zM12,4.25c-0.41,0 -0.75,-0.34 -0.75,-0.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75C12.75,3.91 12.41,4.25 12,4.25zM17.29,12.71l-2.17,2.17c-0.39,0.39 -1.03,0.39 -1.42,0c-0.39,-0.39 -0.39,-1.02 0,-1.41L15.17,12l-1.47,-1.47c-0.39,-0.39 -0.39,-1.02 0,-1.41c0.39,-0.39 1.03,-0.39 1.42,0l2.17,2.17C17.68,11.68 17.68,12.32 17.29,12.71z"/>
+ android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C4.86,3 4.73,3.01 4.6,3.04C4.21,3.12 3.86,3.32 3.59,3.59c-0.18,0.18 -0.33,0.4 -0.43,0.64C3.06,4.46 3,4.72 3,5v14c0,0.27 0.06,0.54 0.16,0.78c0.1,0.24 0.25,0.45 0.43,0.64c0.27,0.27 0.62,0.47 1.01,0.55C4.73,20.99 4.86,21 5,21h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM10.3,14.88L10.3,14.88c-0.39,0.39 -1.03,0.39 -1.42,0l-2.17,-2.17c-0.39,-0.39 -0.39,-1.02 0,-1.41l2.17,-2.17c0.39,-0.39 1.03,-0.39 1.42,0l0,0c0.39,0.39 0.39,1.02 0,1.41L8.83,12l1.46,1.46C10.68,13.85 10.69,14.49 10.3,14.88zM12,4.25c-0.41,0 -0.75,-0.34 -0.75,-0.75S11.59,2.75 12,2.75s0.75,0.34 0.75,0.75S12.41,4.25 12,4.25zM13.7,14.88L13.7,14.88c-0.39,-0.39 -0.39,-1.02 0,-1.41L15.17,12l-1.47,-1.47c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.03,-0.39 1.42,0l2.17,2.17c0.39,0.39 0.39,1.02 0,1.41l-2.17,2.17C14.73,15.27 14.09,15.27 13.7,14.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/interests.xml b/compose/material/material/icons/generator/raw-icons/rounded/interests.xml
new file mode 100644
index 0000000..049dafc
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/interests.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.02,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.23,13 7.02,13zM13,14v6c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1h-6C13.45,13 13,13.45 13,14zM6.13,3.57l-3.3,5.94C2.46,10.18 2.94,11 3.7,11h6.6c0.76,0 1.24,-0.82 0.87,-1.49l-3.3,-5.94C7.49,2.89 6.51,2.89 6.13,3.57zM19.25,2.5c-1.06,0 -1.81,0.56 -2.25,1.17c-0.44,-0.61 -1.19,-1.17 -2.25,-1.17C13.19,2.5 12,3.78 12,5.25c0,1.83 2.03,3.17 4.35,5.18c0.37,0.32 0.92,0.32 1.3,0C19.97,8.42 22,7.08 22,5.25C22,3.78 20.81,2.5 19.25,2.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/interpreter_mode.xml b/compose/material/material/icons/generator/raw-icons/rounded/interpreter_mode.xml
new file mode 100644
index 0000000..9149ddf
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/interpreter_mode.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.5,16.5c-0.83,0 -1.5,-0.67 -1.5,-1.5v-2.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5V15C22,15.83 21.33,16.5 20.5,16.5zM20.5,20c0.28,0 0.5,-0.22 0.5,-0.5c0,-0.45 0,-1.04 0,-1.04c1.51,-0.22 2.71,-1.4 2.95,-2.89C24,15.27 23.76,15 23.46,15c-0.24,0 -0.45,0.17 -0.49,0.41c-0.2,1.18 -1.23,2.09 -2.47,2.09s-2.27,-0.9 -2.47,-2.09C17.99,15.17 17.78,15 17.54,15c-0.3,0 -0.54,0.27 -0.5,0.57c0.25,1.5 1.45,2.68 2.95,2.89c0,0 0,0.59 0,1.04C20,19.78 20.22,20 20.5,20zM9,12c-2.21,0 -4,-1.79 -4,-4c0,-2.21 1.79,-4 4,-4c0.47,0 0.92,0.08 1.34,0.23C9.5,5.26 9,6.57 9,8c0,1.43 0.5,2.74 1.34,3.77C9.92,11.92 9.47,12 9,12zM7.11,13.13C5.79,14.05 5,15.57 5,17.22V20H1v-2.78c0,-1.12 0.61,-2.15 1.61,-2.66C3.85,13.92 5.37,13.37 7.11,13.13zM11,8c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S11,10.21 11,8zM18.32,20c-1.67,-0.81 -2.82,-2.52 -2.82,-4.5c0,-0.89 0.23,-1.73 0.64,-2.45C15.77,13.02 15.39,13 15,13c-2.53,0 -4.71,0.7 -6.39,1.56C7.61,15.07 7,16.1 7,17.22V20L18.32,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/iso.xml b/compose/material/material/icons/generator/raw-icons/rounded/iso.xml
index 0aeb66f..7c48545 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/iso.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/iso.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM6.25,7.5H7.5V6.25c0,-0.41 0.34,-0.75 0.75,-0.75l0,0C8.66,5.5 9,5.84 9,6.25V7.5h1.25C10.66,7.5 11,7.84 11,8.25l0,0C11,8.66 10.66,9 10.25,9H9v1.25C9,10.66 8.66,11 8.25,11l0,0c-0.41,0 -0.75,-0.34 -0.75,-0.75V9H6.25C5.84,9 5.5,8.66 5.5,8.25l0,0C5.5,7.84 5.84,7.5 6.25,7.5zM19,19H5L19,5V19zM17,16.25L17,16.25c0,-0.41 -0.34,-0.75 -0.75,-0.75h-3.5c-0.41,0 -0.75,0.34 -0.75,0.75l0,0c0,0.41 0.34,0.75 0.75,0.75h3.5C16.66,17 17,16.66 17,16.25z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM6.25,7.5L7.5,7.5L7.5,6.25c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75L9,7.5h1.25c0.41,0 0.75,0.34 0.75,0.75s-0.34,0.75 -0.75,0.75L9,9v1.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75L7.5,9L6.25,9c-0.41,0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75zM18,19L5,19L19,5v13c0,0.55 -0.45,1 -1,1zM17,16.25c0,-0.41 -0.34,-0.75 -0.75,-0.75h-3.5c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75h3.5c0.41,0 0.75,-0.34 0.75,-0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/kebab_dining.xml b/compose/material/material/icons/generator/raw-icons/rounded/kebab_dining.xml
new file mode 100644
index 0000000..4e0c4c2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/kebab_dining.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.75,13v1H8.5c1.38,0 2.5,1.12 2.5,2.5c0,1.38 -1.12,2.5 -2.5,2.5H7.75v3.25C7.75,22.66 7.41,23 7,23s-0.75,-0.34 -0.75,-0.75V19H5.5C4.12,19 3,17.88 3,16.5C3,15.12 4.12,14 5.5,14h0.75v-1H4c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1h2.25V7H5.5C4.12,7 3,5.88 3,4.5C3,3.12 4.12,2 5.5,2h0.75V1.75C6.25,1.34 6.59,1 7,1s0.75,0.34 0.75,0.75V2H8.5C9.88,2 11,3.12 11,4.5C11,5.88 9.88,7 8.5,7H7.75v1H10c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1H7.75zM17.75,13v1h0.75c1.38,0 2.5,1.12 2.5,2.5c0,1.38 -1.12,2.5 -2.5,2.5h-0.75v3.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75V19H15.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5h0.75v-1H14c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1h2.25V7H15.5C14.12,7 13,5.88 13,4.5C13,3.12 14.12,2 15.5,2h0.75V1.75C16.25,1.34 16.59,1 17,1s0.75,0.34 0.75,0.75V2h0.75C19.88,2 21,3.12 21,4.5C21,5.88 19.88,7 18.5,7h-0.75v1H20c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1H17.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard.xml
index 7d2a17a..6fd0f6f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5H4C2.9,5 2.01,5.9 2.01,7L2,17c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM11,8h2v2h-2V8zM11,11h2v2h-2V11zM8,8h2v2H8V8zM8,11h2v2H8V11zM7,13H5v-2h2V13zM7,10H5V8h2V10zM15,17H9c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1l0,0C16,16.55 15.55,17 15,17zM16,13h-2v-2h2V13zM16,10h-2V8h2V10zM19,13h-2v-2h2V13zM19,10h-2V8h2V10z"/>
+ android:pathData="M20,5L4,5c-1.1,0 -1.99,0.9 -1.99,2L2,17c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM11,8h2v2h-2L11,8zM11,11h2v2h-2v-2zM8,8h2v2L8,10L8,8zM8,11h2v2L8,13v-2zM7,13L5,13v-2h2v2zM7,10L5,10L5,8h2v2zM15,17L9,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM16,13h-2v-2h2v2zM16,10h-2L14,8h2v2zM19,13h-2v-2h2v2zM19,10h-2L17,8h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_down.xml
index 43ad9c4..3abc794 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_down.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_down.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.71,9.29l3.88,3.88l3.88,-3.88c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0L6.29,10.7c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0C6.68,8.91 7.32,8.9 7.71,9.29z"/>
+ android:pathData="M8.12,9.29L12,13.17l3.88,-3.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0L6.7,10.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.38 1.03,-0.39 1.42,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_left.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_left.xml
index 7a17179..aa83a1f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_left.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_left.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.29,15.46l-3.88,-3.88l3.88,-3.88c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l0,0C15.67,16.49 15.68,15.85 15.29,15.46z"/>
+ android:pathData="M14.71,15.88L10.83,12l3.88,-3.88c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L8.71,11.3c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0 0.38,-0.39 0.39,-1.03 0,-1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_right.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_right.xml
index 38fd791..a247679 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_right.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_right.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M9.29,15.46l3.88,-3.88L9.29,7.7c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l4.59,4.59c0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0l0,0C8.91,16.49 8.9,15.85 9.29,15.46z"/>
+ android:pathData="M9.29,15.88L13.17,12 9.29,8.12c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0l4.59,4.59c0.39,0.39 0.39,1.02 0,1.41L10.7,17.3c-0.39,0.39 -1.02,0.39 -1.41,0 -0.38,-0.39 -0.39,-1.03 0,-1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_up.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_up.xml
index 2f66467..c278cf1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_up.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_arrow_up.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.71,15.29l3.88,-3.88l3.88,3.88c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-4.59,-4.59c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l0,0C6.68,15.67 7.32,15.68 7.71,15.29z"/>
+ android:pathData="M8.12,14.71L12,10.83l3.88,3.88c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L12.7,8.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L6.7,13.3c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.38 1.03,0.39 1.42,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_backspace.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_backspace.xml
index 6d2f151..d28628c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_backspace.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_backspace.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.58,10.58H6.41L9.29,7.7c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C8.9,5.9 8.27,5.9 7.88,6.29l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.88,-2.89h13.17c0.55,0 1,-0.45 1,-1l0,0C20.58,11.03 20.13,10.58 19.58,10.58z"/>
+ android:pathData="M20,11H6.83l2.88,-2.88c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L3.71,11.3c-0.39,0.39 -0.39,1.02 0,1.41L8.3,17.3c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L6.83,13H20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_capslock.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_capslock.xml
index 2a3efc1..5ccc102 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_capslock.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_capslock.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8.41l3.89,3.89c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L12.71,6.3c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.6,4.59c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,8.41zM7,18h10c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H7c-0.55,0 -1,0.45 -1,1l0,0C6,17.55 6.45,18 7,18z"/>
+ android:pathData="M12,8.41l3.89,3.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L12.71,6.3c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.6,4.59c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,8.41zM7,18h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_hide.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_hide.xml
index 01e924d..a2cdda2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_hide.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_hide.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3.1H4c-1.1,0 -1.99,0.9 -1.99,2L2,15.1c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-10C22,4 21.1,3.1 20,3.1zM11,6.1h2v2h-2V6.1zM11,9.1h2v2h-2V9.1zM8,6.1h2v2H8V6.1zM8,9.1h2v2H8V9.1zM7,11.1H5v-2h2V11.1zM7,8.1H5v-2h2V8.1zM15,15.1H9c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1l0,0C16,14.65 15.55,15.1 15,15.1zM16,11.1h-2v-2h2V11.1zM16,8.1h-2v-2h2V8.1zM19,11.1h-2v-2h2V11.1zM19,8.1h-2v-2h2V8.1zM12.35,22.75l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79C11.84,22.94 12.16,22.94 12.35,22.75z"/>
+ android:pathData="M20,3L4,3c-1.1,0 -1.99,0.9 -1.99,2L2,15c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,5c0,-1.1 -0.9,-2 -2,-2zM11,6h2v2h-2L11,6zM11,9h2v2h-2L11,9zM8,6h2v2L8,8L8,6zM8,9h2v2L8,11L8,9zM7,11L5,11L5,9h2v2zM7,8L5,8L5,6h2v2zM15,15L9,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM16,11h-2L14,9h2v2zM16,8h-2L14,6h2v2zM19,11h-2L17,9h2v2zM19,8h-2L17,6h2v2zM12.35,22.65l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85L9.21,19.01c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.19,0.19 0.51,0.19 0.7,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_return.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_return.xml
index 946a4a9..90bb7e4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_return.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_return.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,8v3H5.83l2.88,-2.88c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L5.83,13H20c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1h0C19.45,7 19,7.45 19,8z"/>
+ android:pathData="M19,8v3H5.83l2.88,-2.88c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L2.71,11.3c-0.39,0.39 -0.39,1.02 0,1.41L7.3,17.3c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.83,13H20c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_tab.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_tab.xml
index 1530497..1e16ebe 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_tab.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_tab.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.29,8.12L15.17,11H3c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h12.17l-2.88,2.88c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L13.7,6.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C11.91,7.09 11.9,7.73 12.29,8.12zM20,7v10c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1l0,0C20.45,6 20,6.45 20,7z"/>
+ android:pathData="M12.29,8.12L15.17,11H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h13.17l-2.88,2.88c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L13.7,6.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.38,0.39 -0.39,1.03 0,1.42zM20,7v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_voice.xml b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_voice.xml
index 693e9ee..0e40077 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/keyboard_voice.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/keyboard_voice.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.91,11c-0.49,0 -0.9,0.36 -0.98,0.85C16.52,14.21 14.47,16 12,16s-4.52,-1.79 -4.93,-4.15C6.99,11.36 6.58,11 6.09,11h0c-0.61,0 -1.09,0.54 -1,1.14c0.49,3 2.89,5.34 5.91,5.78V20c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2.08c3.02,-0.44 5.42,-2.78 5.91,-5.78C19.01,11.54 18.52,11 17.91,11L17.91,11z"/>
+ android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM18.08,12c-0.42,0 -0.77,0.3 -0.83,0.71 -0.37,2.61 -2.72,4.39 -5.25,4.39s-4.88,-1.77 -5.25,-4.39c-0.06,-0.41 -0.42,-0.71 -0.83,-0.71 -0.52,0 -0.92,0.46 -0.85,0.97 0.46,2.97 2.96,5.3 5.93,5.75L11,21c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.28c2.96,-0.43 5.47,-2.78 5.93,-5.75 0.07,-0.51 -0.33,-0.97 -0.85,-0.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/king_bed.xml b/compose/material/material/icons/generator/raw-icons/rounded/king_bed.xml
index 348d110..4241434 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/king_bed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/king_bed.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,10V7c0,-1.1 -0.9,-2 -2,-2H6C4.9,5 4,5.9 4,7v3c-1.1,0 -2,0.9 -2,2v5h1.33l0.51,1.53C3.94,18.81 4.2,19 4.5,19l0,0c0.3,0 0.56,-0.19 0.66,-0.47L5.67,17h12.67l0.51,1.53C18.94,18.81 19.2,19 19.5,19l0,0c0.3,0 0.56,-0.19 0.66,-0.47L20.67,17H22v-5C22,10.9 21.1,10 20,10zM11,10H6V7h5V10zM18,10h-5V7h5V10z"/>
+ android:pathData="M20,10V7c0,-1.1 -0.9,-2 -2,-2H6C4.9,5 4,5.9 4,7v3c-1.1,0 -2,0.9 -2,2v5h1.33l0.51,1.53C3.94,18.81 4.2,19 4.5,19h0c0.3,0 0.56,-0.19 0.66,-0.47L5.67,17h12.67l0.51,1.53C18.94,18.81 19.2,19 19.5,19l0,0c0.3,0 0.56,-0.19 0.66,-0.47L20.67,17H22v-5C22,10.9 21.1,10 20,10zM11,10H6V8c0,-0.55 0.45,-1 1,-1h4V10zM18,10h-5V7h4c0.55,0 1,0.45 1,1V10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/kitchen.xml b/compose/material/material/icons/generator/raw-icons/rounded/kitchen.xml
index 551a4b3..e903c21 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/kitchen.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/kitchen.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2.01L6,2C4.9,2 4,2.89 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.89 19.1,2.01 18,2.01zM18,20H6v-9.02h12V20zM18,9H6V4h12V9zM9,5L9,5c0.55,0 1,0.45 1,1v1c0,0.55 -0.45,1 -1,1l0,0C8.45,8 8,7.55 8,7V6C8,5.45 8.45,5 9,5zM9,12L9,12c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-3C8,12.45 8.45,12 9,12z"/>
+ android:pathData="M18,2.01L6,2c-1.1,0 -2,0.89 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.11 -0.9,-1.99 -2,-1.99zM17,20L7,20c-0.55,0 -1,-0.45 -1,-1v-7.02c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1L18,19c0,0.55 -0.45,1 -1,1zM17,9L7,9c-0.55,0 -1,-0.45 -1,-1L6,5c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1zM9,5c0.55,0 1,0.45 1,1v1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L8,6c0,-0.55 0.45,-1 1,-1zM9,12c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/label.xml b/compose/material/material/icons/generator/raw-icons/rounded/label.xml
index 512c9f4..55a2d01 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/label.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/label.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.63,5.84C16.26,5.31 15.65,5 15,5H5C3.9,5 3,5.9 3,7v10c0,1.1 0.9,2 2,2h10c0.65,0 1.26,-0.32 1.63,-0.84l3.55,-5c0.49,-0.69 0.49,-1.62 0,-2.31L16.63,5.84z"/>
+ android:pathData="M17.63,5.84C17.27,5.33 16.67,5 16,5L5,5.01C3.9,5.01 3,5.9 3,7v10c0,1.1 0.9,1.99 2,1.99L16,19c0.67,0 1.27,-0.33 1.63,-0.84l3.96,-5.58c0.25,-0.35 0.25,-0.81 0,-1.16l-3.96,-5.58z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/label_important.xml b/compose/material/material/icons/generator/raw-icons/rounded/label_important.xml
index da43e81..1e8bd507 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/label_important.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/label_important.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.94,18.99H15c0.65,0 1.26,-0.31 1.63,-0.84l3.54,-4.99c0.49,-0.69 0.49,-1.62 0,-2.31l-3.55,-5C16.26,5.31 15.65,5 15,5H5.94C5.13,5 4.66,5.93 5.13,6.59L9,12l-3.87,5.41C4.66,18.07 5.13,18.99 5.94,18.99z"/>
+ android:pathData="M5.94,18.99H15c0.65,0 1.26,-0.31 1.63,-0.84l3.95,-5.57c0.25,-0.35 0.25,-0.81 0,-1.16l-3.96,-5.58C16.26,5.31 15.65,5 15,5H5.94c-0.81,0 -1.28,0.93 -0.81,1.59L9,12l-3.87,5.41c-0.47,0.66 0,1.58 0.81,1.58z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/label_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/label_off.xml
index 275c73e..7d7da48 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/label_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/label_off.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.18,13.16c0.49,-0.69 0.49,-1.62 0,-2.31l-3.55,-5C16.26,5.31 15.65,5 15,5H7.83l10.61,10.61L20.18,13.16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l1.14,1.14C3.09,6.35 3,6.66 3,7v10c0,1.1 0.9,2 2,2h10c0.33,0 0.65,-0.08 0.94,-0.24l3.14,3.14c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M21.59,12.58c0.25,-0.35 0.25,-0.81 0,-1.16l-3.96,-5.58C17.27,5.33 16.67,5 16,5H8.66l10.7,10.73 2.23,-3.15zM2.72,4.72l0.87,0.87C3.23,5.95 3,6.45 3,7v10c0,1.1 0.9,2 2,2h12l1.29,1.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.14,3.31c-0.38,-0.38 -1.01,-0.39 -1.4,-0.01 -0.41,0.38 -0.41,1.03 -0.02,1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/landscape.xml b/compose/material/material/icons/generator/raw-icons/rounded/landscape.xml
index 0b804bb..515fe49 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/landscape.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/landscape.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.2,7.07L10.25,11l2.25,3c0.33,0.44 0.24,1.07 -0.2,1.4l0,0c-0.44,0.33 -1.07,0.25 -1.4,-0.2c-1.05,-1.4 -2.31,-3.07 -3.1,-4.14c-0.4,-0.53 -1.2,-0.53 -1.6,0l-4,5.33C1.71,17.06 2.18,18 3,18h18c0.82,0 1.29,-0.94 0.8,-1.6l-7,-9.33C14.4,6.53 13.6,6.53 13.2,7.07z"/>
+ android:pathData="M13.2,7.07L10.25,11l2.25,3c0.33,0.44 0.24,1.07 -0.2,1.4 -0.44,0.33 -1.07,0.25 -1.4,-0.2 -1.05,-1.4 -2.31,-3.07 -3.1,-4.14 -0.4,-0.53 -1.2,-0.53 -1.6,0l-4,5.33c-0.49,0.67 -0.02,1.61 0.8,1.61h18c0.82,0 1.29,-0.94 0.8,-1.6l-7,-9.33c-0.4,-0.54 -1.2,-0.54 -1.6,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/language.xml b/compose/material/material/icons/generator/raw-icons/rounded/language.xml
index e5c04ff..e745325 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/language.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/language.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56C16.43,5.07 17.96,6.35 18.92,8zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82C10.52,6.57 11.17,5.24 12,4.04zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2s0.06,1.34 0.14,2H4.26zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56C7.57,18.93 6.04,17.66 5.08,16zM8.03,8H5.08c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82C13.48,17.43 12.83,18.76 12,19.96zM14.34,14H9.66c-0.09,-0.66 -0.16,-1.32 -0.16,-2s0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2S14.43,13.34 14.34,14zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95C17.96,17.65 16.43,18.93 14.59,19.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2s-0.06,-1.34 -0.14,-2h3.38C19.9,10.64 20,11.31 20,12s-0.1,1.36 -0.26,2H16.36z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2s0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2s0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2s-0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2s-0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/laptop.xml b/compose/material/material/icons/generator/raw-icons/rounded/laptop.xml
index d4bfea5..ad671d1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/laptop.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/laptop.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h16c1.1,0 1.99,-0.9 1.99,-2L22,5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v11C2,17.1 2.9,18 4,18zM4,5h16v11H4V5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1,20L1,20c0,0.55 0.45,1 1,1h20c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H2C1.45,19 1,19.45 1,20z"/>
+ android:pathData="M20,18c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2H1c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h22c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3zM5,6h14c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/laptop_chromebook.xml b/compose/material/material/icons/generator/raw-icons/rounded/laptop_chromebook.xml
index cf66717..d58be02 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/laptop_chromebook.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/laptop_chromebook.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M23,18h-1V5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v13H1c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h22c0.55,0 1,-0.45 1,-1S23.55,18 23,18zM13.5,18h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5S13.78,18 13.5,18zM20,15H4V5h16V15z"/>
+ android:pathData="M23,18h-1L22,5c0,-1.1 -0.9,-2 -2,-2L4,3c-1.1,0 -2,0.9 -2,2v13L1,18c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h22c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM13.5,18h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5s-0.22,0.5 -0.5,0.5zM20,15L4,15L4,6c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/laptop_mac.xml b/compose/material/material/icons/generator/raw-icons/rounded/laptop_mac.xml
index 31c26ae..af833ec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/laptop_mac.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/laptop_mac.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,18c1.1,0 1.99,-0.9 1.99,-2L22,5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v11c0,1.1 0.9,2 2,2H0c0,1.1 0.9,2 2,2h20c1.1,0 2,-0.9 2,-2H20zM4,5h16v11H4V5zM12,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,19 12,19z"/>
+ android:pathData="M20,18c1.1,0 1.99,-0.9 1.99,-2L22,5c0,-1.1 -0.9,-2 -2,-2L4,3c-1.1,0 -2,0.9 -2,2v11c0,1.1 0.9,2 2,2L0,18c0,1.1 0.9,2 2,2h20c1.1,0 2,-0.9 2,-2h-4zM5,5h14c0.55,0 1,0.45 1,1v9c0,0.55 -0.45,1 -1,1L5,16c-0.55,0 -1,-0.45 -1,-1L4,6c0,-0.55 0.45,-1 1,-1zM12,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/laptop_windows.xml b/compose/material/material/icons/generator/raw-icons/rounded/laptop_windows.xml
index d9c470b..7d4e422 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/laptop_windows.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/laptop_windows.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,18v-1c1.1,0 1.99,-0.9 1.99,-2L22,5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v10c0,1.1 0.9,2 2,2v1H1c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h22c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H20zM4,5h16v10H4V5z"/>
+ android:pathData="M20,18v-1c1.1,0 1.99,-0.9 1.99,-2L22,5c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2v1H1c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h22c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3zM5,5h14c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/last_page.xml b/compose/material/material/icons/generator/raw-icons/rounded/last_page.xml
index 0fabeb0..ec40c0e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/last_page.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/last_page.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.29,8.11L10.18,12l-3.89,3.89c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L7.7,6.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C5.91,7.09 5.91,7.73 6.29,8.11zM17,6L17,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1V7C16,6.45 16.45,6 17,6z"/>
+ android:pathData="M6.29,8.11L10.18,12l-3.89,3.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L7.7,6.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.38,0.39 -0.38,1.03 0,1.41zM17,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/launch.xml b/compose/material/material/icons/generator/raw-icons/rounded/launch.xml
index b5a083f..177eeadd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/launch.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/launch.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,12L20,12c-0.55,0 -1,0.45 -1,1v6H5V5h6c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-6C21,12.45 20.55,12 20,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.5,3h-5.29c-0.45,0 -0.67,0.54 -0.35,0.85l1.94,1.94L9,13.59C8.61,13.98 8.61,14.61 9,15h0c0.39,0.39 1.02,0.39 1.41,0l7.79,-7.79l1.94,1.94C20.46,9.46 21,9.24 21,8.79V3.5C21,3.22 20.78,3 20.5,3z"/>
+ android:pathData="M18,19H6c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v5c0,0.55 -0.45,1 -1,1zM14,4c0,0.55 0.45,1 1,1h2.59l-9.13,9.13c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L19,6.41V9c0,0.55 0.45,1 1,1s1,-0.45 1,-1V3h-6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/layers.xml b/compose/material/material/icons/generator/raw-icons/rounded/layers.xml
index 074432e..14d93a1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/layers.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/layers.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,18.47l-6.77,-5.26c-0.36,-0.28 -0.86,-0.28 -1.22,0l0,0c-0.51,0.4 -0.51,1.17 0,1.57l6.76,5.26c0.72,0.56 1.73,0.56 2.46,0l6.76,-5.26c0.51,-0.4 0.51,-1.17 0,-1.57l-0.01,-0.01c-0.36,-0.28 -0.86,-0.28 -1.22,0L11.99,18.47zM13.23,14.97l6.76,-5.26c0.51,-0.4 0.51,-1.18 0,-1.58l-6.76,-5.26c-0.72,-0.56 -1.73,-0.56 -2.46,0L4.01,8.14c-0.51,0.4 -0.51,1.18 0,1.58l6.76,5.26C11.49,15.54 12.51,15.54 13.23,14.97z"/>
+ android:pathData="M12.6,18.06c-0.36,0.28 -0.87,0.28 -1.23,0l-6.15,-4.78c-0.36,-0.28 -0.86,-0.28 -1.22,0 -0.51,0.4 -0.51,1.17 0,1.57l6.76,5.26c0.72,0.56 1.73,0.56 2.46,0l6.76,-5.26c0.51,-0.4 0.51,-1.17 0,-1.57l-0.01,-0.01c-0.36,-0.28 -0.86,-0.28 -1.22,0l-6.15,4.79zM13.23,15.04l6.76,-5.26c0.51,-0.4 0.51,-1.18 0,-1.58l-6.76,-5.26c-0.72,-0.56 -1.73,-0.56 -2.46,0L4.01,8.21c-0.51,0.4 -0.51,1.18 0,1.58l6.76,5.26c0.72,0.56 1.74,0.56 2.46,-0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/layers_clear.xml b/compose/material/material/icons/generator/raw-icons/rounded/layers_clear.xml
index ee8ea79..e3bd31c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/layers_clear.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/layers_clear.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.97,13.2c-0.36,-0.28 -0.86,-0.28 -1.22,0l-1.23,0.96l1.43,1.43l1.03,-0.8c0.51,-0.4 0.51,-1.17 0,-1.57L19.97,13.2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.99,9.71c0.51,-0.4 0.51,-1.18 0,-1.58l-6.76,-5.26c-0.72,-0.56 -1.73,-0.56 -2.46,0L8.23,4.86l7.88,7.88L19.99,9.71z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.48,19.94L3.51,2.97c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l2.95,2.95L4.01,8.14c-0.51,0.4 -0.51,1.18 0,1.58l6.76,5.26c0.61,0.48 1.43,0.52 2.11,0.18l1.47,1.47l-2.36,1.84l-6.77,-5.26c-0.36,-0.28 -0.86,-0.28 -1.22,0c-0.51,0.4 -0.51,1.17 0,1.57l6.76,5.26c0.72,0.56 1.73,0.56 2.46,0l2.55,-1.98l3.3,3.3c0.39,0.39 1.02,0.39 1.41,0C20.88,20.97 20.88,20.33 20.48,19.94z"/>
+ android:pathData="M19.99,9.79c0.51,-0.4 0.51,-1.18 0,-1.58l-6.76,-5.26c-0.72,-0.56 -1.73,-0.56 -2.46,0L9.41,4.02l7.88,7.88 2.7,-2.11zM19.99,13.28l-0.01,-0.01c-0.36,-0.28 -0.86,-0.28 -1.22,0l-0.05,0.04 1.4,1.4c0.37,-0.41 0.34,-1.07 -0.12,-1.43zM21.44,18.88L4.12,1.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l3.52,3.52 -2.22,1.72c-0.51,0.4 -0.51,1.18 0,1.58l6.76,5.26c0.72,0.56 1.73,0.56 2.46,0l0.87,-0.68 1.42,1.42 -2.92,2.27c-0.36,0.28 -0.87,0.28 -1.23,0l-6.15,-4.78c-0.36,-0.28 -0.86,-0.28 -1.22,0 -0.51,0.4 -0.51,1.17 0,1.57l6.76,5.26c0.72,0.56 1.73,0.56 2.46,0l3.72,-2.89 3.07,3.07c0.39,0.39 1.02,0.39 1.41,0 0.41,-0.39 0.41,-1.02 0.02,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/leak_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/leak_add.xml
index c2d95fe..03f420d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/leak_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/leak_add.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.05,21c0.5,0 0.94,-0.37 0.99,-0.87c0.41,-4.27 3.81,-7.67 8.08,-8.08C20.62,12 21,11.57 21,11.06l0,0c0,-0.59 -0.51,-1.06 -1.1,-1c-5.19,0.52 -9.32,4.65 -9.84,9.83C10,20.48 10.46,21 11.05,21L11.05,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,21h3v-3C19.34,18 18,19.34 18,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.09,21c0.49,0 0.9,-0.36 0.98,-0.85c0.36,-2.08 2,-3.72 4.08,-4.08c0.49,-0.08 0.85,-0.49 0.85,-0.98l0,0c0,-0.61 -0.54,-1.09 -1.14,-1c-2.96,0.48 -5.29,2.81 -5.77,5.77C13.99,20.46 14.48,21 15.09,21L15.09,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.97,3.02c-0.5,0 -0.94,0.37 -0.99,0.87c-0.41,4.27 -3.81,7.67 -8.08,8.08c-0.5,0.05 -0.88,0.48 -0.88,0.99l0,0c0,0.59 0.51,1.06 1.1,1c5.19,-0.52 9.32,-4.65 9.84,-9.83C14.03,3.55 13.57,3.02 12.97,3.02L12.97,3.02z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.03,3.02h-3v3C4.69,6.02 6.03,4.68 6.03,3.02z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8.94,3.02c-0.49,0 -0.9,0.36 -0.98,0.85c-0.36,2.08 -2,3.72 -4.08,4.08C3.39,8.04 3.03,8.44 3.03,8.94l0,0c0,0.61 0.54,1.09 1.14,1c2.96,-0.48 5.29,-2.81 5.77,-5.77C10.03,3.56 9.54,3.02 8.94,3.02L8.94,3.02z"/>
+ android:pathData="M11.05,21c0.5,0 0.94,-0.37 0.99,-0.87 0.41,-4.27 3.81,-7.67 8.08,-8.08 0.5,-0.05 0.88,-0.48 0.88,-0.99 0,-0.59 -0.51,-1.06 -1.1,-1 -5.19,0.52 -9.32,4.65 -9.84,9.83 -0.06,0.59 0.4,1.11 0.99,1.11zM18,21h3v-3c-1.66,0 -3,1.34 -3,3zM15.09,21c0.49,0 0.9,-0.36 0.98,-0.85 0.36,-2.08 2,-3.72 4.08,-4.08 0.49,-0.08 0.85,-0.49 0.85,-0.98 0,-0.61 -0.54,-1.09 -1.14,-1 -2.96,0.48 -5.29,2.81 -5.77,5.77 -0.1,0.6 0.39,1.14 1,1.14zM12.97,3.02c-0.5,0 -0.94,0.37 -0.99,0.87 -0.41,4.27 -3.81,7.67 -8.08,8.08 -0.5,0.05 -0.88,0.48 -0.88,0.99 0,0.59 0.51,1.06 1.1,1 5.19,-0.52 9.32,-4.65 9.84,-9.83 0.07,-0.58 -0.39,-1.11 -0.99,-1.11zM6.03,3.02h-3v3c1.66,0 3,-1.34 3,-3zM8.94,3.02c-0.49,0 -0.9,0.36 -0.98,0.85 -0.36,2.08 -2,3.72 -4.08,4.08 -0.49,0.09 -0.85,0.49 -0.85,0.99 0,0.61 0.54,1.09 1.14,1 2.96,-0.48 5.29,-2.81 5.77,-5.77 0.09,-0.61 -0.4,-1.15 -1,-1.15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/leak_remove.xml b/compose/material/material/icons/generator/raw-icons/rounded/leak_remove.xml
index 02ac12e..6915ae9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/leak_remove.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/leak_remove.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.06,9.23c1.02,-1.48 1.69,-3.23 1.88,-5.11C14,3.52 13.54,3 12.94,3h0c-0.5,0 -0.94,0.38 -0.99,0.88c-0.14,1.43 -0.62,2.75 -1.34,3.91L12.06,9.23z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.87,14.09c-0.79,0.13 -1.53,0.39 -2.21,0.75l1.51,1.51c0.31,-0.12 0.63,-0.22 0.97,-0.28c0.49,-0.09 0.85,-0.49 0.85,-0.98v-0.01C21,14.48 20.47,13.99 19.87,14.09z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.22,13.39c1.15,-0.73 2.48,-1.2 3.91,-1.34c0.5,-0.05 0.88,-0.48 0.88,-0.99v0c0,-0.6 -0.52,-1.06 -1.12,-1c-1.89,0.19 -3.63,0.86 -5.11,1.88L16.22,13.39z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l2.72,2.72C4.51,7.77 4.19,7.86 3.85,7.92C3.37,8.01 3,8.41 3,8.91v0.01c0,0.6 0.53,1.09 1.13,0.99c0.79,-0.13 1.53,-0.38 2.21,-0.75l1.45,1.45c-1.15,0.73 -2.48,1.2 -3.91,1.34C3.38,12.01 3,12.44 3,12.94v0c0,0.6 0.52,1.06 1.12,1c1.89,-0.19 3.63,-0.86 5.12,-1.88l2.71,2.71c-1.02,1.48 -1.69,3.23 -1.89,5.11c-0.06,0.59 0.4,1.12 1,1.12h0c0.5,0 0.94,-0.38 0.99,-0.88c0.14,-1.43 0.62,-2.75 1.34,-3.91l1.45,1.45c-0.37,0.68 -0.62,1.42 -0.75,2.21c-0.1,0.59 0.39,1.13 0.99,1.13h0.01c0.49,0 0.9,-0.37 0.98,-0.85c0.06,-0.33 0.16,-0.66 0.28,-0.97l2.72,2.72c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.16,6.33c0.37,-0.68 0.62,-1.42 0.75,-2.21C10.01,3.53 9.52,3 8.92,3H8.91c-0.49,0 -0.9,0.37 -0.98,0.85C7.86,4.19 7.77,4.51 7.65,4.82L9.16,6.33z"/>
+ android:pathData="M20.12,12.04c0.5,-0.05 0.88,-0.48 0.88,-0.99 0,-0.59 -0.51,-1.06 -1.1,-1 -1.5,0.15 -2.9,0.61 -4.16,1.3l1.48,1.48c0.9,-0.41 1.87,-0.69 2.9,-0.79zM21,15.09c0,-0.61 -0.54,-1.09 -1.14,-1 -0.38,0.06 -0.75,0.16 -1.11,0.28l1.62,1.62c0.37,-0.15 0.63,-0.49 0.63,-0.9zM13.97,4.14c0.06,-0.59 -0.4,-1.11 -1,-1.11 -0.5,0 -0.94,0.37 -0.99,0.87 -0.1,1.03 -0.38,2.01 -0.79,2.91l1.48,1.48c0.69,-1.26 1.15,-2.66 1.3,-4.15zM9.93,4.16c0.1,-0.6 -0.39,-1.14 -1,-1.14 -0.41,0 -0.75,0.26 -0.9,0.62l1.62,1.62c0.13,-0.35 0.22,-0.72 0.28,-1.1zM20.44,18.88L5.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.15,2.15c-0.59,0.41 -1.26,0.7 -1.99,0.82 -0.48,0.1 -0.84,0.5 -0.84,1 0,0.61 0.54,1.09 1.14,1 1.17,-0.19 2.23,-0.68 3.13,-1.37L8.73,10c-1.34,1.1 -3,1.82 -4.81,1.99 -0.5,0.05 -0.88,0.48 -0.88,0.99 0,0.59 0.51,1.06 1.1,1 2.28,-0.23 4.36,-1.15 6.01,-2.56l2.48,2.48c-1.4,1.65 -2.33,3.72 -2.56,6 -0.06,0.59 0.4,1.11 1,1.11 0.5,0 0.94,-0.37 0.99,-0.87 0.18,-1.82 0.9,-3.48 1.99,-4.82l1.43,1.43c-0.69,0.9 -1.18,1.96 -1.37,3.13 -0.1,0.6 0.39,1.14 1,1.14 0.49,0 0.9,-0.36 0.98,-0.85 0.12,-0.73 0.42,-1.4 0.82,-1.99l2.13,2.13c0.39,0.39 1.02,0.39 1.41,0 0.38,-0.41 0.38,-1.04 -0.01,-1.43z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/lens.xml b/compose/material/material/icons/generator/raw-icons/rounded/lens.xml
index 8df4c8a..e45ef6c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/lens.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/lens.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/library_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/library_add.xml
index fe89126..1fee4b6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/library_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/library_add.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,11h-2v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-2h-2c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h2V7c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2h2c0.55,0 1,0.45 1,1v0C18,10.55 17.55,11 17,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M3,6c-0.55,0 -1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,11h-3v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3L13,6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/library_add_check.xml b/compose/material/material/icons/generator/raw-icons/rounded/library_add_check.xml
index 0621e85..4cdac86 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/library_add_check.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/library_add_check.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20zM20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17.89,8.59l-4.24,4.24c-0.39,0.39 -1.02,0.39 -1.41,0l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41h0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0C18.28,7.56 18.28,8.2 17.89,8.59z"/>
+ android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM11.76,13.28L9.69,11.2c-0.38,-0.39 -0.38,-1.01 0,-1.4l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.36,1.37l4.42,-4.46c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.38,0.39 0.38,1.01 0,1.4l-5.13,5.17C12.79,13.68 12.15,13.68 11.76,13.28zM3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,-0.45 -1,-1V7C4,6.45 3.55,6 3,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/library_books.xml b/compose/material/material/icons/generator/raw-icons/rounded/library_books.xml
index f0bc21c..6c88dc9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/library_books.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/library_books.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM13,14h-2c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1v0C14,13.55 13.55,14 13,14zM17,11h-6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v0C18,10.55 17.55,11 17,11zM17,8h-6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v0C18,7.55 17.55,8 17,8z"/>
+ android:pathData="M3,6c-0.55,0 -1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,11h-8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM14,15h-4c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h4c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM18,7h-8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/library_music.xml b/compose/material/material/icons/generator/raw-icons/rounded/library_music.xml
index 56c4029..f25c106 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/library_music.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/library_music.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,7h-2v5.37c0,1.27 -0.9,2.44 -2.16,2.6c-1.69,0.23 -3.11,-1.25 -2.8,-2.95c0.2,-1.1 1.18,-1.95 2.3,-2.02c0.63,-0.04 1.2,0.16 1.66,0.51V6c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1l0,0C18,6.55 17.55,7 17,7zM3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM17,7h-2v5.37c0,1.27 -0.9,2.44 -2.16,2.6 -1.69,0.23 -3.11,-1.25 -2.8,-2.95 0.2,-1.1 1.18,-1.95 2.3,-2.02 0.63,-0.04 1.2,0.16 1.66,0.51L14,6c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM3,6c-0.55,0 -1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/line_style.xml b/compose/material/material/icons/generator/raw-icons/rounded/line_style.xml
index e3c69e2..1e37632 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/line_style.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/line_style.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,16h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,16 4,16zM10.5,16h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1S9.95,16 10.5,16zM17,16h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1S16.45,16 17,16zM4,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S3.45,20 4,20zM8,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S7.45,20 8,20zM12,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S11.45,20 12,20zM16,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S15.45,20 16,20zM20,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S19.45,20 20,20zM4,12h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,12 4,12zM14,12h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1S13.45,12 14,12zM3,5v2c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1H4C3.45,4 3,4.45 3,5z"/>
+ android:pathData="M4,16h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM10.5,16h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM17,16h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM8,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM12,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM16,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM20,20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM4,12h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM14,12h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,5v2c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1L21,5c0,-0.55 -0.45,-1 -1,-1L4,4c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/line_weight.xml b/compose/material/material/icons/generator/raw-icons/rounded/line_weight.xml
index bb9ab33..0f2ef16 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/line_weight.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/line_weight.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15H4c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1S20.55,15 20,15zM20,10H4c-0.55,0 -1,0.45 -1,1v1c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-1C21,10.45 20.55,10 20,10zM20,4H4C3.45,4 3,4.45 3,5v2c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1V5C21,4.45 20.55,4 20,4zM20.5,19h-17C3.22,19 3,19.22 3,19.5S3.22,20 3.5,20h17c0.28,0 0.5,-0.22 0.5,-0.5S20.78,19 20.5,19z"/>
+ android:pathData="M20,15L4,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM20,10L4,10c-0.55,0 -1,0.45 -1,1v1c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-1c0,-0.55 -0.45,-1 -1,-1zM20,4L4,4c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1L21,5c0,-0.55 -0.45,-1 -1,-1zM20.5,19h-17c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h17c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/list.xml b/compose/material/material/icons/generator/raw-icons/rounded/list.xml
index c899588d..8ddb03c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/list.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/list.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S3.45,13 4,13zM4,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1C3,16.55 3.45,17 4,17zM4,9c0.55,0 1,-0.45 1,-1S4.55,7 4,7S3,7.45 3,8S3.45,9 4,9zM8,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8c-0.55,0 -1,0.45 -1,1S7.45,13 8,13zM8,17h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8c-0.55,0 -1,0.45 -1,1C7,16.55 7.45,17 8,17zM7,8c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8C7.45,7 7,7.45 7,8zM4,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S3.45,13 4,13zM4,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1C3,16.55 3.45,17 4,17zM4,9c0.55,0 1,-0.45 1,-1S4.55,7 4,7S3,7.45 3,8S3.45,9 4,9zM8,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8c-0.55,0 -1,0.45 -1,1S7.45,13 8,13zM8,17h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8c-0.55,0 -1,0.45 -1,1C7,16.55 7.45,17 8,17zM7,8c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H8C7.45,7 7,7.45 7,8z"/>
+ android:pathData="M4,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM4,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM4,9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM8,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM8,17h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM7,8c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,7c-0.55,0 -1,0.45 -1,1zM4,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM4,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM4,9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM8,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM8,17h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM7,8c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,7c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/list_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/list_alt.xml
index 026b017..72b604f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/list_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/list_alt.xml
@@ -7,23 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,9h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1S11.45,9 12,9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,13h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1S11.45,13 12,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,17h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1S11.45,17 12,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8,8m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8,12m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"/>
+ android:pathData="M12,9h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM12,13h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM12,17h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM7,7h2v2L7,9zM7,11h2v2L7,13zM7,15h2v2L7,17zM20,3L4,3c-0.55,0 -1,0.45 -1,1v16c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1zM19,19L5,19L5,5h14v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/live_help.xml b/compose/material/material/icons/generator/raw-icons/rounded/live_help.xml
index e26ebf0..ec129a3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/live_help.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/live_help.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,2H5C3.89,2 3,2.9 3,4v14c0,1.1 0.9,2 2,2h4l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0L15,20h4c1.1,0 2,-0.9 2,-2V4C21,2.9 20.1,2 19,2zM12.01,17c-0.7,0 -1.26,-0.56 -1.26,-1.26c0,-0.71 0.56,-1.25 1.26,-1.25c0.71,0 1.25,0.54 1.25,1.25C13.25,16.43 12.72,17 12.01,17zM15.02,9.6c-0.76,1.11 -1.48,1.46 -1.87,2.17c-0.1,0.18 -0.16,0.32 -0.19,0.62c-0.05,0.46 -0.45,0.79 -0.91,0.79h0c-0.54,0 -0.98,-0.46 -0.92,-1c0.03,-0.32 0.11,-0.67 0.29,-0.98c0.49,-0.87 1.42,-1.39 1.96,-2.16c0.57,-0.81 0.25,-2.33 -1.37,-2.33c-0.71,0 -1.18,0.36 -1.47,0.79c-0.25,0.36 -0.69,0.53 -1.1,0.36l0,0C8.91,7.64 8.72,7 9.04,6.54C9.65,5.65 10.67,5 11.99,5c1.48,0 2.49,0.67 3.01,1.52C15.44,7.24 15.7,8.59 15.02,9.6z"/>
+ android:pathData="M19,2L5,2c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h4l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0L15,20h4c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM13,18h-2v-2h2v2zM15.07,10.25l-0.9,0.92c-0.58,0.59 -0.99,1.1 -1.12,2.06 -0.06,0.43 -0.41,0.76 -0.85,0.76h-0.31c-0.52,0 -0.92,-0.46 -0.85,-0.98 0.11,-0.91 0.53,-1.72 1.14,-2.34l1.24,-1.26c0.36,-0.36 0.58,-0.86 0.58,-1.41 0,-1.1 -0.9,-2 -2,-2 -0.87,0 -1.62,0.57 -1.89,1.35 -0.13,0.37 -0.44,0.64 -0.83,0.64h-0.3c-0.58,0 -0.98,-0.56 -0.82,-1.12C8.65,5.21 10.18,4 12,4c2.21,0 4,1.79 4,4 0,0.88 -0.36,1.68 -0.93,2.25z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/live_tv.xml b/compose/material/material/icons/generator/raw-icons/rounded/live_tv.xml
index 82b73d0..699353e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/live_tv.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/live_tv.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h4c1.1,0 1.99,-0.9 1.99,-2L22,5C22,3.9 21.1,3 20,3zM20,17H4V5h16V17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.5,8.33v5.34c0,0.79 0.88,1.27 1.54,0.84l4.15,-2.67c0.61,-0.39 0.61,-1.29 0,-1.68l-4.15,-2.67C10.38,7.06 9.5,7.54 9.5,8.33z"/>
+ android:pathData="M10.5,17.15l3.98,-2.28c0.67,-0.38 0.67,-1.35 0,-1.74l-3.98,-2.28c-0.67,-0.38 -1.5,0.11 -1.5,0.87v4.55c0,0.77 0.83,1.26 1.5,0.88zM21,6h-7.59l2.94,-2.94c0.2,-0.2 0.2,-0.51 0,-0.71s-0.51,-0.2 -0.71,0L12,5.99 8.36,2.35c-0.2,-0.2 -0.51,-0.2 -0.71,0s-0.2,0.51 0,0.71L10.59,6L3,6c-1.1,0 -2,0.89 -2,2v12c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,8c0,-1.11 -0.9,-2 -2,-2zM20,20L4,20c-0.55,0 -1,-0.45 -1,-1L3,9c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_activity.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_activity.xml
index 2efedf6..8348734 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_activity.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_activity.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,10V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2.01,4.9 2.01,6v4C3.11,10 4,10.9 4,12s-0.89,2 -2,2v4c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-4c-1.1,0 -2,-0.9 -2,-2S20.9,10 22,10zM15.38,11.27l-1.66,1.32l0.6,1.92c0.14,0.46 -0.39,0.84 -0.78,0.55L12,13.89l-1.54,1.17c-0.39,0.29 -0.92,-0.08 -0.78,-0.55l0.6,-1.92l-1.66,-1.32c-0.37,-0.29 -0.16,-0.89 0.31,-0.89h1.98l0.62,-1.9c0.15,-0.46 0.8,-0.46 0.95,0l0.62,1.9h1.98C15.54,10.38 15.75,10.97 15.38,11.27z"/>
+ android:pathData="M20,12c0,-0.76 0.43,-1.42 1.06,-1.76 0.6,-0.33 0.94,-1.01 0.94,-1.7L22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -1.99,0.89 -1.99,1.99v2.55c0,0.69 0.33,1.37 0.94,1.69C3.58,10.58 4,11.24 4,12s-0.43,1.43 -1.06,1.76c-0.6,0.33 -0.94,1.01 -0.94,1.7L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-2.54c0,-0.69 -0.34,-1.37 -0.94,-1.7 -0.63,-0.34 -1.06,-1 -1.06,-1.76zM14.5,16.1L12,14.5l-2.5,1.61c-0.38,0.24 -0.87,-0.11 -0.75,-0.55l0.75,-2.88 -2.3,-1.88c-0.35,-0.29 -0.17,-0.86 0.29,-0.89l2.96,-0.17 1.08,-2.75c0.17,-0.42 0.77,-0.42 0.93,0l1.08,2.76 2.96,0.17c0.45,0.03 0.64,0.6 0.29,0.89l-2.3,1.88 0.76,2.86c0.12,0.45 -0.37,0.8 -0.75,0.55z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_airport.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_airport.xml
index 7a6c65f..360739c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_airport.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_airport.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,14.6L22,14.6c0,-0.37 -0.2,-0.72 -0.52,-0.9L13.5,9l0,-5.42c0,-0.81 -0.61,-1.54 -1.42,-1.58c-0.87,-0.04 -1.58,0.64 -1.58,1.5V9l-7.98,4.7C2.2,13.88 2,14.23 2,14.6v0c0,0.7 0.67,1.2 1.34,1.01l7.16,-2.1V19l-1.67,1.25c-0.21,0.16 -0.33,0.4 -0.33,0.66l0,0c0,0.55 0.52,0.94 1.05,0.79L12,21l2.45,0.7c0.52,0.15 1.05,-0.24 1.05,-0.79l0,0c0,-0.26 -0.12,-0.5 -0.33,-0.66L13.5,19v-5.5l7.16,2.1C21.33,15.8 22,15.3 22,14.6z"/>
+ android:pathData="M21.48,13.7L13.5,9V3.5C13.5,2.67 12.83,2 12,2c-0.83,0 -1.5,0.67 -1.5,1.5V9l-7.98,4.7C2.2,13.88 2,14.23 2,14.6c0,0.7 0.67,1.2 1.34,1.01l7.16,-2.1V19l-2.26,1.35C8.09,20.44 8,20.61 8,20.78l0,0.5h0v0.08c0,0.33 0.31,0.57 0.62,0.49l2.92,-0.73L12,21l0.38,0.09c0,0 0,0 0,0l0.42,0.11l1.9,0.48l0,0l0.67,0.17c0.32,0.08 0.62,-0.16 0.62,-0.49v-0.37c0,0 0,0 0,0v-0.21c0,-0.18 -0.09,-0.34 -0.24,-0.43L13.5,19v-5.5l7.16,2.1C21.33,15.8 22,15.3 22,14.6C22,14.23 21.8,13.88 21.48,13.7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_atm.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_atm.xml
index 8c10440..978789c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_atm.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_atm.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2.01,4.89 2.01,6L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6C22,4.89 21.11,4 20,4zM14,11c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1h-1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1h-1c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3v-1h-3c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1h1V7.99c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V8h1c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-3v1H14z"/>
+ android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,17c0,0.55 -0.45,1 -1,1L5,18c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v10zM14,10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-0.01c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1L11,8h-1c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3v1h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1c0,0.55 0.45,1 1,1s1,-0.45 1,-1h1c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1h-3v-1h3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_bar.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_bar.xml
index f703d2e..ccb05ce 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_bar.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_bar.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,4.45L21,4.45C21,3.65 20.35,3 19.55,3H4.45C3.65,3 3,3.65 3,4.45l0,0c0,0.35 0.13,0.7 0.37,0.96L11,14v5H7c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-4v-5l7.63,-8.59C20.87,5.15 21,4.8 21,4.45zM7.43,7L5.66,5h12.69l-1.78,2H7.43z"/>
+ android:pathData="M21,4.45c0,-0.8 -0.65,-1.45 -1.45,-1.45H4.45C3.65,3 3,3.65 3,4.45c0,0.35 0.13,0.7 0.37,0.96L11,14v5H7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4v-5l7.63,-8.59c0.24,-0.26 0.37,-0.61 0.37,-0.96zM7.43,7L5.66,5h12.69l-1.78,2H7.43z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_cafe.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_cafe.xml
index 5d4447e..cb57dd5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_cafe.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_cafe.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H6C4.9,3 4,3.9 4,5v8c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.11,0 2,-0.9 2,-2V5C22,3.9 21.1,3 20,3zM20,8h-2V5h2V8zM5,19h14c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1l0,0C4,19.45 4.45,19 5,19z"/>
+ android:pathData="M20,3L6,3c-1.1,0 -2,0.9 -2,2v8c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.1,0 2,-0.9 2,-2L22,5c0,-1.1 -0.9,-2 -2,-2zM20,8h-2L18,5h2v3zM3,21h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_car_wash.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_car_wash.xml
index 9b72d7f1..ddfb2a1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_car_wash.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_car_wash.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,5c0.83,0 1.5,-0.64 1.5,-1.43c0,-0.64 -0.67,-1.57 -1.11,-2.12c-0.2,-0.25 -0.57,-0.25 -0.77,0C11.17,2 10.5,2.94 10.5,3.57C10.5,4.36 11.17,5 12,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,5c0.83,0 1.5,-0.64 1.5,-1.43c0,-0.64 -0.67,-1.57 -1.11,-2.12c-0.2,-0.25 -0.57,-0.25 -0.77,0C16.17,2 15.5,2.94 15.5,3.57C15.5,4.36 16.17,5 17,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,5c0.83,0 1.5,-0.67 1.5,-1.5c0,-0.67 -0.68,-1.57 -1.12,-2.09c-0.2,-0.23 -0.55,-0.23 -0.75,0C6.18,1.93 5.5,2.83 5.5,3.5C5.5,4.33 6.17,5 7,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.92,8.01C18.72,7.42 18.16,7 17.5,7h-11C5.84,7 5.29,7.42 5.08,8.01L3,14v7.5C3,22.32 3.67,23 4.5,23S6,22.32 6,21.5V21h12v0.5c0,0.82 0.67,1.5 1.5,1.5s1.5,-0.68 1.5,-1.5V14L18.92,8.01zM7.5,18C6.67,18 6,17.33 6,16.5S6.67,15 7.5,15S9,15.67 9,16.5S8.33,18 7.5,18zM16.5,18c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S17.33,18 16.5,18zM5.81,12l1.04,-3h10.29l1.04,3H5.81z"/>
+ android:pathData="M17,5c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.66 -0.66,-1.64 -1.11,-2.22 -0.2,-0.26 -0.59,-0.26 -0.79,0 -0.44,0.58 -1.1,1.56 -1.1,2.22 0,0.83 0.67,1.5 1.5,1.5zM12,5c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.66 -0.66,-1.64 -1.11,-2.22 -0.2,-0.26 -0.59,-0.26 -0.79,0 -0.44,0.58 -1.1,1.56 -1.1,2.22 0,0.83 0.67,1.5 1.5,1.5zM7,5c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.66 -0.66,-1.64 -1.11,-2.22 -0.2,-0.26 -0.59,-0.26 -0.79,0 -0.44,0.58 -1.1,1.56 -1.1,2.22C5.5,4.33 6.17,5 7,5zM18.92,8.01C18.72,7.42 18.16,7 17.5,7h-11c-0.66,0 -1.21,0.42 -1.42,1.01l-1.97,5.67c-0.07,0.21 -0.11,0.43 -0.11,0.66v7.16c0,0.83 0.67,1.5 1.5,1.5S6,22.33 6,21.5L6,21h12v0.5c0,0.82 0.67,1.5 1.5,1.5 0.82,0 1.5,-0.67 1.5,-1.5v-7.16c0,-0.22 -0.04,-0.45 -0.11,-0.66l-1.97,-5.67zM6.5,18c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,15 6.5,15s1.5,0.67 1.5,1.5S7.33,18 6.5,18zM17.5,18c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,13l1.27,-3.82c0.14,-0.4 0.52,-0.68 0.95,-0.68h9.56c0.43,0 0.81,0.28 0.95,0.68L19,13L5,13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_dining.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_dining.xml
index 96e0a63..3e84bb2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_dining.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_dining.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.41,12l1.26,-1.26c1.4,0.6 3.32,0.14 4.75,-1.3c1.75,-1.75 2.09,-4.27 0.74,-5.62c-1.34,-1.34 -3.85,-1.01 -5.62,0.74c-1.43,1.43 -1.9,3.36 -1.29,4.76l-9.55,9.55c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,13.41l6.88,6.88c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7.34,12.42l3.21,-3.21l-5.4,-5.4C4.67,3.34 3.87,3.45 3.55,4.04C2.61,5.76 2.87,7.96 4.33,9.41L7.34,12.42z"/>
+ android:pathData="M8.1,13.34l2.83,-2.83 -6.19,-6.18c-0.48,-0.48 -1.31,-0.35 -1.61,0.27 -0.71,1.49 -0.45,3.32 0.78,4.56l4.19,4.18zM14.88,11.53c1.53,0.71 3.68,0.21 5.27,-1.38 1.91,-1.91 2.28,-4.65 0.81,-6.12 -1.46,-1.46 -4.2,-1.1 -6.12,0.81 -1.59,1.59 -2.09,3.74 -1.38,5.27l-9.05,9.05c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,14.41l6.18,6.18c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,13l1.47,-1.47z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_drink.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_drink.xml
index abe1d64..b0fd704 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_drink.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_drink.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.12,2c-0.6,0 -1.06,0.52 -0.99,1.11l1.89,17.12C5.13,21.23 5.97,22 7,22h10c1.03,0 1.87,-0.77 1.99,-1.77l1.89,-17.12C20.94,2.52 20.48,2 19.88,2H4.12zM12,19c-1.58,0 -2.86,-1.28 -2.86,-2.86c0,-1.24 1.22,-3.06 2.07,-4.17c0.4,-0.52 1.18,-0.52 1.58,0c0.85,1.11 2.07,2.92 2.07,4.17C14.86,17.72 13.58,19 12,19zM18.33,8H5.67L5.23,4h13.53L18.33,8z"/>
+ android:pathData="M5.23,2C4.04,2 3.11,3.04 3.24,4.22l1.77,16.01C5.13,21.23 5.97,22 7,22h10c1.03,0 1.87,-0.77 1.99,-1.77l1.77,-16.01c0.13,-1.18 -0.8,-2.22 -1.99,-2.22L5.23,2zM12,19c-1.66,0 -3,-1.34 -3,-3 0,-1.55 1.81,-3.95 2.62,-4.94 0.2,-0.25 0.57,-0.25 0.77,0 0.81,1 2.62,3.39 2.62,4.94 -0.01,1.66 -1.35,3 -3.01,3zM18.33,8L5.67,8l-0.32,-2.89c-0.06,-0.59 0.4,-1.11 1,-1.11h11.3c0.59,0 1.06,0.52 0.99,1.11L18.33,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_florist.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_florist.xml
index 0743a17..42bd051 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_florist.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_florist.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,22c4.56,0 8.33,-3.4 8.92,-7.8c0.09,-0.64 -0.48,-1.21 -1.12,-1.12C15.4,13.67 12,17.44 12,22zM5.6,10.25c0,1.38 1.12,2.5 2.5,2.5c0.53,0 1.01,-0.16 1.42,-0.44L9.5,12.5c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5l-0.02,-0.19c0.4,0.28 0.89,0.44 1.42,0.44c1.38,0 2.5,-1.12 2.5,-2.5c0,-1 -0.59,-1.85 -1.43,-2.25c0.84,-0.4 1.43,-1.25 1.43,-2.25c0,-1.38 -1.12,-2.5 -2.5,-2.5c-0.53,0 -1.01,0.16 -1.42,0.44L14.5,3.5C14.5,2.12 13.38,1 12,1S9.5,2.12 9.5,3.5l0.02,0.19C9.12,3.41 8.63,3.25 8.1,3.25c-1.38,0 -2.5,1.12 -2.5,2.5c0,1 0.59,1.85 1.43,2.25C6.19,8.4 5.6,9.25 5.6,10.25zM12,5.5c1.38,0 2.5,1.12 2.5,2.5s-1.12,2.5 -2.5,2.5S9.5,9.38 9.5,8S10.62,5.5 12,5.5zM3.08,14.2C3.67,18.6 7.44,22 12,22c0,-4.56 -3.4,-8.33 -7.8,-8.92C3.56,12.99 2.99,13.56 3.08,14.2z"/>
+ android:pathData="M12,22c4.56,0 8.33,-3.4 8.92,-7.8 0.09,-0.64 -0.48,-1.21 -1.12,-1.12 -4.4,0.59 -7.8,4.36 -7.8,8.92zM5.6,10.25c0,1.38 1.12,2.5 2.5,2.5 0.53,0 1.01,-0.16 1.42,-0.44l-0.02,0.19c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5l-0.02,-0.19c0.4,0.28 0.89,0.44 1.42,0.44 1.38,0 2.5,-1.12 2.5,-2.5 0,-1 -0.59,-1.85 -1.43,-2.25 0.84,-0.4 1.43,-1.25 1.43,-2.25 0,-1.38 -1.12,-2.5 -2.5,-2.5 -0.53,0 -1.01,0.16 -1.42,0.44l0.02,-0.19C14.5,2.12 13.38,1 12,1S9.5,2.12 9.5,3.5l0.02,0.19c-0.4,-0.28 -0.89,-0.44 -1.42,-0.44 -1.38,0 -2.5,1.12 -2.5,2.5 0,1 0.59,1.85 1.43,2.25 -0.84,0.4 -1.43,1.25 -1.43,2.25zM12,5.5c1.38,0 2.5,1.12 2.5,2.5s-1.12,2.5 -2.5,2.5S9.5,9.38 9.5,8s1.12,-2.5 2.5,-2.5zM3.08,14.2C3.67,18.6 7.44,22 12,22c0,-4.56 -3.4,-8.33 -7.8,-8.92 -0.64,-0.09 -1.21,0.48 -1.12,1.12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_gas_station.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_gas_station.xml
index dd42333..c20adae 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_gas_station.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_gas_station.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.77,7.23l0.01,-0.01l-3.19,-3.19c-0.29,-0.29 -0.77,-0.29 -1.06,0l0,0c-0.29,0.29 -0.29,0.77 0,1.06l1.58,1.58c-1.05,0.4 -1.76,1.47 -1.58,2.71c0.16,1.1 1.1,1.99 2.2,2.11c0.47,0.05 0.88,-0.03 1.27,-0.2v7.21c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V14c0,-1.1 -0.9,-2 -2,-2h-1V5c0,-1.1 -0.9,-2 -2,-2H6C4.9,3 4,3.9 4,5v15c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-6.5h1.5v4.86c0,1.31 0.94,2.5 2.24,2.63c1.5,0.15 2.76,-1.02 2.76,-2.49V9C20.5,8.31 20.22,7.68 19.77,7.23zM12,10H6V5h6V10zM18,10c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S18.55,10 18,10z"/>
+ android:pathData="M19.77,7.23l0.01,-0.01 -3.19,-3.19c-0.29,-0.29 -0.77,-0.29 -1.06,0 -0.29,0.29 -0.29,0.77 0,1.06l1.58,1.58c-1.05,0.4 -1.76,1.47 -1.58,2.71 0.16,1.1 1.1,1.99 2.2,2.11 0.47,0.05 0.88,-0.03 1.27,-0.2v7.21c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L17,14c0,-1.1 -0.9,-2 -2,-2h-1L14,5c0,-1.1 -0.9,-2 -2,-2L6,3c-1.1,0 -2,0.9 -2,2v15c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-6.5h1.5v4.86c0,1.31 0.94,2.5 2.24,2.63 1.5,0.15 2.76,-1.02 2.76,-2.49L20.5,9c0,-0.69 -0.28,-1.32 -0.73,-1.77zM12,10L6,10L6,6c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1v4zM18,10c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_grocery_store.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_grocery_store.xml
index cbf0397..d3cb399 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_grocery_store.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_grocery_store.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.55,13c1.22,0 1.74,-1.01 1.75,-1.03l3.55,-6.44c0.23,-0.45 0.18,-0.84 -0.01,-1.11C20.66,4.16 20.33,4 20,4C19.99,4 5.21,4 5.21,4L4.54,2.57C4.38,2.22 4.02,2 3.64,2H2C1.45,2 1,2.45 1,3v0c0,0.55 0.45,1 1,1h1l3.6,7.59l-1.35,2.44C4.52,15.37 5.48,17 7,17h11c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H7l1.1,-2H15.55z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,20m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2zM2,4h1l3.6,7.59 -1.35,2.44C4.52,15.37 5.48,17 7,17h11c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L7,15l1.1,-2h7.45c0.75,0 1.41,-0.41 1.75,-1.03l3.58,-6.49c0.37,-0.66 -0.11,-1.48 -0.87,-1.48L5.21,4l-0.67,-1.43c-0.16,-0.35 -0.52,-0.57 -0.9,-0.57L2,2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM17,18c-1.1,0 -1.99,0.9 -1.99,2s0.89,2 1.99,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_hospital.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_hospital.xml
index ae07a43..4f59c4f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_hospital.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_hospital.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3.01,3.9 3.01,5L3,19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM15.5,13.5h-2v2c0,0.83 -0.67,1.5 -1.5,1.5h0c-0.83,0 -1.5,-0.67 -1.5,-1.5v-2h-2C7.67,13.5 7,12.83 7,12v0c0,-0.83 0.67,-1.5 1.5,-1.5h2v-2C10.5,7.67 11.17,7 12,7h0c0.83,0 1.5,0.67 1.5,1.5v2h2c0.83,0 1.5,0.67 1.5,1.5v0C17,12.83 16.33,13.5 15.5,13.5z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM17,14h-3v3c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,-0.45 -1,-1v-3L7,14c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1h3L10,7c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1v3h3c0.55,0 1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_hotel.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_hotel.xml
index 49ff962..cda81ef 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_hotel.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_hotel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,14c1.66,0 3,-1.34 3,-3S8.66,8 7,8s-3,1.34 -3,3S5.34,14 7,14zM19,7h-6c-1.1,0 -2,0.9 -2,2v6H3V6c0,-0.55 -0.45,-1 -1,-1l0,0C1.45,5 1,5.45 1,6v13c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-2h18v2c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-8C23,8.79 21.21,7 19,7z"/>
+ android:pathData="M7,13c1.66,0 3,-1.34 3,-3S8.66,7 7,7s-3,1.34 -3,3 1.34,3 3,3zM19,7h-6c-1.1,0 -2,0.9 -2,2v5L3,14L3,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v13c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h18v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-8c0,-2.21 -1.79,-4 -4,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_library.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_library.xml
index 4a1fc6ee..8ba3a08 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_library.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_library.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,9c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4S8,2.79 8,5S9.79,9 12,9zM12,11.55c-1.82,-1.7 -4.12,-2.89 -6.68,-3.35C4.11,7.99 3,8.95 3,10.18v6.92c0,1 0.72,1.88 1.71,2c2.25,0.28 4.32,1.12 6.07,2.39c0.73,0.53 1.7,0.53 2.44,0c1.75,-1.27 3.82,-2.11 6.07,-2.39c0.99,-0.13 1.71,-1.01 1.71,-2v-6.92c0,-1.23 -1.11,-2.2 -2.32,-1.98C16.12,8.66 13.82,9.85 12,11.55z"/>
+ android:pathData="M12,11.55c-1.82,-1.7 -4.12,-2.89 -6.68,-3.35C4.11,7.99 3,8.95 3,10.18v6.24c0,1.68 0.72,2.56 1.71,2.69 2.5,0.32 4.77,1.35 6.63,2.87 0.35,0.29 0.92,0.32 1.27,0.04 1.87,-1.53 4.16,-2.58 6.68,-2.9 0.94,-0.13 1.71,-1.06 1.71,-2.02v-6.92c0,-1.23 -1.11,-2.19 -2.32,-1.98 -2.56,0.46 -4.86,1.65 -6.68,3.35zM12,8c1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3 1.34,3 3,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_mall.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_mall.xml
index c3eb8f5..a292c6f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_mall.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_mall.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,6h-2c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6H5C3.9,6 3,6.9 3,8v12c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V8C21,6.9 20.1,6 19,6zM12,3c1.66,0 3,1.34 3,3H9C9,4.34 10.34,3 12,3zM12,14c-2.33,0 -4.29,-1.59 -4.84,-3.75C6.99,9.62 7.48,9 8.13,9l0,0C8.6,9 8.98,9.34 9.11,9.8C9.46,11.07 10.62,12 12,12s2.54,-0.93 2.89,-2.2C15.02,9.34 15.4,9 15.87,9l0,0c0.65,0 1.13,0.62 0.97,1.25C16.29,12.41 14.33,14 12,14z"/>
+ android:pathData="M19,6h-2c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6L5,6c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,8c0,-1.1 -0.9,-2 -2,-2zM12,3c1.66,0 3,1.34 3,3L9,6c0,-1.66 1.34,-3 3,-3zM12,13c-2.33,0 -4.29,-1.59 -4.84,-3.75 -0.17,-0.63 0.32,-1.25 0.97,-1.25 0.47,0 0.85,0.34 0.98,0.8 0.35,1.27 1.51,2.2 2.89,2.2s2.54,-0.93 2.89,-2.2c0.13,-0.46 0.51,-0.8 0.98,-0.8 0.65,0 1.13,0.62 0.97,1.25C16.29,11.41 14.33,13 12,13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_movies.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_movies.xml
index f0d6236..3fe1f95 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_movies.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_movies.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,4v1h-2V4c0,-0.55 -0.45,-1 -1,-1H9C8.45,3 8,3.45 8,4v1H6V4c0,-0.55 -0.45,-1 -1,-1S4,3.45 4,4v16c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1S18,3.45 18,4zM8,17H6v-2h2V17zM8,13H6v-2h2V13zM8,9H6V7h2V9zM18,17h-2v-2h2V17zM18,13h-2v-2h2V13zM18,9h-2V7h2V9z"/>
+ android:pathData="M18,4v1h-2L16,4c0,-0.55 -0.45,-1 -1,-1L9,3c-0.55,0 -1,0.45 -1,1v1L6,5L6,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v16c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1L20,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM8,17L6,17v-2h2v2zM8,13L6,13v-2h2v2zM8,9L6,9L6,7h2v2zM18,17h-2v-2h2v2zM18,13h-2v-2h2v2zM18,9h-2L16,7h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_offer.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_offer.xml
index b6dfa29..5e29267 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_offer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_offer.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.41,11.41l-8.83,-8.83C12.21,2.21 11.7,2 11.17,2H4C2.9,2 2,2.9 2,4v7.17c0,0.53 0.21,1.04 0.59,1.41l8.83,8.83c0.78,0.78 2.05,0.78 2.83,0l7.17,-7.17C22.2,13.46 22.2,12.2 21.41,11.41zM6.5,8C5.67,8 5,7.33 5,6.5S5.67,5 6.5,5S8,5.67 8,6.5S7.33,8 6.5,8z"/>
+ android:pathData="M21.41,11.58l-9,-9C12.05,2.22 11.55,2 11,2H4c-1.1,0 -2,0.9 -2,2v7c0,0.55 0.22,1.05 0.59,1.42l9,9c0.36,0.36 0.86,0.58 1.41,0.58s1.05,-0.22 1.41,-0.59l7,-7c0.37,-0.36 0.59,-0.86 0.59,-1.41s-0.23,-1.06 -0.59,-1.42zM5.5,7C4.67,7 4,6.33 4,5.5S4.67,4 5.5,4 7,4.67 7,5.5 6.33,7 5.5,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_parking.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_parking.xml
index dc8d482..a48b3e5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_parking.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_parking.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.79,3H8C6.9,3 6,3.9 6,5v14c0,1.1 0.9,2 2,2l0,0c1.1,0 2,-0.9 2,-2v-4h3c3.57,0 6.42,-3.13 5.95,-6.79C18.56,5.19 15.84,3 12.79,3zM13.2,11H10V7h3.2c1.1,0 2,0.9 2,2S14.3,11 13.2,11z"/>
+ android:pathData="M12.79,3L8,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2s2,-0.9 2,-2v-4h3c3.57,0 6.42,-3.13 5.95,-6.79C18.56,5.19 15.84,3 12.79,3zM13.2,11L10,11L10,7h3.2c1.1,0 2,0.9 2,2s-0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_pharmacy.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_pharmacy.xml
index 5045d56..898b344 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_pharmacy.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_pharmacy.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.89,5h-0.53l0.71,-1.97c0.24,-0.65 -0.1,-1.37 -0.75,-1.6l0,0c-0.65,-0.24 -1.37,0.1 -1.61,0.75L15.69,5H5.1C3.73,5 2.77,6.34 3.2,7.63L5,13l-1.79,5.37C2.77,19.66 3.74,21 5.1,21h13.78c1.36,0 2.33,-1.34 1.9,-2.63L19,13l1.78,-5.37C21.21,6.34 20.25,5 18.89,5zM15,14h-2v2c0,0.55 -0.45,1 -1,1l0,0c-0.55,0 -1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v2h2c0.55,0 1,0.45 1,1l0,0C16,13.55 15.55,14 15,14z"/>
+ android:pathData="M18.89,5h-0.53l0.71,-1.97c0.24,-0.65 -0.1,-1.37 -0.75,-1.6 -0.65,-0.24 -1.37,0.1 -1.61,0.75L15.69,5H5.1C3.73,5 2.77,6.34 3.2,7.63L5,13l-1.79,5.37C2.77,19.66 3.74,21 5.1,21h13.78c1.36,0 2.33,-1.34 1.9,-2.63L19,13l1.78,-5.37C21.21,6.34 20.25,5 18.89,5zM15,14h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_phone.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_phone.xml
index 324cfc7..0c2d257 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_phone.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_phone.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77H5.03c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_pizza.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_pizza.xml
index 738a103..fdbd04f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_pizza.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_pizza.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,3C9.02,3 6.03,4.17 3.61,5.79C2.69,6.4 2.43,7.65 3.05,8.57l7.29,10.93c0.79,1.19 2.54,1.19 3.33,0l7.29,-10.93c0.62,-0.92 0.36,-2.17 -0.56,-2.79C17.97,4.17 14.98,3 12,3zM8,8.5C8,7.67 8.67,7 9.5,7S11,7.67 11,8.5S10.33,10 9.5,10S8,9.33 8,8.5zM12,15c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,12 12,12s1.5,0.67 1.5,1.5S12.83,15 12,15z"/>
+ android:pathData="M12,2C9.01,2 6.28,3.08 4.17,4.88c-0.71,0.61 -0.86,1.65 -0.4,2.46l7.36,13.11c0.38,0.68 1.36,0.68 1.74,0l7.36,-13.11c0.46,-0.81 0.31,-1.86 -0.4,-2.46C17.73,3.09 14.99,2 12,2zM7,7c0,-1.1 0.9,-2 2,-2s2,0.9 2,2 -0.9,2 -2,2 -2,-0.9 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_play.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_play.xml
index 2efedf6..eba3021 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_play.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_play.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,10V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2.01,4.9 2.01,6v4C3.11,10 4,10.9 4,12s-0.89,2 -2,2v4c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-4c-1.1,0 -2,-0.9 -2,-2S20.9,10 22,10zM15.38,11.27l-1.66,1.32l0.6,1.92c0.14,0.46 -0.39,0.84 -0.78,0.55L12,13.89l-1.54,1.17c-0.39,0.29 -0.92,-0.08 -0.78,-0.55l0.6,-1.92l-1.66,-1.32c-0.37,-0.29 -0.16,-0.89 0.31,-0.89h1.98l0.62,-1.9c0.15,-0.46 0.8,-0.46 0.95,0l0.62,1.9h1.98C15.54,10.38 15.75,10.97 15.38,11.27z"/>
+ android:pathData="M20,12c0,-0.76 0.43,-1.42 1.06,-1.76 0.6,-0.33 0.94,-1.01 0.94,-1.7L22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -1.99,0.89 -1.99,1.99v2.55c0,0.69 0.33,1.37 0.94,1.69C3.58,10.58 4,11.24 4,12s-0.43,1.43 -1.06,1.76c-0.6,0.33 -0.94,1.01 -0.94,1.7v2.25C2,19.1 2.9,20 4,20h16c1.1,0 2,-0.9 2,-2v-2.54c0,-0.69 -0.34,-1.37 -0.94,-1.7 -0.63,-0.34 -1.06,-1 -1.06,-1.76zM14.5,16.1L12,14.5l-2.5,1.61c-0.38,0.24 -0.87,-0.11 -0.75,-0.55l0.75,-2.88 -2.3,-1.88c-0.35,-0.29 -0.17,-0.86 0.29,-0.89l2.96,-0.17 1.08,-2.75c0.17,-0.42 0.77,-0.42 0.93,0l1.08,2.76 2.96,0.17c0.45,0.03 0.64,0.6 0.29,0.89l-2.3,1.88 0.76,2.86c0.12,0.45 -0.37,0.8 -0.75,0.55z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_police.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_police.xml
index d97fdff..6732730 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_police.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_police.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.3,2.26l-6,2.25C4.52,4.81 4,5.55 4,6.39v4.7c0,5.05 3.41,9.76 8,10.91c4.59,-1.15 8,-5.86 8,-10.91v-4.7c0,-0.83 -0.52,-1.58 -1.3,-1.87l-6,-2.25C12.25,2.09 11.75,2.09 11.3,2.26zM13.81,12.21l0.6,1.92c0.14,0.46 -0.39,0.84 -0.78,0.55l-1.54,-1.17l-1.54,1.17c-0.39,0.29 -0.92,-0.08 -0.78,-0.55l0.6,-1.92l-1.66,-1.32C8.34,10.6 8.55,10 9.02,10H11l0.62,-1.9c0.15,-0.46 0.8,-0.46 0.95,0l0.62,1.9h1.98c0.47,0 0.68,0.6 0.31,0.89L13.81,12.21z"/>
+ android:pathData="M14.5,12.59l0.63,2.73c0.1,0.43 -0.37,0.77 -0.75,0.54L12,14.42l-2.39,1.44c-0.38,0.23 -0.85,-0.11 -0.75,-0.54L9.5,12.6l-2.1,-1.81C7.06,10.5 7.24,9.95 7.68,9.91l2.78,-0.24l1.08,-2.56c0.17,-0.41 0.75,-0.41 0.92,0l1.08,2.55l2.78,0.24c0.44,0.04 0.62,0.59 0.28,0.88L14.5,12.59zM4.19,4.47C3.47,4.79 3,5.51 3,6.3V11c0,5.55 3.84,10.74 9,12c5.16,-1.26 9,-6.45 9,-12V6.3c0,-0.79 -0.47,-1.51 -1.19,-1.83l-7,-3.11c-0.52,-0.23 -1.11,-0.23 -1.62,0L4.19,4.47z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_post_office.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_post_office.xml
index 450b0ad..d171466 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_post_office.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_post_office.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,2h-4C8.69,2 6,4.69 6,8v4H3c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-2h4v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V8C22,4.69 19.31,2 16,2zM20,17h-4v-4c0,-0.55 -0.45,-1 -1,-1H8V8c0,-2.21 1.79,-4 4,-4h4c2.21,0 4,1.79 4,4V17zM13.62,15.94l-3.63,2.07c-0.61,0.35 -1.37,0.35 -1.98,0l-3.63,-2.07C4.14,15.81 4,15.56 4,15.29v0c0,-0.58 0.62,-0.94 1.12,-0.65L9,16.86l3.88,-2.22c0.5,-0.29 1.12,0.08 1.12,0.65v0C14,15.56 13.86,15.81 13.62,15.94z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,10h6c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1v0C10,9.55 10.45,10 11,10z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19.6,8.25l-6.54,4.09c-0.65,0.41 -1.47,0.41 -2.12,0L4.4,8.25c-0.25,-0.16 -0.4,-0.43 -0.4,-0.72 0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19c0.57,-0.35 1.3,0.05 1.3,0.72 0,0.29 -0.15,0.56 -0.4,0.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_shipping.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_shipping.xml
index cb1a643..ade1315 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_shipping.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_shipping.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.5,8H17V6c0,-1.1 -0.9,-2 -2,-2H3C1.9,4 1,4.9 1,6v9c0,1.1 0.9,2 2,2h0c0,1.66 1.34,3 3,3s3,-1.34 3,-3h6c0,1.66 1.34,3 3,3s3,-1.34 3,-3h1c0.55,0 1,-0.45 1,-1v-3.67c0,-0.22 -0.07,-0.43 -0.2,-0.6L20.3,8.4C20.11,8.15 19.81,8 19.5,8zM6,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S6.55,18 6,18zM18,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S18.55,18 18,18zM17,13v-3h2l2.25,3H17z"/>
+ android:pathData="M19.5,8L17,8L17,6c0,-1.1 -0.9,-2 -2,-2L3,4c-1.1,0 -2,0.9 -2,2v9c0,1.1 0.9,2 2,2 0,1.66 1.34,3 3,3s3,-1.34 3,-3h6c0,1.66 1.34,3 3,3s3,-1.34 3,-3h1c0.55,0 1,-0.45 1,-1v-3.33c0,-0.43 -0.14,-0.85 -0.4,-1.2L20.3,8.4c-0.19,-0.25 -0.49,-0.4 -0.8,-0.4zM6,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM19.5,9.5l1.96,2.5L17,12L17,9.5h2.5zM18,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/local_taxi.xml b/compose/material/material/icons/generator/raw-icons/rounded/local_taxi.xml
index c348123..d23bdaf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/local_taxi.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/local_taxi.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5H15V4c0,-0.55 -0.45,-1 -1,-1h-4C9.45,3 9,3.45 9,4v1H6.5C5.84,5 5.29,5.42 5.08,6.01L3,12v7.5C3,20.32 3.67,21 4.5,21S6,20.32 6,19.5V19h12v0.5c0,0.82 0.67,1.5 1.5,1.5s1.5,-0.68 1.5,-1.5V12L18.92,6.01zM7.5,16C6.67,16 6,15.33 6,14.5S6.67,13 7.5,13S9,13.67 9,14.5S8.33,16 7.5,16zM16.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S17.33,16 16.5,16zM5.81,10l1.04,-3h10.29l1.04,3H5.81z"/>
+ android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5L15,5L15,4c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v1L6.5,5c-0.66,0 -1.21,0.42 -1.42,1.01l-1.97,5.67c-0.07,0.21 -0.11,0.43 -0.11,0.66v7.16c0,0.83 0.67,1.5 1.5,1.5S6,20.33 6,19.5L6,19h12v0.5c0,0.82 0.67,1.5 1.5,1.5 0.82,0 1.5,-0.67 1.5,-1.5v-7.16c0,-0.22 -0.04,-0.45 -0.11,-0.66l-1.97,-5.67zM6.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,13 6.5,13s1.5,0.67 1.5,1.5S7.33,16 6.5,16zM17.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,11l1.5,-4.5h11L19,11L5,11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/location_city.xml b/compose/material/material/icons/generator/raw-icons/rounded/location_city.xml
index 369ab66..0465c33 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/location_city.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/location_city.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,11V5.83c0,-0.53 -0.21,-1.04 -0.59,-1.42l-1.71,-1.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.7,1.7C9.21,4.79 9,5.3 9,5.83V7H5C3.9,7 3,7.9 3,9v10c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-6c0,-1.1 -0.9,-2 -2,-2H15zM7,19H5v-2h2V19zM7,15H5v-2h2V15zM7,11H5V9h2V11zM13,19h-2v-2h2V19zM13,15h-2v-2h2V15zM13,11h-2V9h2V11zM13,7h-2V5h2V7zM19,19h-2v-2h2V19zM19,15h-2v-2h2V15z"/>
+ android:pathData="M15,11L15,5.83c0,-0.53 -0.21,-1.04 -0.59,-1.41L12.7,2.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.7,1.7C9.21,4.79 9,5.3 9,5.83L9,7L5,7c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-6c0,-1.1 -0.9,-2 -2,-2h-4zM7,19L5,19v-2h2v2zM7,15L5,15v-2h2v2zM7,11L5,11L5,9h2v2zM13,19h-2v-2h2v2zM13,15h-2v-2h2v2zM13,11h-2L11,9h2v2zM13,7h-2L11,5h2v2zM19,19h-2v-2h2v2zM19,15h-2v-2h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/location_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/location_disabled.xml
index c8334d6..09a832e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/location_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/location_disabled.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.94,11C20.48,6.83 17.17,3.52 13,3.06V2c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1.06C9.62,3.21 8.34,3.68 7.22,4.39l1.45,1.45C10,5.12 11.6,4.82 13.28,5.11c2.82,0.5 5.11,2.78 5.61,5.61c0.3,1.68 0,3.28 -0.73,4.61l1.45,1.45c0.71,-1.12 1.18,-2.4 1.33,-3.78H22c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H20.94zM2.1,4.93l2.29,2.29C3.68,8.34 3.21,9.62 3.06,11H2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-1.06c1.38,-0.15 2.66,-0.62 3.78,-1.33l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.71,3.91 1.71,4.54 2.1,4.93zM5.84,8.67l9.49,9.49C14.34,18.7 13.21,19 12,19c-3.87,0 -7,-3.13 -7,-7C5,10.79 5.3,9.66 5.84,8.67z"/>
+ android:pathData="M22,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.06c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1.06c-0.98,0.11 -1.91,0.38 -2.77,0.78l1.53,1.53C10.46,5.13 11.22,5 12,5c3.87,0 7,3.13 7,7 0,0.79 -0.13,1.54 -0.37,2.24l1.53,1.53c0.4,-0.86 0.67,-1.79 0.78,-2.77L22,13zM20.44,18.88L5.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L5.04,6.3C3.97,7.62 3.26,9.23 3.06,11L2,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94L11,22c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1.06c1.77,-0.2 3.38,-0.91 4.69,-1.98l1.33,1.33c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.39 0.4,-1.02 0.01,-1.41zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-1.61 0.55,-3.09 1.46,-4.27l9.81,9.81C15.09,18.45 13.61,19 12,19z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/location_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/location_off.xml
index c76a6fa..78084f3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/location_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/location_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.07,8.24C11.35,8.09 11.66,8 12,8c1.1,0 2,0.9 2,2c0,0.34 -0.09,0.65 -0.24,0.93l4.42,4.42C19.39,13.49 20,11.77 20,10.2C20,5.22 16.2,2 12,2c-1.95,0 -3.8,0.69 -5.24,1.93L11.07,8.24z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l2.38,2.38C4.18,8.19 4,9.15 4,10.2c0,3.18 2.44,6.92 7.33,11.23c0.38,0.33 0.96,0.33 1.33,0c1.14,-1 2.14,-1.97 3.01,-2.92l3.39,3.39c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M2.71,3.56c-0.39,0.39 -0.39,1.02 0,1.41l2.47,2.47C5.07,7.95 5,8.47 5,9c0,4.17 4.42,9.92 6.23,12.11 0.4,0.48 1.13,0.48 1.53,0 0.65,-0.78 1.62,-2.01 2.61,-3.46l2.65,2.65c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0zM12,2c-1.84,0 -3.5,0.71 -4.75,1.86l3.19,3.19c0.43,-0.34 0.97,-0.55 1.56,-0.55 1.38,0 2.5,1.12 2.5,2.5 0,0.59 -0.21,1.13 -0.56,1.56l3.55,3.55C18.37,12.36 19,10.57 19,9c0,-3.87 -3.13,-7 -7,-7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/location_searching.xml b/compose/material/material/icons/generator/raw-icons/rounded/location_searching.xml
index 7d5e2fa..75b73c8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/location_searching.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/location_searching.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.94,11C20.48,6.83 17.17,3.52 13,3.06V2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11H2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94H22c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H20.94zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7s7,3.13 7,7S15.87,19 12,19z"/>
+ android:pathData="M20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94H22c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/lock.xml b/compose/material/material/icons/generator/raw-icons/rounded/lock.xml
index 90555a0..c985c05 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/lock.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/lock.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10C20,8.9 19.1,8 18,8zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,17 12,17zM9,8V6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2H9z"/>
+ android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM9,8L9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/lock_open.xml b/compose/material/material/icons/generator/raw-icons/rounded/lock_open.xml
index a7a4756..def7919 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/lock_open.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/lock_open.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5C9.72,1 7.73,2.54 7.16,4.75C7.02,5.29 7.34,5.83 7.88,5.97C8.41,6.11 8.96,5.79 9.1,5.25C9.44,3.93 10.63,3 12,3c1.65,0 3,1.35 3,3v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10C20,8.9 19.1,8 18,8zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,17 12,17z"/>
+ android:pathData="M12,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5 -2.28,0 -4.27,1.54 -4.84,3.75 -0.14,0.54 0.18,1.08 0.72,1.22 0.53,0.14 1.08,-0.18 1.22,-0.72C9.44,3.93 10.63,3 12,3c1.65,0 3,1.35 3,3v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,19c0,0.55 -0.45,1 -1,1L7,20c-0.55,0 -1,-0.45 -1,-1v-8c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1v8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/login.xml b/compose/material/material/icons/generator/raw-icons/rounded/login.xml
index 779ecc5..207b6d5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/login.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/login.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3h-6c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h6v14h-6c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h6c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,9.21V11H4c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h7v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C11.54,8.54 11,8.76 11,9.21z"/>
+ android:pathData="M10.3,7.7L10.3,7.7c-0.39,0.39 -0.39,1.01 0,1.4l1.9,1.9H3c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h9.2l-1.9,1.9c-0.39,0.39 -0.39,1.01 0,1.4l0,0c0.39,0.39 1.01,0.39 1.4,0l3.59,-3.59c0.39,-0.39 0.39,-1.02 0,-1.41L11.7,7.7C11.31,7.31 10.69,7.31 10.3,7.7zM20,19h-7c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h7c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2h-7c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h7V19z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/looks.xml b/compose/material/material/icons/generator/raw-icons/rounded/looks.xml
index 20ede7d..a58b7b1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/looks.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/looks.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,10c-3.47,0 -6.36,2.54 -6.91,5.86c-0.1,0.6 0.39,1.14 1,1.14l0,0c0.49,0 0.9,-0.36 0.98,-0.85C7.48,13.79 9.53,12 12,12s4.52,1.79 4.93,4.15c0.08,0.49 0.49,0.85 0.98,0.85l0,0c0.61,0 1.09,-0.54 0.99,-1.14C18.36,12.54 15.47,10 12,10zM12,6C6.3,6 1.61,10.34 1.05,15.9C1,16.49 1.46,17 2.06,17l0,0c0.51,0 0.94,-0.38 0.99,-0.88C3.49,11.57 7.34,8 12,8s8.51,3.57 8.96,8.12c0.05,0.5 0.48,0.88 0.99,0.88l0,0c0.59,0 1.06,-0.51 1,-1.1C22.39,10.34 17.7,6 12,6z"/>
+ android:pathData="M12,10c-3.47,0 -6.36,2.54 -6.91,5.86 -0.1,0.6 0.39,1.14 1,1.14 0.49,0 0.9,-0.36 0.98,-0.85C7.48,13.79 9.53,12 12,12s4.52,1.79 4.93,4.15c0.08,0.49 0.49,0.85 0.98,0.85 0.61,0 1.09,-0.54 0.99,-1.14C18.36,12.54 15.47,10 12,10zM12,6C6.3,6 1.61,10.34 1.05,15.9c-0.05,0.59 0.41,1.1 1.01,1.1 0.51,0 0.94,-0.38 0.99,-0.88C3.49,11.57 7.34,8 12,8s8.51,3.57 8.96,8.12c0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1C22.39,10.34 17.7,6 12,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/looks_3.xml b/compose/material/material/icons/generator/raw-icons/rounded/looks_3.xml
index af80bba..bb47494 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/looks_3.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/looks_3.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.11,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM15,10.5c0,0.83 -0.67,1.5 -1.5,1.5c0.83,0 1.5,0.67 1.5,1.5V15c0,1.1 -0.9,2 -2,2h-3c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h3v-2h-1c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h1V9h-3C9.45,9 9,8.55 9,8v0c0,-0.55 0.45,-1 1,-1h3c1.1,0 2,0.89 2,2V10.5z"/>
+ android:pathData="M19,3L5.01,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2L19,21c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM15.01,10.5c0,0.83 -0.67,1.5 -1.5,1.5 0.83,0 1.5,0.67 1.5,1.5L15.01,15c0,1.11 -0.9,2 -2,2L10,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3.01L13,13h-1c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h1l0.01,-2L10,9c-0.55,0 -0.99,-0.45 -0.99,-1s0.44,-1 0.99,-1h3.01c1.1,0 2,0.9 2,2v1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/looks_4.xml b/compose/material/material/icons/generator/raw-icons/rounded/looks_4.xml
index 25eba51..25d6a6e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/looks_4.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/looks_4.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM14,17L14,17c-0.55,0 -1,-0.45 -1,-1v-3h-3c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v3h2V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v8C15,16.55 14.55,17 14,17z"/>
+ android:pathData="M19.04,3h-14c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21.04,5c0,-1.1 -0.9,-2 -2,-2zM14.04,17c-0.55,0 -1,-0.45 -1,-1v-3h-3c-0.55,0 -1,-0.45 -1,-1L9.04,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h2L13.04,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/looks_5.xml b/compose/material/material/icons/generator/raw-icons/rounded/looks_5.xml
index c87e194..f5be9c5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/looks_5.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/looks_5.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM14,9h-3v2h2c1.1,0 2,0.9 2,2v2c0,1.11 -0.9,2 -2,2h-3c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h3v-2h-3c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1l0,0C15,8.55 14.55,9 14,9z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM14,9h-3v2h2c1.1,0 2,0.9 2,2v2c0,1.11 -0.9,2 -2,2h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3v-2h-3c-0.55,0 -1,-0.45 -1,-1L9,8c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/looks_6.xml b/compose/material/material/icons/generator/raw-icons/rounded/looks_6.xml
index 0ab16e0..402935a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/looks_6.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/looks_6.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,15h2v-2h-2V15zM19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM13,9h-2v2h2c1.1,0 2,0.9 2,2v2c0,1.11 -0.9,2 -2,2h-2c-1.1,0 -2,-0.89 -2,-2V9c0,-1.1 0.9,-2 2,-2h2c0.55,0 1,0.45 1,1l0,0C14,8.55 13.55,9 13,9z"/>
+ android:pathData="M11,15h2v-2h-2v2zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM14,9h-3v2h2c1.1,0 2,0.9 2,2v2c0,1.11 -0.9,2 -2,2h-2c-1.1,0 -2,-0.89 -2,-2L9,9c0,-1.1 0.9,-2 2,-2h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/looks_one.xml b/compose/material/material/icons/generator/raw-icons/rounded/looks_one.xml
index 0c138f8..1810aff 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/looks_one.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/looks_one.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM13,17L13,17c-0.55,0 -1,-0.45 -1,-1V9h-1c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h2c0.55,0 1,0.45 1,1v8C14,16.55 13.55,17 13,17z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM13,17c-0.55,0 -1,-0.45 -1,-1L12,9h-1c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/looks_two.xml b/compose/material/material/icons/generator/raw-icons/rounded/looks_two.xml
index 561b7bf..b81815e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/looks_two.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/looks_two.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM15,11c0,1.1 -0.9,2 -2,2h-2v2h3c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1v-3c0,-1.1 0.9,-2 2,-2h2V9h-3C9.45,9 9,8.55 9,8l0,0c0,-0.55 0.45,-1 1,-1h3c1.1,0 2,0.9 2,2V11z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM15,11c0,1.1 -0.9,2 -2,2h-2v2h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1v-3c0,-1.1 0.9,-2 2,-2h2L13,9h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3c1.1,0 2,0.9 2,2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/loop.xml b/compose/material/material/icons/generator/raw-icons/rounded/loop.xml
index 953af82..0ea3056 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/loop.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/loop.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.35,13.99C5.01,10.29 7.71,6 12,6v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C12.54,1.54 12,1.76 12,2.21V4C6.24,4 2.61,9.78 4.52,14.79c0.24,0.63 1.08,0.78 1.56,0.3l0.08,-0.08C6.42,14.75 6.48,14.35 6.35,13.99z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.64,10.02C19.01,13.86 16.17,18 12,18v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.35V20c5.76,0 9.39,-5.78 7.48,-10.79c-0.24,-0.63 -1.08,-0.78 -1.56,-0.3l-0.07,0.07C17.58,9.25 17.52,9.65 17.64,10.02z"/>
+ android:pathData="M12,4L12,2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.8,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.32,0.31 0.86,0.09 0.86,-0.36L12,6c3.31,0 6,2.69 6,6 0,0.79 -0.15,1.56 -0.44,2.25 -0.15,0.36 -0.04,0.77 0.23,1.04 0.51,0.51 1.37,0.33 1.64,-0.34 0.37,-0.91 0.57,-1.91 0.57,-2.95 0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-0.79 0.15,-1.56 0.44,-2.25 0.15,-0.36 0.04,-0.77 -0.23,-1.04 -0.51,-0.51 -1.37,-0.33 -1.64,0.34C4.2,9.96 4,10.96 4,12c0,4.42 3.58,8 8,8v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L12,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/loupe.xml b/compose/material/material/icons/generator/raw-icons/rounded/loupe.xml
index e094be6..6608b06 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/loupe.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/loupe.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7L12,7c-0.55,0 -1,0.45 -1,1v3H8c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-3V8C13,7.45 12.55,7 12,7zM12,2C6.49,2 2,6.49 2,12s4.49,10 10,10h8c1.1,0 2,-0.9 2,-2v-8C22,6.49 17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/>
+ android:pathData="M12,7c-0.55,0 -1,0.45 -1,1v3L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L13,8c0,-0.55 -0.45,-1 -1,-1zM12,2C6.49,2 2,6.49 2,12s4.49,10 10,10h8c1.1,0 2,-0.9 2,-2v-8c0,-5.51 -4.49,-10 -10,-10zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/low_priority.xml b/compose/material/material/icons/generator/raw-icons/rounded/low_priority.xml
index f8d50db..2cab168 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/low_priority.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/low_priority.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,5h6c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1l0,0C14,5.45 14.45,5 15,5zM15,10.5h6c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1l0,0C14,10.95 14.45,10.5 15,10.5zM15,16h6c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1l0,0C14,16.45 14.45,16 15,16zM9.85,19.15l1.79,-1.79c0.2,-0.2 0.2,-0.51 0,-0.71l-1.79,-1.79C9.54,14.54 9,14.76 9,15.21v3.59C9,19.24 9.54,19.46 9.85,19.15zM9,16H8.7c-2.35,0 -4.45,-1.71 -4.68,-4.05C3.76,9.27 5.87,7 8.5,7H11c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8.5c-3.86,0 -6.96,3.4 -6.44,7.36C2.48,15.64 5.43,18 8.73,18H9"/>
+ android:pathData="M15,5h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM15,10.5h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM15,16h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM9.85,19.15l1.79,-1.79c0.2,-0.2 0.2,-0.51 0,-0.71l-1.79,-1.79c-0.31,-0.32 -0.85,-0.1 -0.85,0.35v3.59c0,0.44 0.54,0.66 0.85,0.35zM9,16h-0.3c-2.35,0 -4.45,-1.71 -4.68,-4.05C3.76,9.27 5.87,7 8.5,7L11,7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8.5,5c-3.86,0 -6.96,3.4 -6.44,7.36C2.48,15.64 5.43,18 8.73,18L9,18"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/loyalty.xml b/compose/material/material/icons/generator/raw-icons/rounded/loyalty.xml
index 350b34a..63a7163 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/loyalty.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/loyalty.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.41,11.41l-8.83,-8.83C12.21,2.21 11.7,2 11.17,2H4C2.9,2 2,2.9 2,4v7.17c0,0.53 0.21,1.04 0.59,1.41l8.83,8.83C11.8,21.8 12.32,22 12.83,22s1.02,-0.2 1.41,-0.59l7.17,-7.17C22.2,13.46 22.2,12.2 21.41,11.41zM6.5,8C5.67,8 5,7.33 5,6.5S5.67,5 6.5,5S8,5.67 8,6.5S7.33,8 6.5,8zM16.5,14l-2.79,2.79c-0.39,0.39 -1.02,0.39 -1.41,0L9.5,14c-1.31,-1.35 -0.32,-3.5 1.45,-3.5c0.92,0 1.32,0.48 2.05,1.2c0.67,-0.67 1.07,-1.2 2.05,-1.2C16.88,10.5 17.78,12.72 16.5,14z"/>
+ android:pathData="M21.41,11.58l-9,-9C12.05,2.22 11.55,2 11,2L4,2c-1.1,0 -2,0.9 -2,2v7c0,0.55 0.22,1.05 0.59,1.42l9,9c0.36,0.36 0.86,0.58 1.41,0.58s1.05,-0.22 1.41,-0.59l7,-7c0.37,-0.36 0.59,-0.86 0.59,-1.41s-0.23,-1.06 -0.59,-1.42zM5.5,7C4.67,7 4,6.33 4,5.5S4.67,4 5.5,4 7,4.67 7,5.5 6.33,7 5.5,7zM17.27,15.27l-3.92,3.92c-0.2,0.2 -0.51,0.2 -0.71,0l-3.92,-3.92c-0.57,-0.58 -0.87,-1.43 -0.67,-2.34 0.19,-0.88 0.89,-1.61 1.76,-1.84 0.94,-0.25 1.85,0.04 2.44,0.65l0.75,0.72 0.73,-0.73c0.45,-0.45 1.08,-0.73 1.77,-0.73 1.38,0 2.5,1.12 2.5,2.5 0,0.69 -0.28,1.32 -0.73,1.77z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mail.xml b/compose/material/material/icons/generator/raw-icons/rounded/mail.xml
index 600919e..d171466 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mail.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mail.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM19.6,8.25l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25C4.15,8.09 4,7.82 4,7.53c0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19C19.27,6.46 20,6.86 20,7.53C20,7.82 19.85,8.09 19.6,8.25z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19.6,8.25l-6.54,4.09c-0.65,0.41 -1.47,0.41 -2.12,0L4.4,8.25c-0.25,-0.16 -0.4,-0.43 -0.4,-0.72 0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19c0.57,-0.35 1.3,0.05 1.3,0.72 0,0.29 -0.15,0.56 -0.4,0.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mail_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/mail_outline.xml
index 600919e..27fd8be 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mail_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mail_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM19.6,8.25l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25C4.15,8.09 4,7.82 4,7.53c0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19C19.27,6.46 20,6.86 20,7.53C20,7.82 19.85,8.09 19.6,8.25z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19,18L5,18c-0.55,0 -1,-0.45 -1,-1L4,8l6.94,4.34c0.65,0.41 1.47,0.41 2.12,0L20,8v9c0,0.55 -0.45,1 -1,1zM12,11L4,6h16l-8,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/map.xml b/compose/material/material/icons/generator/raw-icons/rounded/map.xml
index 714712a..b6f2bc5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/map.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/map.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,5.1L9.65,3.23c-0.42,-0.15 -0.88,-0.15 -1.3,-0.01L3.68,4.79C3.27,4.93 3,5.31 3,5.74v14.03c0,0.7 0.71,1.19 1.36,0.93L9,18.9l5.35,1.87c0.42,0.15 0.88,0.15 1.3,0.01l4.67,-1.57c0.41,-0.14 0.68,-0.52 0.68,-0.95V4.23c0,-0.7 -0.71,-1.19 -1.36,-0.93L15,5.1zM15,18.9l-6,-2.11V5.11l6,2.11V18.9z"/>
+ android:pathData="M14.65,4.98l-5,-1.75c-0.42,-0.15 -0.88,-0.15 -1.3,-0.01L4.36,4.56C3.55,4.84 3,5.6 3,6.46v11.85c0,1.41 1.41,2.37 2.72,1.86l2.93,-1.14c0.22,-0.09 0.47,-0.09 0.69,-0.01l5,1.75c0.42,0.15 0.88,0.15 1.3,0.01l3.99,-1.34c0.81,-0.27 1.36,-1.04 1.36,-1.9V5.69c0,-1.41 -1.41,-2.37 -2.72,-1.86l-2.93,1.14c-0.22,0.08 -0.46,0.09 -0.69,0.01zM15,18.89l-6,-2.11V5.11l6,2.11v11.67z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/maps_ugc.xml b/compose/material/material/icons/generator/raw-icons/rounded/maps_ugc.xml
index c1d459f..753a785 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/maps_ugc.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/maps_ugc.xml
@@ -6,5 +6,9 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,1.54 0.36,2.98 0.97,4.29l-1.46,4.96C1.29,22 2,22.71 2.76,22.48l4.96,-1.46c1.66,0.79 3.56,1.15 5.58,0.89c4.56,-0.59 8.21,-4.35 8.66,-8.92C22.53,7.03 17.85,2 12,2zM15,13h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2V9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1S15.55,13 15,13z"/>
+ android:pathData="M12,4c4.97,0 8.9,4.56 7.82,9.72c-0.68,3.23 -3.4,5.74 -6.67,6.2c-1.59,0.22 -3.14,-0.01 -4.58,-0.7c-0.27,-0.13 -0.56,-0.19 -0.86,-0.19c-0.19,0 -0.38,0.03 -0.56,0.08l-2.31,0.68c-0.38,0.11 -0.74,-0.24 -0.63,-0.63l0.7,-2.39c0.13,-0.45 0.07,-0.92 -0.14,-1.35C4.26,14.34 4,13.18 4,12C4,7.59 7.59,4 12,4M12,2C6.48,2 2,6.48 2,12c0,1.54 0.36,2.98 0.97,4.29l-1.46,4.96C1.29,22 2,22.71 2.76,22.48l4.96,-1.46c1.66,0.79 3.56,1.15 5.58,0.89c4.56,-0.59 8.21,-4.35 8.66,-8.92C22.53,7.03 17.85,2 12,2L12,2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,8L12,8c-0.55,0 -1,0.45 -1,1v2H9c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-2V9C13,8.45 12.55,8 12,8z"
+ android:fillType="evenOdd"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/markunread.xml b/compose/material/material/icons/generator/raw-icons/rounded/markunread.xml
index 600919e..d171466 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/markunread.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/markunread.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM19.6,8.25l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25C4.15,8.09 4,7.82 4,7.53c0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19C19.27,6.46 20,6.86 20,7.53C20,7.82 19.85,8.09 19.6,8.25z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19.6,8.25l-6.54,4.09c-0.65,0.41 -1.47,0.41 -2.12,0L4.4,8.25c-0.25,-0.16 -0.4,-0.43 -0.4,-0.72 0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19c0.57,-0.35 1.3,0.05 1.3,0.72 0,0.29 -0.15,0.56 -0.4,0.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/markunread_mailbox.xml b/compose/material/material/icons/generator/raw-icons/rounded/markunread_mailbox.xml
index 21ed89d..166591a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/markunread_mailbox.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/markunread_mailbox.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,8H10v5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6h5c0.55,0 1,-0.45 1,-1V3c0,-0.55 -0.45,-1 -1,-1H7C6.45,2 6,2.45 6,3v5H4c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V10C22,8.9 21.1,8 20,8z"/>
+ android:pathData="M20,6H10v5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V4h5c0.55,0 1,-0.45 1,-1V1c0,-0.55 -0.45,-1 -1,-1H7c-0.55,0 -1,0.45 -1,1v5H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/maximize.xml b/compose/material/material/icons/generator/raw-icons/rounded/maximize.xml
index a48d2d5..f0f1875d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/maximize.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/maximize.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,3h16c0.55,0 1,0.45 1,1s-0.45,1 -1,1H4C3.45,5 3,4.55 3,4S3.45,3 4,3z"/>
+ android:pathData="M4,3h16c0.55,0 1,0.45 1,1s-0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/memory.xml b/compose/material/material/icons/generator/raw-icons/rounded/memory.xml
index e6558ea..ea4f4a1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/memory.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/memory.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,9h-4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4C15,9.45 14.55,9 14,9zM13,13h-2v-2h2V13zM21,10L21,10c0,-0.55 -0.45,-1 -1,-1h-1V7c0,-1.1 -0.9,-2 -2,-2h-2V4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v1h-2V4c0,-0.55 -0.45,-1 -1,-1l0,0C9.45,3 9,3.45 9,4v1H7C5.9,5 5,5.9 5,7v2H4c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h1v2H4c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h1v2c0,1.1 0.9,2 2,2h2v1c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-1h2c1.1,0 2,-0.9 2,-2v-2h1c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-1v-2h1C20.55,11 21,10.55 21,10zM17,17H7V7h10V17z"/>
+ android:pathData="M14,9h-4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1zM13,13h-2v-2h2v2zM21,10c0,-0.55 -0.45,-1 -1,-1h-1L19,7c0,-1.1 -0.9,-2 -2,-2h-2L15,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1h-2L11,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L7,5c-1.1,0 -2,0.9 -2,2v2L4,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v2L4,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v2c0,1.1 0.9,2 2,2h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2c1.1,0 2,-0.9 2,-2v-2h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-2h1c0.55,0 1,-0.45 1,-1zM16,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,8c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/menu.xml b/compose/material/material/icons/generator/raw-icons/rounded/menu.xml
index 4709e8e..ff67e556 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/menu.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/menu.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,17.55 3.45,18 4,18zM4,13h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13zM3,7L3,7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,6 3,6.45 3,7z"/>
+ android:pathData="M4,18h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,16c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,13h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/menu_book.xml b/compose/material/material/icons/generator/raw-icons/rounded/menu_book.xml
index 69d047b..cf2be78 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/menu_book.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/menu_book.xml
@@ -7,14 +7,14 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M22.47,5.2C21.55,4.73 19.82,4 17.5,4C14.91,4 13,4.91 12,5.48C11,4.91 9.09,4 6.5,4C4.18,4 2.44,4.73 1.53,5.2C1.04,5.44 1,5.95 1,6.08v12.08c0,0.71 0.77,1.25 1.48,0.87C4.33,18.06 5.87,18 6.5,18c2.13,0 3.86,0.86 4.96,1.61c0.35,0.23 0.78,0.2 1.07,0c1.1,-0.75 2.83,-1.61 4.96,-1.61c0.63,0 2.17,0.06 4.02,1.04c0.74,0.39 1.48,-0.19 1.48,-0.87V6.08C23,5.95 22.96,5.44 22.47,5.2zM21,16.62C19.48,16.07 18.22,16 17.5,16c-0.87,0 -3.03,0.09 -5.5,1.58V7.79C13.28,7.05 14.87,6 17.5,6c0.72,0 2.02,0.09 3.5,0.72V16.62z"/>
+ android:pathData="M17.5,4.5c-1.95,0 -4.05,0.4 -5.5,1.5c-1.45,-1.1 -3.55,-1.5 -5.5,-1.5c-1.45,0 -2.99,0.22 -4.28,0.79C1.49,5.62 1,6.33 1,7.14l0,11.28c0,1.3 1.22,2.26 2.48,1.94C4.46,20.11 5.5,20 6.5,20c1.56,0 3.22,0.26 4.56,0.92c0.6,0.3 1.28,0.3 1.87,0c1.34,-0.67 3,-0.92 4.56,-0.92c1,0 2.04,0.11 3.02,0.36c1.26,0.33 2.48,-0.63 2.48,-1.94l0,-11.28c0,-0.81 -0.49,-1.52 -1.22,-1.85C20.49,4.72 18.95,4.5 17.5,4.5zM21,17.23c0,0.63 -0.58,1.09 -1.2,0.98c-0.75,-0.14 -1.53,-0.2 -2.3,-0.2c-1.7,0 -4.15,0.65 -5.5,1.5V8c1.35,-0.85 3.8,-1.5 5.5,-1.5c0.92,0 1.83,0.09 2.7,0.28c0.46,0.1 0.8,0.51 0.8,0.98V17.23z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19.4,13.21C18.79,13.08 18.16,13 17.5,13c-1.05,0 -2.05,0.19 -2.99,0.52c-0.3,0.11 -0.51,0.39 -0.51,0.71v0c0,0.52 0.51,0.88 1,0.7c0.78,-0.28 1.62,-0.44 2.5,-0.44c0.55,0 1.08,0.06 1.6,0.18c0.46,0.11 0.9,-0.25 0.9,-0.73C20,13.59 19.75,13.29 19.4,13.21z"/>
+ android:pathData="M13.98,11.01c-0.32,0 -0.61,-0.2 -0.71,-0.52c-0.13,-0.39 0.09,-0.82 0.48,-0.94c1.54,-0.5 3.53,-0.66 5.36,-0.45c0.41,0.05 0.71,0.42 0.66,0.83c-0.05,0.41 -0.42,0.71 -0.83,0.66c-1.62,-0.19 -3.39,-0.04 -4.73,0.39C14.13,10.99 14.05,11.01 13.98,11.01z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19.4,10.46c-0.61,-0.14 -1.25,-0.21 -1.9,-0.21c-1.05,0 -2.05,0.19 -2.99,0.52c-0.3,0.11 -0.51,0.39 -0.51,0.71v0.01c0,0.52 0.51,0.88 1,0.7c0.78,-0.28 1.62,-0.44 2.5,-0.44c0.55,0 1.08,0.07 1.59,0.18C19.56,12.04 20,11.68 20,11.2v0C20,10.84 19.75,10.54 19.4,10.46z"/>
+ android:pathData="M13.98,13.67c-0.32,0 -0.61,-0.2 -0.71,-0.52c-0.13,-0.39 0.09,-0.82 0.48,-0.94c1.53,-0.5 3.53,-0.66 5.36,-0.45c0.41,0.05 0.71,0.42 0.66,0.83c-0.05,0.41 -0.42,0.71 -0.83,0.66c-1.62,-0.19 -3.39,-0.04 -4.73,0.39C14.13,13.66 14.05,13.67 13.98,13.67z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M14.52,8.01C14.21,8.11 14,8.4 14,8.72v0.02c0,0.52 0.51,0.88 1,0.7C15.78,9.16 16.62,9 17.5,9c0.55,0 1.08,0.07 1.59,0.18C19.56,9.29 20,8.93 20,8.45V8.44c0,-0.36 -0.25,-0.66 -0.6,-0.74c-0.61,-0.13 -1.25,-0.21 -1.9,-0.21C16.45,7.5 15.45,7.68 14.52,8.01z"/>
+ android:pathData="M13.98,16.33c-0.32,0 -0.61,-0.2 -0.71,-0.52c-0.13,-0.39 0.09,-0.82 0.48,-0.94c1.53,-0.5 3.53,-0.66 5.36,-0.45c0.41,0.05 0.71,0.42 0.66,0.83c-0.05,0.41 -0.42,0.7 -0.83,0.66c-1.62,-0.19 -3.39,-0.04 -4.73,0.39C14.13,16.32 14.05,16.33 13.98,16.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/menu_open.xml b/compose/material/material/icons/generator/raw-icons/rounded/menu_open.xml
index 01007c1..3952985 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/menu_open.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/menu_open.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h11c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,17.55 3.45,18 4,18zM4,13h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13zM3,7L3,7c0,0.55 0.45,1 1,1h11c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,6 3,6.45 3,7zM20.3,14.88L17.42,12l2.88,-2.88c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L15.3,11.3c-0.39,0.39 -0.39,1.02 0,1.41l3.59,3.59c0.39,0.39 1.02,0.39 1.41,0l0,0C20.68,15.91 20.69,15.27 20.3,14.88z"/>
+ android:pathData="M4,18h11c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,17.55 3.45,18 4,18zM4,13h8c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,12.55 3.45,13 4,13zM3,7L3,7c0,0.55 0.45,1 1,1h11c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4C3.45,6 3,6.45 3,7zM20.3,14.88L17.42,12l2.88,-2.88c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.59,3.59c-0.39,0.39 -0.39,1.02 0,1.41l3.59,3.59c0.39,0.39 1.02,0.39 1.41,0l0,0C20.68,15.91 20.69,15.27 20.3,14.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/merge_type.xml b/compose/material/material/icons/generator/raw-icons/rounded/merge_type.xml
index 09522be..9cf562c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/merge_type.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/merge_type.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,15.59L10.41,17l-2.3,2.3c-0.39,0.39 -1.02,0.39 -1.41,0h0c-0.39,-0.39 -0.39,-1.02 0,-1.41L9,15.59z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.35,3.35l3.79,3.79C16.46,7.46 16.24,8 15.79,8H13v5.59l4.3,4.3c0.39,0.39 0.39,1.02 0,1.41h0c-0.39,0.39 -1.02,0.39 -1.41,0L11,14.41V8H8.21C7.76,8 7.54,7.46 7.85,7.15l3.79,-3.79C11.84,3.16 12.16,3.16 12.35,3.35z"/>
+ android:pathData="M17.7,19.7c0.39,-0.39 0.39,-1.02 0,-1.41l-2.7,-2.7L13.59,17l2.7,2.7c0.39,0.39 1.03,0.39 1.41,0zM8.71,8H11v5.59l-4.71,4.7c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.71,-4.7c0.38,-0.38 0.59,-0.88 0.59,-1.41V8h2.29c0.45,0 0.67,-0.54 0.35,-0.85l-3.29,-3.29c-0.2,-0.2 -0.51,-0.2 -0.71,0L8.35,7.15c-0.31,0.31 -0.09,0.85 0.36,0.85z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/message.xml b/compose/material/material/icons/generator/raw-icons/rounded/message.xml
index d9f5fe8..8d0c7b9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/message.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/message.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2.01,2.9 2.01,4L2,19.58c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM7,9h10c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1l0,0C6,9.45 6.45,9 7,9zM13,14H7c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1l0,0C14,13.55 13.55,14 13,14zM17,8H7C6.45,8 6,7.55 6,7l0,0c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,0.45 1,1l0,0C18,7.55 17.55,8 17,8z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM17,14L7,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,11L7,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,8L7,8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mic.xml b/compose/material/material/icons/generator/raw-icons/rounded/mic.xml
index 693e9ee..137e720 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mic.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mic.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.91,11c-0.49,0 -0.9,0.36 -0.98,0.85C16.52,14.21 14.47,16 12,16s-4.52,-1.79 -4.93,-4.15C6.99,11.36 6.58,11 6.09,11h0c-0.61,0 -1.09,0.54 -1,1.14c0.49,3 2.89,5.34 5.91,5.78V20c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2.08c3.02,-0.44 5.42,-2.78 5.91,-5.78C19.01,11.54 18.52,11 17.91,11L17.91,11z"/>
+ android:pathData="M12,14c1.66,0 3,-1.34 3,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.91,11c-0.49,0 -0.9,0.36 -0.98,0.85C16.52,14.2 14.47,16 12,16s-4.52,-1.8 -4.93,-4.15c-0.08,-0.49 -0.49,-0.85 -0.98,-0.85 -0.61,0 -1.09,0.54 -1,1.14 0.49,3 2.89,5.35 5.91,5.78L11,20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.08c3.02,-0.43 5.42,-2.78 5.91,-5.78 0.1,-0.6 -0.39,-1.14 -1,-1.14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mic_none.xml b/compose/material/material/icons/generator/raw-icons/rounded/mic_none.xml
index e2b6115..4d73267 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mic_none.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mic_none.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.92,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3v6C8.92,12.66 10.26,14 11.92,14zM10.92,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5zM17.83,11c-0.49,0 -0.9,0.36 -0.98,0.85C16.44,14.2 14.39,16 11.92,16s-4.52,-1.8 -4.93,-4.15C6.91,11.36 6.5,11 6.01,11c-0.61,0 -1.09,0.54 -1,1.14c0.49,3 2.89,5.35 5.91,5.78V20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.08c3.02,-0.43 5.42,-2.78 5.91,-5.78C18.93,11.54 18.44,11 17.83,11z"/>
+ android:pathData="M12,14c1.66,0 3,-1.34 3,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,5zM17.91,11c-0.49,0 -0.9,0.36 -0.98,0.85C16.52,14.2 14.47,16 12,16s-4.52,-1.8 -4.93,-4.15c-0.08,-0.49 -0.49,-0.85 -0.98,-0.85 -0.61,0 -1.09,0.54 -1,1.14 0.49,3 2.89,5.35 5.91,5.78L11,20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.08c3.02,-0.43 5.42,-2.78 5.91,-5.78 0.1,-0.6 -0.39,-1.14 -1,-1.14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mic_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/mic_off.xml
index 2884733..b0790ef 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mic_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mic_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.91,11L17.91,11c-0.49,0 -0.9,0.36 -0.99,0.84c-0.1,0.59 -0.32,1.15 -0.61,1.65l1.45,1.45c0.57,-0.83 0.97,-1.78 1.14,-2.81C19.01,11.54 18.52,11 17.91,11zM2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l10.95,10.95C12.71,15.96 12.36,16 12,16c-2.47,0 -4.52,-1.79 -4.93,-4.15C6.99,11.36 6.58,11 6.09,11h0c-0.61,0 -1.09,0.54 -1,1.14c0.49,3 2.89,5.34 5.91,5.78V20c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2.08c0.57,-0.08 1.12,-0.24 1.64,-0.45l4.43,4.43c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51zM15,11V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v1.17l5.81,5.81C14.92,11.67 15,11.35 15,11z"/>
+ android:pathData="M15,10.6L15,5c0,-1.66 -1.34,-3 -3,-3 -1.54,0 -2.79,1.16 -2.96,2.65L15,10.6zM18.08,11c-0.41,0 -0.77,0.3 -0.83,0.71 -0.05,0.32 -0.12,0.64 -0.22,0.93l1.27,1.27c0.3,-0.6 0.52,-1.25 0.63,-1.94 0.07,-0.51 -0.33,-0.97 -0.85,-0.97zM3.71,3.56c-0.39,0.39 -0.39,1.02 0,1.41L9,10.27v0.43c0,1.19 0.6,2.32 1.63,2.91 0.75,0.43 1.41,0.44 2.02,0.31l1.66,1.66c-0.71,0.33 -1.5,0.52 -2.31,0.52 -2.54,0 -4.88,-1.77 -5.25,-4.39 -0.06,-0.41 -0.42,-0.71 -0.83,-0.71 -0.52,0 -0.92,0.46 -0.85,0.97 0.46,2.96 2.96,5.3 5.93,5.75L11,20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.28c0.91,-0.13 1.77,-0.45 2.55,-0.9l3.49,3.49c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/military_tech.xml b/compose/material/material/icons/generator/raw-icons/rounded/military_tech.xml
index 295d35d..ce10455 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/military_tech.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/military_tech.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,9.87V4c0,-1.1 -0.9,-2 -2,-2H9C7.9,2 7,2.9 7,4v5.87c0,0.7 0.37,1.35 0.97,1.72l3.52,2.11L10.79,16H8.56c-0.49,0 -0.69,0.62 -0.29,0.91l1.82,1.3l-0.71,2.3c-0.14,0.46 0.39,0.84 0.78,0.55l1.85,-1.4l1.85,1.4c0.39,0.29 0.92,-0.08 0.78,-0.55l-0.71,-2.3l1.82,-1.3c0.4,-0.28 0.2,-0.91 -0.29,-0.91h-2.23l-0.7,-2.31l3.52,-2.11C16.63,11.22 17,10.57 17,9.87zM13,11.07l-1,0.6l-1,-0.6V5c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1V11.07z"/>
+ android:pathData="M17,10.43V3c0,-0.55 -0.45,-1 -1,-1H8C7.45,2 7,2.45 7,3v7.43c0,0.35 0.18,0.68 0.49,0.86l4.18,2.51l-0.99,2.34l-2.22,0.19C8,16.37 7.82,16.92 8.16,17.21l1.69,1.46l-0.51,2.18c-0.1,0.43 0.37,0.77 0.75,0.54L12,20.23l1.91,1.15c0.38,0.23 0.85,-0.11 0.75,-0.54l-0.51,-2.18l1.69,-1.46c0.33,-0.29 0.16,-0.84 -0.29,-0.88l-2.22,-0.19l-0.99,-2.34l4.18,-2.51C16.82,11.11 17,10.79 17,10.43zM13,12.23l-1,0.6l-1,-0.6V3h2V12.23z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/minimize.xml b/compose/material/material/icons/generator/raw-icons/rounded/minimize.xml
index f731f32..8a1485f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/minimize.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/minimize.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,19h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1S6.45,19 7,19z"/>
+ android:pathData="M7,19h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1H7c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/missed_video_call.xml b/compose/material/material/icons/generator/raw-icons/rounded/missed_video_call.xml
index b8fffa3..a37b5e1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/missed_video_call.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/missed_video_call.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.29,8.2L18,10.48V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l2.29,2.28c0.63,0.63 1.71,0.18 1.71,-0.71V8.91C22,8.02 20.93,7.57 20.29,8.2zM14.5,12.18l-3.14,3.14c-0.39,0.39 -1.02,0.39 -1.41,0l-3.13,-3.13l-0.96,0.96C5.54,13.46 5,13.24 5,12.79L5,10c0,-0.55 0.45,-1 1,-1h2.79c0.45,0 0.67,0.54 0.35,0.85l-0.92,0.92l2.43,2.42l2.43,-2.43c0.39,-0.39 1.02,-0.39 1.41,0l0,0C14.89,11.15 14.89,11.79 14.5,12.18z"/>
+ android:pathData="M17,10.5L17,7c0,-0.55 -0.45,-1 -1,-1L4,6c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71L21,8.91c0,-0.89 -1.08,-1.34 -1.71,-0.71L17,10.5zM10.71,14.29c-0.39,0.39 -1.02,0.39 -1.41,0l-3.18,-3.18v2.55L5,13.66L5,9.72c0,-0.28 0.22,-0.5 0.5,-0.5h3.94v1.11L6.89,10.33l3.11,3.1 4.22,-4.22 0.78,0.79 -4.29,4.29z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mms.xml b/compose/material/material/icons/generator/raw-icons/rounded/mms.xml
index c087886..a0d99a0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mms.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mms.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v15.59c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,14H7c-0.41,0 -0.65,-0.47 -0.4,-0.8l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,13l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67C17.65,13.53 17.41,14 17,14z"/>
+ android:pathData="M20,2H4c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zM5.63,13.19l2.49,-3.2c0.2,-0.25 0.58,-0.26 0.78,-0.01l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8H6.02c-0.41,-0.01 -0.65,-0.49 -0.39,-0.82z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mobile_friendly.xml b/compose/material/material/icons/generator/raw-icons/rounded/mobile_friendly.xml
index 8fecff6..b1e1bc2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mobile_friendly.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mobile_friendly.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,17c-0.55,0 -1,0.45 -1,1H6V6h10c0,0.55 0.45,1 1,1s1,-0.45 1,-1V3c0,-1.1 -0.9,-2 -2,-2H6C4.9,1 4,1.9 4,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-3C18,17.45 17.55,17 17,17zM21.29,8.22c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.95,4.95l-2.12,-2.12c-0.39,-0.39 -1.02,-0.39 -1.41,0h0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l5.66,-5.66C21.68,9.25 21.68,8.61 21.29,8.22z"/>
+ android:pathData="M19,1H9c-1.1,0 -2,0.9 -2,2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4h10v16H9v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-2 -2,-2zM7.01,13.47l-1.92,-1.92c-0.35,-0.35 -0.92,-0.35 -1.27,0s-0.35,0.92 0,1.27l2.47,2.47c0.39,0.39 1.02,0.39 1.41,0l5.85,-5.85c0.35,-0.35 0.35,-0.92 0,-1.27s-0.92,-0.35 -1.27,0l-5.27,5.3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mobile_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/mobile_off.xml
index 9f00631..2289378 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mobile_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mobile_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,6v8.17l2,2V3c0,-1.1 -0.9,-2 -2,-2H7C6.14,1 5.42,1.55 5.14,2.31L8.83,6H17zM21.19,21.19L2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22l3.62,3.62V21c0,1.1 0.89,2 1.99,2h10c0.85,0 1.58,-0.55 1.87,-1.3l0.91,0.91c0.39,0.39 1.02,0.39 1.41,0C21.58,22.22 21.58,21.58 21.19,21.19zM7,18V9.83L15.17,18H7z"/>
+ android:pathData="M17,16.44L3.61,3.05c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L5,7.27V21c0,1.1 0.9,2 2,2h10c1.02,0 1.85,-0.77 1.98,-1.75L20,22.27c0.39,0.39 1.02,0.39 1.41,0s0.39,-1.02 0,-1.41L19,18.44l-2,-2zM7,19V9.27L16.73,19H7zM17,5v8.61l2,2V3c0,-1.1 -0.9,-2 -2,-2H7c-0.71,0 -1.33,0.37 -1.68,0.93L8.39,5H17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mobile_screen_share.xml b/compose/material/material/icons/generator/raw-icons/rounded/mobile_screen_share.xml
index 3bbfbe8..a62bfd6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mobile_screen_share.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mobile_screen_share.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,18H7V6h10V18zM11,13.5c0,-0.55 0.45,-1 1,-1h1v0.79c0,0.45 0.54,0.67 0.85,0.35l1.79,-1.79c0.2,-0.2 0.2,-0.51 0,-0.71l-1.79,-1.79C13.54,9.04 13,9.26 13,9.71v0.79h-1c-1.65,0 -3,1.35 -3,3V14c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V13.5z"/>
+ android:pathData="M17,1L7,1c-1.1,0 -1.99,0.9 -1.99,2v18c0,1.1 0.89,2 1.99,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-2 -2,-2zM17,19L7,19L7,5h10v14zM12.8,13.22v1.75l2.81,-2.62c0.21,-0.2 0.21,-0.53 0,-0.73L12.8,9v1.7c-3.11,0.43 -4.35,2.56 -4.8,4.7 1.11,-1.5 2.58,-2.18 4.8,-2.18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mode.xml b/compose/material/material/icons/generator/raw-icons/rounded/mode.xml
index 89fee4c..1599eed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mode.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mode.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,17.46l0,3.04C3,20.78 3.22,21 3.5,21h3.04c0.13,0 0.26,-0.05 0.35,-0.15L17.81,9.94l-3.75,-3.75L3.15,17.1C3.05,17.2 3,17.32 3,17.46z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83l3.75,3.75l1.83,-1.83C21.1,6.65 21.1,6.02 20.71,5.63z"/>
+ android:pathData="M3,17.46v3.04c0,0.28 0.22,0.5 0.5,0.5h3.04c0.13,0 0.26,-0.05 0.35,-0.15L17.81,9.94l-3.75,-3.75L3.15,17.1c-0.1,0.1 -0.15,0.22 -0.15,0.36zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mode_comment.xml b/compose/material/material/icons/generator/raw-icons/rounded/mode_comment.xml
index 604f543..366bca7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mode_comment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mode_comment.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,4c0,-1.1 -0.9,-2 -2,-2H4C2.9,2 2,2.9 2,4v12c0,1.1 0.9,2 2,2h14l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71V4z"/>
+ android:pathData="M22,4c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4V4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mode_of_travel.xml b/compose/material/material/icons/generator/raw-icons/rounded/mode_of_travel.xml
new file mode 100644
index 0000000..79483f8
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mode_of_travel.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4,10.2C4,5.22 7.8,2 12,2c4,0 7.64,2.92 7.97,7.5l2.32,0c0.45,0 0.67,0.54 0.35,0.85l-3.29,3.29c-0.2,0.2 -0.51,0.2 -0.71,0l-3.29,-3.29c-0.31,-0.31 -0.09,-0.85 0.35,-0.85l2.26,0C17.65,6.24 15.13,4 12,4c-3.35,0 -6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14c0.64,-0.59 1.23,-1.16 1.77,-1.71c-0.17,-0.34 -0.27,-0.72 -0.27,-1.12c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S17.38,19 16,19c-0.24,0 -0.47,-0.03 -0.69,-0.1c-0.78,0.82 -1.67,1.66 -2.65,2.52c-0.38,0.33 -0.95,0.33 -1.33,0C6.45,17.12 4,13.38 4,10.2z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/monetization_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/monetization_on.xml
index ff39f5f..4c35f52 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/monetization_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/monetization_on.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12.84,17.77v0.39c0,0.46 -0.37,0.83 -0.83,0.83h0c-0.46,0 -0.83,-0.37 -0.83,-0.83v-0.45c-1.54,-0.35 -2.33,-1.32 -2.73,-2.11c-0.23,-0.44 -0.01,-0.99 0.45,-1.18l0.07,-0.03c0.41,-0.17 0.87,0 1.08,0.39c0.32,0.61 0.96,1.38 2.13,1.38c0.93,0 1.98,-0.47 1.98,-1.6c0,-0.96 -0.7,-1.47 -2.28,-2.03c-1.42,-0.51 -3.35,-1.17 -3.35,-3.31c0,-1.81 1.52,-2.75 2.66,-2.97V5.83C11.17,5.37 11.54,5 12,5h0c0.46,0 0.83,0.37 0.83,0.83v0.39c1.1,0.18 1.78,0.76 2.19,1.28c0.35,0.45 0.18,1.1 -0.34,1.33l0,0c-0.36,0.15 -0.78,0.04 -1.02,-0.27c-0.28,-0.38 -0.78,-0.77 -1.61,-0.77c-0.7,0 -1.81,0.37 -1.81,1.39c0,1.1 1.28,1.46 2.64,1.91c1.8,0.63 3.03,1.58 3.01,3.44C15.9,17.43 12.89,17.76 12.84,17.77z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13.41,18.09v0.58c0,0.73 -0.6,1.33 -1.33,1.33h-0.01c-0.73,0 -1.33,-0.6 -1.33,-1.33v-0.6c-1.33,-0.28 -2.51,-1.01 -3.01,-2.24 -0.23,-0.55 0.2,-1.16 0.8,-1.16h0.24c0.37,0 0.67,0.25 0.81,0.6 0.29,0.75 1.05,1.27 2.51,1.27 1.96,0 2.4,-0.98 2.4,-1.59 0,-0.83 -0.44,-1.61 -2.67,-2.14 -2.48,-0.6 -4.18,-1.62 -4.18,-3.67 0,-1.72 1.39,-2.84 3.11,-3.21v-0.6c0,-0.73 0.6,-1.33 1.33,-1.33h0.01c0.73,0 1.33,0.6 1.33,1.33v0.62c1.38,0.34 2.25,1.2 2.63,2.26 0.2,0.55 -0.22,1.13 -0.81,1.13h-0.26c-0.37,0 -0.67,-0.26 -0.77,-0.62 -0.23,-0.76 -0.86,-1.25 -2.12,-1.25 -1.5,0 -2.4,0.68 -2.4,1.64 0,0.84 0.65,1.39 2.67,1.91s4.18,1.39 4.18,3.91c-0.02,1.83 -1.39,2.83 -3.13,3.16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/money.xml b/compose/material/material/icons/generator/raw-icons/rounded/money.xml
index 7851417f..91fc2ea 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/money.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/money.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,10h1v4h-1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,10h1v4h-1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM7,15c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V15zM13,15c0,0.55 -0.45,1 -1,1H9c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1V15zM19,15c0,0.55 -0.45,1 -1,1h-3c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1V15z"/>
+ android:pathData="M15,16h3c0.55,0 1,-0.45 1,-1L19,9c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1zM16,10h1v4h-1v-4zM9,16h3c0.55,0 1,-0.45 1,-1L13,9c0,-0.55 -0.45,-1 -1,-1L9,8c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1zM10,10h1v4h-1v-4zM6,8c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1s1,-0.45 1,-1L7,9c0,-0.55 -0.45,-1 -1,-1zM2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2zM19,18L5,18c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/money_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/money_off.xml
index 73e5d61..cc4a1de 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/money_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/money_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.53,7.43c0.42,-0.31 0.93,-0.47 1.54,-0.47s1.11,0.16 1.5,0.49c0.17,0.14 0.32,0.3 0.44,0.46c0.27,0.37 0.77,0.48 1.19,0.3l0,0c0.61,-0.26 0.84,-1.03 0.43,-1.55c-0.22,-0.28 -0.48,-0.55 -0.79,-0.81c-0.5,-0.4 -1.12,-0.65 -1.85,-0.77V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1.11c-0.41,0.08 -0.79,0.21 -1.14,0.39c-0.35,0.18 -0.64,0.39 -0.9,0.63l1.43,1.43C10.43,7.52 10.48,7.47 10.53,7.43zM2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l11.64,11.64C13.31,16.85 12.79,17 12.19,17c-0.71,0 -1.32,-0.23 -1.83,-0.7c-0.28,-0.27 -0.52,-0.57 -0.71,-0.93c-0.25,-0.47 -0.8,-0.7 -1.3,-0.5l-0.09,0.04c-0.54,0.22 -0.81,0.86 -0.55,1.38c0.35,0.7 0.83,1.28 1.44,1.73c0.57,0.42 1.19,0.68 1.85,0.83V20c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-1.08c0.44,-0.07 0.87,-0.17 1.29,-0.35c0.34,-0.14 0.64,-0.32 0.92,-0.53l3.86,3.86c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M12.5,6.9c1.42,0 2.13,0.54 2.39,1.4 0.13,0.43 0.56,0.7 1.01,0.7h0.06c0.7,0 1.22,-0.71 0.97,-1.36 -0.44,-1.15 -1.41,-2.08 -2.93,-2.45V4.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S11,3.67 11,4.5v0.66c-0.39,0.08 -0.75,0.21 -1.1,0.36l1.51,1.51c0.32,-0.08 0.69,-0.13 1.09,-0.13zM4.77,4.62c-0.39,0.39 -0.39,1.02 0,1.41L7.5,8.77c0,2.08 1.56,3.22 3.91,3.91l3.51,3.51c-0.34,0.49 -1.05,0.91 -2.42,0.91 -1.65,0 -2.5,-0.59 -2.83,-1.43 -0.15,-0.39 -0.49,-0.67 -0.9,-0.67H8.6c-0.72,0 -1.24,0.74 -0.95,1.39 0.59,1.33 1.89,2.12 3.36,2.44v0.67c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-0.65c0.96,-0.18 1.83,-0.55 2.46,-1.12l1.51,1.51c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L6.18,4.62c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/money_off_csred.xml b/compose/material/material/icons/generator/raw-icons/rounded/money_off_csred.xml
index 73e5d61..cc4a1de 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/money_off_csred.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/money_off_csred.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.53,7.43c0.42,-0.31 0.93,-0.47 1.54,-0.47s1.11,0.16 1.5,0.49c0.17,0.14 0.32,0.3 0.44,0.46c0.27,0.37 0.77,0.48 1.19,0.3l0,0c0.61,-0.26 0.84,-1.03 0.43,-1.55c-0.22,-0.28 -0.48,-0.55 -0.79,-0.81c-0.5,-0.4 -1.12,-0.65 -1.85,-0.77V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1.11c-0.41,0.08 -0.79,0.21 -1.14,0.39c-0.35,0.18 -0.64,0.39 -0.9,0.63l1.43,1.43C10.43,7.52 10.48,7.47 10.53,7.43zM2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l11.64,11.64C13.31,16.85 12.79,17 12.19,17c-0.71,0 -1.32,-0.23 -1.83,-0.7c-0.28,-0.27 -0.52,-0.57 -0.71,-0.93c-0.25,-0.47 -0.8,-0.7 -1.3,-0.5l-0.09,0.04c-0.54,0.22 -0.81,0.86 -0.55,1.38c0.35,0.7 0.83,1.28 1.44,1.73c0.57,0.42 1.19,0.68 1.85,0.83V20c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-1.08c0.44,-0.07 0.87,-0.17 1.29,-0.35c0.34,-0.14 0.64,-0.32 0.92,-0.53l3.86,3.86c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M12.5,6.9c1.42,0 2.13,0.54 2.39,1.4 0.13,0.43 0.56,0.7 1.01,0.7h0.06c0.7,0 1.22,-0.71 0.97,-1.36 -0.44,-1.15 -1.41,-2.08 -2.93,-2.45V4.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S11,3.67 11,4.5v0.66c-0.39,0.08 -0.75,0.21 -1.1,0.36l1.51,1.51c0.32,-0.08 0.69,-0.13 1.09,-0.13zM4.77,4.62c-0.39,0.39 -0.39,1.02 0,1.41L7.5,8.77c0,2.08 1.56,3.22 3.91,3.91l3.51,3.51c-0.34,0.49 -1.05,0.91 -2.42,0.91 -1.65,0 -2.5,-0.59 -2.83,-1.43 -0.15,-0.39 -0.49,-0.67 -0.9,-0.67H8.6c-0.72,0 -1.24,0.74 -0.95,1.39 0.59,1.33 1.89,2.12 3.36,2.44v0.67c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-0.65c0.96,-0.18 1.83,-0.55 2.46,-1.12l1.51,1.51c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L6.18,4.62c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/monochrome_photos.xml b/compose/material/material/icons/generator/raw-icons/rounded/monochrome_photos.xml
index 1c254c4..d264781 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/monochrome_photos.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/monochrome_photos.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-3.17l-1.24,-1.35C15.22,3.24 14.68,3 14.12,3H9.88c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM20,19h-8v-1.5c-2.48,0 -4.5,-2.02 -4.5,-4.5c0,-2.48 2.02,-4.5 4.5,-4.5V7h8V19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.5,13c0,-2.48 -2.02,-4.5 -4.5,-4.5v2c1.38,0 2.5,1.12 2.5,2.5s-1.12,2.5 -2.5,2.5v2C14.48,17.5 16.5,15.48 16.5,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.5,13c0,1.38 1.12,2.5 2.5,2.5v-5C10.62,10.5 9.5,11.62 9.5,13z"/>
+ android:pathData="M20,5h-3.2l-1.2,-1.34c-0.38,-0.42 -0.92,-0.66 -1.49,-0.66L9.89,3c-0.57,0 -1.11,0.24 -1.49,0.66L7.2,5L4,5c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM20,18c0,0.55 -0.45,1 -1,1h-7v-1c-2.8,0 -5,-2.2 -5,-5s2.2,-5 5,-5L12,7h7c0.55,0 1,0.45 1,1v10zM17,13c0,-2.8 -2.2,-5 -5,-5v1.8c1.8,0 3.2,1.4 3.2,3.2s-1.4,3.2 -3.2,3.2L12,18c2.8,0 5,-2.2 5,-5zM8.8,13c0,1.8 1.4,3.2 3.2,3.2L12,9.8c-1.8,0 -3.2,1.4 -3.2,3.2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mood.xml b/compose/material/material/icons/generator/raw-icons/rounded/mood.xml
index af9fe28..4a1b68e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mood.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mood.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM16.75,14.75C15.8,16.39 14.03,17.5 12,17.5s-3.8,-1.11 -4.75,-2.75C7.06,14.42 7.31,14 7.69,14h8.62C16.7,14 16.94,14.42 16.75,14.75zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.03,0 3.8,-1.11 4.75,-2.75 0.19,-0.33 -0.05,-0.75 -0.44,-0.75L7.69,14c-0.38,0 -0.63,0.42 -0.44,0.75 0.95,1.64 2.72,2.75 4.75,2.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mood_bad.xml b/compose/material/material/icons/generator/raw-icons/rounded/mood_bad.xml
index 4ba2ae2..5832be0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mood_bad.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mood_bad.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM16.31,17H7.69c-0.38,0 -0.63,-0.42 -0.44,-0.75C8.2,14.61 9.97,13.5 12,13.5s3.8,1.11 4.75,2.75C16.94,16.58 16.7,17 16.31,17zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,13.5c-2.03,0 -3.8,1.11 -4.75,2.75 -0.19,0.33 0.06,0.75 0.44,0.75h8.62c0.38,0 0.63,-0.42 0.44,-0.75 -0.95,-1.64 -2.72,-2.75 -4.75,-2.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/moped.xml b/compose/material/material/icons/generator/raw-icons/rounded/moped.xml
index b5a51a4..918b767 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/moped.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/moped.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,7c0,-1.1 -0.9,-2 -2,-2h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2.65L13.52,14H10v-4c0,-0.55 -0.45,-1 -1,-1H6c-2.21,0 -4,1.79 -4,4v2c0,0.55 0.45,1 1,1h1c0,1.66 1.34,3 3,3s3,-1.34 3,-3h3.52c0.61,0 1.18,-0.28 1.56,-0.75l3.48,-4.35C18.85,10.54 19,10.1 19,9.65V7zM7,17c-0.55,0 -1,-0.45 -1,-1h2C8,16.55 7.55,17 7,17z"/>
+ android:pathData="M19,7c0,-1.1 -0.9,-2 -2,-2h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2.65L13.52,14H10v-4c0,-0.55 -0.45,-1 -1,-1H6c-2.21,0 -4,1.79 -4,4v3h2c0,1.66 1.34,3 3,3s3,-1.34 3,-3h4.48L19,10.35V7zM7,17c-0.55,0 -1,-0.45 -1,-1h2C8,16.55 7.55,17 7,17z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M6,6h3c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H6C5.45,8 5,7.55 5,7v0C5,6.45 5.45,6 6,6z"/>
+ android:pathData="M9,6H6C5.45,6 5,6.45 5,7v0c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v0C10,6.45 9.55,6 9,6z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19,13c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,13 19,13zM19,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1C20,16.55 19.55,17 19,17z"/>
+ android:pathData="M19,13c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,13 19,13zM19,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S19.55,17 19,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/more.xml b/compose/material/material/icons/generator/raw-icons/rounded/more.xml
index 79d7a59..3e254d6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/more.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/more.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,5H9C8.35,5 7.75,5.31 7.37,5.84l-3.55,5c-0.49,0.69 -0.49,1.62 0,2.32l3.55,5C7.75,18.69 8.35,19 9,19h10c1.1,0 2,-0.9 2,-2V7C21,5.9 20.1,5 19,5zM9.5,13c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C10.5,12.55 10.05,13 9.5,13zM13,13c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C14,12.55 13.55,13 13,13zM16.5,13c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C17.5,12.55 17.05,13 16.5,13z"/>
+ android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0.37,11.45c-0.22,0.34 -0.22,0.77 0,1.11l5.04,7.56c0.36,0.52 0.97,0.88 1.66,0.88L22,21c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM9,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM14,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/more_horiz.xml b/compose/material/material/icons/generator/raw-icons/rounded/more_horiz.xml
index b39c1f8b..6439bcc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/more_horiz.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/more_horiz.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S7.1,10 6,10zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S19.1,10 18,10zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,10 12,10z"/>
+ android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/more_time.xml b/compose/material/material/icons/generator/raw-icons/rounded/more_time.xml
index 189e55d..4250cae 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/more_time.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/more_time.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v4c0,0.27 0.11,0.52 0.29,0.71l2.79,2.79c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.5,-2.5V8zM22,4h-2V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6h2c0.55,0 1,-0.45 1,-1S22.55,4 22,4zM19,11c-0.55,0 -1,0.45 -1,1c0,3.86 -3.14,7 -7,7s-7,-3.14 -7,-7s3.14,-7 7,-7c0.3,0 0.59,0.02 0.88,0.05c0.55,0.08 1.05,-0.32 1.11,-0.87c0.07,-0.55 -0.32,-1.05 -0.87,-1.11C11.75,3.02 11.37,3 11,3c-4.96,0 -9,4.04 -9,9s4.04,9 9,9s9,-4.04 9,-9C20,11.45 19.55,11 19,11z"/>
+ android:pathData="M10.75,8C10.34,8 10,8.34 10,8.75v4.69c0,0.35 0.18,0.67 0.47,0.85l3.64,2.24c0.33,0.2 0.76,0.11 0.97,-0.21c0.23,-0.34 0.12,-0.8 -0.23,-1.01L11.5,13.3V8.75C11.5,8.34 11.16,8 10.75,8z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.92,12c0.05,0.33 0.08,0.66 0.08,1c0,3.9 -3.1,7 -7,7s-7,-3.1 -7,-7c0,-3.9 3.1,-7 7,-7c0.7,0 1.37,0.1 2,0.29V4.23C12.36,4.08 11.69,4 11,4c-5,0 -9,4 -9,9s4,9 9,9s9,-4 9,-9c0,-0.34 -0.02,-0.67 -0.06,-1H17.92z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,5h-2V3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7h2c0.55,0 1,-0.45 1,-1C23,5.45 22.55,5 22,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/more_vert.xml b/compose/material/material/icons/generator/raw-icons/rounded/more_vert.xml
index 17ead24..34b93ec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/more_vert.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/more_vert.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,16 12,16z"/>
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/mouse.xml b/compose/material/material/icons/generator/raw-icons/rounded/mouse.xml
index 3794bee..a19d2dd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/mouse.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/mouse.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,9h6c0,-3.53 -2.61,-6.43 -6,-6.92V9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5,11v4c0,3.87 3.13,7 7,7s7,-3.13 7,-7v-4H5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,2.08C7.61,2.57 5,5.47 5,9h6V2.08z"/>
+ android:pathData="M13,1.07L13,9h7c0,-4.08 -3.05,-7.44 -7,-7.93zM4,15c0,4.42 3.58,8 8,8s8,-3.58 8,-8v-4L4,11v4zM11,1.07C7.05,1.56 4,4.92 4,9h7L11,1.07z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/movie.xml b/compose/material/material/icons/generator/raw-icons/rounded/movie.xml
index 425d8a6..33a3e31 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/movie.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/movie.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4h-3l2,4h-3l-2,-4h-2l2,4h-3L9,4H7l2,4H6L4,4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4z"/>
+ android:pathData="M18,4l1.82,3.64c0.08,0.16 -0.04,0.36 -0.22,0.36h-1.98c-0.38,0 -0.73,-0.21 -0.89,-0.55L15,4h-2l1.82,3.64c0.08,0.16 -0.04,0.36 -0.22,0.36h-1.98c-0.38,0 -0.73,-0.21 -0.89,-0.55L10,4H8l1.82,3.64c0.08,0.16 -0.04,0.36 -0.22,0.36H7.62c-0.38,0 -0.73,-0.21 -0.9,-0.55L5,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V5c0,-0.55 -0.45,-1 -1,-1h-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/movie_creation.xml b/compose/material/material/icons/generator/raw-icons/rounded/movie_creation.xml
index 425d8a6..33a3e31 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/movie_creation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/movie_creation.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4h-3l2,4h-3l-2,-4h-2l2,4h-3L9,4H7l2,4H6L4,4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4z"/>
+ android:pathData="M18,4l1.82,3.64c0.08,0.16 -0.04,0.36 -0.22,0.36h-1.98c-0.38,0 -0.73,-0.21 -0.89,-0.55L15,4h-2l1.82,3.64c0.08,0.16 -0.04,0.36 -0.22,0.36h-1.98c-0.38,0 -0.73,-0.21 -0.89,-0.55L10,4H8l1.82,3.64c0.08,0.16 -0.04,0.36 -0.22,0.36H7.62c-0.38,0 -0.73,-0.21 -0.9,-0.55L5,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V5c0,-0.55 -0.45,-1 -1,-1h-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/movie_filter.xml b/compose/material/material/icons/generator/raw-icons/rounded/movie_filter.xml
index 3c6a82f..c32b03b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/movie_filter.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/movie_filter.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4h-3l2,4h-3l-2,-4h-2l2,4h-3L9,4H7l2,4H6L4,4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM10.44,14.94L9.5,17l-0.94,-2.06L6.5,14l2.06,-0.94L9.5,11l0.94,2.06L12.5,14L10.44,14.94zM16.13,13.63L15.5,15l-0.63,-1.37L13.5,13l1.37,-0.63L15.5,11l0.63,1.37L17.5,13L16.13,13.63z"/>
+ android:pathData="M21.5,4L18,4l1.74,2.61c0.11,0.17 -0.01,0.39 -0.21,0.39h-2c-0.33,0 -0.65,-0.17 -0.83,-0.45L15,4h-2l1.74,2.61c0.11,0.17 -0.01,0.39 -0.21,0.39h-2c-0.33,0 -0.65,-0.17 -0.83,-0.45L10,4L8,4l1.74,2.61c0.11,0.17 -0.01,0.39 -0.21,0.39h-2c-0.33,0 -0.64,-0.17 -0.83,-0.45L5,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM11.25,15.25L10,18l-1.25,-2.75L6,14l2.75,-1.25L10,10l1.25,2.75L14,14l-2.75,1.25zM16.94,11.94L16,14l-0.94,-2.06L13,11l2.06,-0.94L16,8l0.94,2.06L19,11l-2.06,0.94z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/multiline_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/multiline_chart.xml
index b42b951..14d85ba 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/multiline_chart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/multiline_chart.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.36,6.28L21.3,6.22c-0.39,-0.39 -1.03,-0.37 -1.39,0.04l-2.18,2.45C15.68,6.4 12.83,5 9.61,5c-2.5,0 -4.83,0.87 -6.75,2.3C2.39,7.65 2.34,8.34 2.75,8.75l0.06,0.06C3.14,9.14 3.67,9.2 4.04,8.92C5.63,7.72 7.54,7 9.61,7c2.74,0 5.09,1.26 6.77,3.24l-2.88,3.24l-3.29,-3.29c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.12,6.13c-0.37,0.37 -0.37,0.98 0,1.35l0.15,0.15c0.37,0.37 0.98,0.37 1.35,0l5.32,-5.33l3.25,3.25c0.41,0.41 1.07,0.39 1.45,-0.04l3.35,-3.76c0.62,1.12 1.08,2.39 1.32,3.73c0.08,0.47 0.47,0.82 0.95,0.82h0.09c0.6,0 1.05,-0.55 0.94,-1.14c-0.32,-1.85 -0.98,-3.54 -1.89,-5L21.4,7.6C21.74,7.22 21.72,6.64 21.36,6.28z"/>
+ android:pathData="M21.36,6.28l-0.06,-0.06c-0.39,-0.39 -1.03,-0.37 -1.39,0.04l-2.18,2.45C15.68,6.4 12.83,5 9.61,5c-2.5,0 -4.83,0.87 -6.75,2.3 -0.47,0.35 -0.52,1.04 -0.11,1.45l0.06,0.06c0.33,0.33 0.86,0.39 1.23,0.11C5.63,7.72 7.54,7 9.61,7c2.74,0 5.09,1.26 6.77,3.24l-2.88,3.24 -3.29,-3.29c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.12,6.13c-0.37,0.37 -0.37,0.98 0,1.35l0.15,0.15c0.37,0.37 0.98,0.37 1.35,0l5.32,-5.33 3.25,3.25c0.41,0.41 1.07,0.39 1.45,-0.04l3.35,-3.76c0.62,1.12 1.08,2.39 1.32,3.73 0.08,0.47 0.47,0.82 0.95,0.82h0.09c0.6,0 1.05,-0.55 0.94,-1.14 -0.32,-1.85 -0.98,-3.54 -1.89,-5L21.4,7.6c0.34,-0.38 0.32,-0.96 -0.04,-1.32z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/museum.xml b/compose/material/material/icons/generator/raw-icons/rounded/museum.xml
index cdadede..a184244 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/museum.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/museum.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,20h-1v-9h0.68C21.41,11 22,10.41 22,9.68c0,-0.43 -0.21,-0.83 -0.56,-1.08l-8.29,-5.8c-0.69,-0.48 -1.61,-0.48 -2.29,0l-8.29,5.8C2.21,8.85 2,9.26 2,9.68C2,10.41 2.59,11 3.32,11H4v9H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h18c0.55,0 1,-0.45 1,-1S21.55,20 21,20zM16,17c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3l-1.17,1.75c-0.4,0.59 -1.27,0.59 -1.66,0L10,14v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4.7C8,11.58 8.58,11 9.3,11c0.43,0 0.84,0.22 1.08,0.58L12,14l1.61,-2.42C13.86,11.22 14.26,11 14.7,11c0.72,0 1.3,0.58 1.3,1.3V17z"/>
+ android:pathData="M21.5,11c0.28,0 0.5,-0.22 0.5,-0.5V9.26c0,-0.16 -0.08,-0.32 -0.21,-0.41L12.57,2.4c-0.34,-0.24 -0.8,-0.24 -1.15,0L2.21,8.85C2.08,8.94 2,9.1 2,9.26v1.24C2,10.78 2.22,11 2.5,11H4v9H3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-1v-9H21.5zM16,17c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3l-1.17,1.75c-0.4,0.59 -1.27,0.59 -1.66,0L10,14v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-4.7C8,11.58 8.58,11 9.3,11h0c0.43,0 0.84,0.22 1.08,0.58L12,14l1.61,-2.42C13.86,11.22 14.26,11 14.7,11h0c0.72,0 1.3,0.58 1.3,1.3V17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/music_note.xml b/compose/material/material/icons/generator/raw-icons/rounded/music_note.xml
index a3ed653..20ed3cc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/music_note.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/music_note.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,5v8.55c-0.94,-0.54 -2.1,-0.75 -3.33,-0.32C7.33,13.71 6.3,14.9 6.06,16.3c-0.46,2.74 1.86,5.08 4.59,4.65c1.96,-0.31 3.35,-2.11 3.35,-4.1V7h2c1.1,0 2,-0.9 2,-2l0,0c0,-1.1 -0.9,-2 -2,-2h-2C12.9,3 12,3.9 12,5z"/>
+ android:pathData="M12,5v8.55c-0.94,-0.54 -2.1,-0.75 -3.33,-0.32 -1.34,0.48 -2.37,1.67 -2.61,3.07 -0.46,2.74 1.86,5.08 4.59,4.65 1.96,-0.31 3.35,-2.11 3.35,-4.1V7h2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-2c-1.1,0 -2,0.9 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/music_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/music_off.xml
index a517cda..af1ca73 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/music_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/music_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.49,21.9c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.03,-0.39 -1.42,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l8.09,8.09C7.11,13.01 6,15.44 6,17c0,2.21 1.79,4 4.01,4S14,19.21 14,17v-0.17l5.07,5.07C19.46,22.29 20.1,22.29 20.49,21.9L20.49,21.9zM14,11.17V7h2c1.1,0 2,-0.9 2,-2v0c0,-1.1 -0.9,-2 -2,-2h-3c-0.55,0 -1,0.45 -1,1v5.17L14,11.17z"/>
+ android:pathData="M14,9.61V7h2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-3c-0.55,0 -1,0.45 -1,1v3.61l2,2zM5.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l8.29,8.3v0.28c-0.94,-0.54 -2.1,-0.75 -3.33,-0.32 -1.34,0.48 -2.37,1.67 -2.61,3.07 -0.46,2.74 1.86,5.08 4.59,4.65 1.96,-0.31 3.35,-2.11 3.35,-4.1v-1.58l5.02,5.02c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.12,3.56z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/my_location.xml b/compose/material/material/icons/generator/raw-icons/rounded/my_location.xml
index 821714e..b861b63 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/my_location.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/my_location.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S14.21,8 12,8zM20.94,11C20.48,6.83 17.17,3.52 13,3.06V2c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11H2c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94V22c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94H22c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H20.94zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7s7,3.13 7,7S15.87,19 12,19z"/>
+ android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1.06C6.83,3.52 3.52,6.83 3.06,11L2,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1.06c0.46,4.17 3.77,7.48 7.94,7.94L11,22c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L22,13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/nat.xml b/compose/material/material/icons/generator/raw-icons/rounded/nat.xml
index 5ef3242..2d407c6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/nat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/nat.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.82,13H11v-2H6.82C6.4,9.84 5.3,9 4,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3C5.3,15 6.4,14.16 6.82,13zM4,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S4.55,13 4,13z"/>
+ android:pathData="M6.82,13H11v-2H6.82C6.4,9.84 5.3,9 4,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3C5.3,15 6.4,14.16 6.82,13zM4,13c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C5,12.55 4.55,13 4,13z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M22.65,11.65l-2.79,-2.79C19.54,8.54 19,8.76 19,9.21V11h-4.05c-0.46,-4.68 -4.16,-8.42 -8.84,-8.94C5.52,2 5,2.46 5,3.06v0c0,0.5 0.37,0.93 0.87,0.99C9.88,4.48 13,7.87 13,12s-3.12,7.52 -7.13,7.95C5.37,20.01 5,20.44 5,20.94v0c0,0.6 0.52,1.07 1.11,1c4.67,-0.52 8.37,-4.26 8.84,-8.94H19v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79C22.84,12.16 22.84,11.84 22.65,11.65z"/>
+ android:pathData="M22.47,12.4c0.27,-0.2 0.27,-0.6 0,-0.8L19,9v2h-4.05c-0.47,-4.69 -4.16,-8.42 -8.83,-8.94C5.52,2 5,2.46 5,3.06v0c0,0.5 0.37,0.93 0.87,0.99C9.88,4.48 13,7.87 13,12s-3.12,7.52 -7.13,7.95C5.37,20.01 5,20.44 5,20.94v0c0,0.6 0.52,1.07 1.11,1c4.67,-0.52 8.37,-4.25 8.83,-8.94H19v2L22.47,12.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/nature.xml b/compose/material/material/icons/generator/raw-icons/rounded/nature.xml
index 8e79159..271d883 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/nature.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/nature.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,16l1.78,0c2.63,0 4.98,-1.94 5.2,-4.56c0.19,-2.26 -1.12,-4.24 -3.04,-5.05C16.63,3.92 14.55,2 12,2S7.37,3.92 7.06,6.39C5.14,7.2 3.83,9.18 4.02,11.44C4.24,14.06 6.59,16 9.22,16L11,16v4H6c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-5V16z"/>
+ android:pathData="M13,16.12c3.37,-0.4 6.01,-3.19 6.16,-6.64 0.17,-3.87 -3.02,-7.25 -6.89,-7.31 -3.92,-0.05 -7.1,3.1 -7.1,7 0,3.47 2.52,6.34 5.83,6.89V20H6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-5v-3.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/nature_people.xml b/compose/material/material/icons/generator/raw-icons/rounded/nature_people.xml
index 9c90728..b64a50e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/nature_people.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/nature_people.xml
@@ -9,5 +9,5 @@
android:pathData="M4.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M16,15l1.56,0c2.23,0 4.22,-1.64 4.42,-3.86c0.17,-1.91 -0.93,-3.59 -2.55,-4.29C19.12,4.68 17.26,3 15,3s-4.12,1.68 -4.43,3.85c-1.62,0.7 -2.72,2.38 -2.55,4.29c0.2,2.22 2.19,3.86 4.42,3.86L14,15v5H6v-3h0.5C6.78,17 7,16.78 7,16.5V13c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1v3.5C2,16.78 2.22,17 2.5,17H3v4c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-4V15z"/>
+ android:pathData="M22.17,9.17c0,-3.91 -3.19,-7.06 -7.11,-7 -3.83,0.06 -6.99,3.37 -6.88,7.19 0.09,3.38 2.58,6.16 5.83,6.7V20H6v-3h0.5c0.28,0 0.5,-0.22 0.5,-0.5V13c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1v3.5c0,0.28 0.22,0.5 0.5,0.5H3v4c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2v-3.88c3.47,-0.41 6.17,-3.36 6.17,-6.95z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/navigate_before.xml b/compose/material/material/icons/generator/raw-icons/rounded/navigate_before.xml
index 7a17179..d39b55a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/navigate_before.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/navigate_before.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.29,15.46l-3.88,-3.88l3.88,-3.88c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l0,0C15.67,16.49 15.68,15.85 15.29,15.46z"/>
+ android:pathData="M14.91,6.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.91,11.3c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L11.03,12l3.88,-3.88c0.38,-0.39 0.38,-1.03 0,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/navigate_next.xml b/compose/material/material/icons/generator/raw-icons/rounded/navigate_next.xml
index 38fd791..725db07 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/navigate_next.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/navigate_next.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M9.29,15.46l3.88,-3.88L9.29,7.7c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l4.59,4.59c0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0l0,0C8.91,16.49 8.9,15.85 9.29,15.46z"/>
+ android:pathData="M9.31,6.71c-0.39,0.39 -0.39,1.02 0,1.41L13.19,12l-3.88,3.88c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L10.72,6.7c-0.38,-0.38 -1.02,-0.38 -1.41,0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/navigation.xml b/compose/material/material/icons/generator/raw-icons/rounded/navigation.xml
index 72bcc41..6eb8edc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/navigation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/navigation.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.93,4.26l6.15,14.99c0.34,0.83 -0.51,1.66 -1.33,1.29l-5.34,-2.36c-0.26,-0.11 -0.55,-0.11 -0.81,0l-5.34,2.36c-0.82,0.36 -1.67,-0.46 -1.33,-1.29l6.15,-14.99C11.41,3.43 12.59,3.43 12.93,4.26z"/>
+ android:pathData="M12.93,4.26l6.15,14.99c0.34,0.83 -0.51,1.66 -1.33,1.29l-5.34,-2.36c-0.26,-0.11 -0.55,-0.11 -0.81,0l-5.34,2.36c-0.82,0.36 -1.67,-0.46 -1.33,-1.29l6.15,-14.99c0.33,-0.83 1.51,-0.83 1.85,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/near_me.xml b/compose/material/material/icons/generator/raw-icons/rounded/near_me.xml
index e7c22f1..140db90 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/near_me.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/near_me.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.95,3.76L3.67,9.44C3.27,9.59 3,9.97 3,10.4v0c0,0.42 0.26,0.8 0.65,0.96l6.42,2.57l2.57,6.42C12.8,20.74 13.18,21 13.6,21h0c0.43,0 0.82,-0.27 0.97,-0.67l5.68,-15.28C20.54,4.24 19.76,3.46 18.95,3.76z"/>
+ android:pathData="M18.75,3.94L4.07,10.08c-0.83,0.35 -0.81,1.53 0.02,1.85L9.43,14c0.26,0.1 0.47,0.31 0.57,0.57l2.06,5.33c0.32,0.84 1.51,0.86 1.86,0.03l6.15,-14.67c0.33,-0.83 -0.5,-1.66 -1.32,-1.32z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/network_check.xml b/compose/material/material/icons/generator/raw-icons/rounded/network_check.xml
index 083d13a..e16bb9a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/network_check.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/network_check.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.79,4.84c-0.27,-0.1 -0.56,0.02 -0.69,0.27c-1.07,2.14 -5.64,11.28 -5.98,12.2c-0.38,1.04 0.16,2.19 1.2,2.56c1.04,0.38 2.19,-0.16 2.56,-1.2c0.28,-0.76 2.7,-10.84 3.26,-13.19C17.21,5.22 17.06,4.94 16.79,4.84z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22.8,7.89c-1.11,-0.92 -2.34,-1.69 -3.66,-2.31c-0.01,0.13 -0.02,0.26 -0.06,0.39c-0.21,0.86 -0.42,1.74 -0.63,2.63c0.86,0.45 1.67,0.98 2.41,1.59c0.6,0.49 1.47,0.46 2.02,-0.09l0,0C23.51,9.47 23.47,8.44 22.8,7.89z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.9,7.04c0.47,-0.95 0.95,-1.9 1.41,-2.82c0.01,-0.02 0.02,-0.03 0.03,-0.04C13.57,4.07 12.8,4 12,4C7.9,4 4.14,5.46 1.2,7.89C0.53,8.44 0.49,9.47 1.11,10.1l0,0c0.55,0.55 1.42,0.58 2.02,0.09C5.55,8.2 8.64,7 12,7C12.3,7 12.6,7.02 12.9,7.04z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.49,12.13c-0.25,-0.18 -0.51,-0.35 -0.77,-0.51c-0.26,1.07 -0.51,2.1 -0.74,3.04c0.56,0.23 1.2,0.15 1.64,-0.29C19.26,13.73 19.22,12.66 18.49,12.13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5.51,12.13c-0.72,0.53 -0.76,1.6 -0.13,2.24c0.53,0.54 1.37,0.57 1.98,0.12c0.73,-0.52 1.55,-0.91 2.43,-1.16c0.48,-0.98 1.03,-2.11 1.63,-3.31C9.21,10.14 7.18,10.9 5.51,12.13z"/>
+ android:pathData="M15.9,5c-0.17,0 -0.32,0.09 -0.41,0.23l-0.07,0.15 -5.18,11.65c-0.16,0.29 -0.26,0.61 -0.26,0.96 0,1.11 0.9,2.01 2.01,2.01 0.96,0 1.77,-0.68 1.96,-1.59l0.01,-0.03L16.4,5.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM2.06,10.06c0.51,0.51 1.33,0.55 1.89,0.09 2.76,-2.26 6.24,-3.18 9.58,-2.76l1.19,-2.68c-4.35,-0.78 -8.96,0.3 -12.57,3.25 -0.64,0.53 -0.68,1.51 -0.09,2.1zM21.94,10.06c0.59,-0.59 0.55,-1.57 -0.1,-2.1 -1.36,-1.11 -2.86,-1.95 -4.44,-2.53l-0.53,2.82c1.13,0.47 2.19,1.09 3.17,1.89 0.58,0.46 1.39,0.43 1.9,-0.08zM17.91,14.09c0.6,-0.6 0.56,-1.63 -0.14,-2.12 -0.46,-0.33 -0.94,-0.61 -1.44,-0.86l-0.55,2.92c0.11,0.07 0.22,0.14 0.32,0.22 0.57,0.4 1.33,0.32 1.81,-0.16zM6.08,14.08c0.5,0.5 1.27,0.54 1.85,0.13 0.94,-0.66 2.01,-1.06 3.1,-1.22l1.28,-2.88c-2.13,-0.06 -4.28,0.54 -6.09,1.84 -0.69,0.51 -0.74,1.53 -0.14,2.13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/new_label.xml b/compose/material/material/icons/generator/raw-icons/rounded/new_label.xml
new file mode 100644
index 0000000..2a32334
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/new_label.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.18,13.16l-3.55,5C16.25,18.69 15.65,19 15,19h-3l0,-2l0,-1c0,-1.66 -1.34,-3 -3,-3h0v0c0,-1.66 -1.34,-3 -3,-3H3V7c0,-1.1 0.9,-2 2,-2h10c0.65,0 1.26,0.31 1.63,0.84l3.55,5C20.67,11.54 20.67,12.46 20.18,13.16zM10,16c0,-0.55 -0.45,-1 -1,-1H7v-2c0,-0.55 -0.45,-1 -1,-1c-0.55,0 -1,0.45 -1,1v2H3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1c0.55,0 1,-0.45 1,-1v-2h2C9.55,17 10,16.55 10,16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/new_releases.xml b/compose/material/material/icons/generator/raw-icons/rounded/new_releases.xml
index 91a3fe0..8e8d522 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/new_releases.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/new_releases.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22.42,11.34l-1.86,-2.13l0.26,-2.82c0.05,-0.5 -0.29,-0.96 -0.77,-1.07L17.29,4.7l-1.44,-2.44c-0.26,-0.43 -0.79,-0.61 -1.26,-0.41L12,2.96L9.41,1.85c-0.46,-0.2 -1,-0.02 -1.25,0.41L6.71,4.69L3.96,5.31C3.47,5.42 3.13,5.87 3.18,6.37L3.44,9.2l-1.87,2.14c-0.33,0.38 -0.33,0.94 0,1.32l1.87,2.13l-0.26,2.83c-0.05,0.5 0.29,0.96 0.77,1.07l2.76,0.63l1.44,2.43c0.26,0.43 0.8,0.61 1.26,0.41L12,21.03l2.59,1.11c0.46,0.2 1,0.02 1.25,-0.41l1.44,-2.43l2.76,-0.63c0.49,-0.11 0.82,-0.57 0.77,-1.07l-0.26,-2.82l1.86,-2.13C22.75,12.28 22.75,11.72 22.42,11.34zM11.67,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1c0.55,0 1,0.45 1,1S12.22,17 11.67,17zM12.67,12c0,0.55 -0.45,1 -1,1c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1c0.55,0 1,0.45 1,1V12z"/>
+ android:pathData="M22.42,11.34l-1.86,-2.12 0.26,-2.81c0.05,-0.5 -0.29,-0.96 -0.77,-1.07l-2.76,-0.63 -1.44,-2.43c-0.26,-0.43 -0.79,-0.61 -1.25,-0.41L12,3 9.41,1.89c-0.46,-0.2 -1,-0.02 -1.25,0.41L6.71,4.72l-2.75,0.62c-0.49,0.11 -0.83,0.56 -0.78,1.07l0.26,2.8 -1.86,2.13c-0.33,0.38 -0.33,0.94 0,1.32l1.86,2.12 -0.26,2.82c-0.05,0.5 0.29,0.96 0.77,1.07l2.76,0.63 1.44,2.42c0.26,0.43 0.79,0.61 1.26,0.41L12,21l2.59,1.11c0.46,0.2 1,0.02 1.25,-0.41l1.44,-2.43 2.76,-0.63c0.49,-0.11 0.82,-0.57 0.77,-1.07l-0.26,-2.81 1.86,-2.12c0.34,-0.36 0.34,-0.92 0.01,-1.3zM13,17h-2v-2h2v2zM12,13c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/next_plan.xml b/compose/material/material/icons/generator/raw-icons/rounded/next_plan.xml
index dce5f23..190436f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/next_plan.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/next_plan.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM17.5,14h-3.29c-0.45,0 -0.67,-0.54 -0.35,-0.85l0.9,-0.9c-0.63,-1.05 -1.79,-1.76 -3.12,-1.76c-1.73,0 -3.17,1.17 -3.54,2.74C7.98,13.68 7.58,14 7.12,14h0c-0.65,0 -1.12,-0.61 -0.97,-1.24c0.58,-2.44 2.81,-4.27 5.48,-4.27c1.88,0 3.55,0.92 4.57,2.31l0.95,-0.95C17.46,9.54 18,9.76 18,10.21v3.29C18,13.78 17.78,14 17.5,14z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18,13.97h-5l2.26,-2.26c-0.91,-1.06 -2.25,-1.74 -3.76,-1.74c-2.37,0 -4.35,1.66 -4.86,3.88l-0.96,-0.32c0.64,-2.62 3,-4.56 5.82,-4.56c1.78,0 3.37,0.79 4.47,2.03L18,8.97V13.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/next_week.xml b/compose/material/material/icons/generator/raw-icons/rounded/next_week.xml
index 026eb64..07d1cf5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/next_week.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/next_week.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-4V4c0,-0.55 -0.22,-1.05 -0.59,-1.41C15.05,2.22 14.55,2 14,2h-4C8.9,2 8,2.9 8,4v2H4C2.9,6 2,6.9 2,8v11c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM10,4h4v2h-4V4zM14.3,14.2l-2.59,2.59c-0.39,0.39 -1.02,0.39 -1.41,0h0c-0.39,-0.39 -0.39,-1.02 0,-1.41l1.89,-1.89l-1.89,-1.89c-0.39,-0.39 -0.39,-1.02 0,-1.41c0.39,-0.39 1.02,-0.39 1.41,0l2.59,2.59C14.68,13.18 14.68,13.82 14.3,14.2z"/>
+ android:pathData="M20,7h-4L16,5c0,-0.55 -0.22,-1.05 -0.59,-1.41C15.05,3.22 14.55,3 14,3h-4c-1.1,0 -2,0.9 -2,2v2L4,7c-1.1,0 -2,0.9 -2,2v11c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,9c0,-1.1 -0.9,-2 -2,-2zM10,5h4v2h-4L10,5zM10.5,18c-0.28,-0.28 -0.28,-0.72 0,-1l2.5,-2.5 -2.5,-2.5c-0.28,-0.28 -0.28,-0.72 0,-1s0.72,-0.28 1,0l3.15,3.15c0.2,0.2 0.2,0.51 0,0.71L11.5,18c-0.28,0.28 -0.72,0.28 -1,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/nfc.xml b/compose/material/material/icons/generator/raw-icons/rounded/nfc.xml
index 86c64bf..576fb0e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/nfc.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/nfc.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19zM15,17H9c-1.1,0 -2,-0.9 -2,-2V9c0,-1.1 0.9,-2 2,-2h1v2H9v6h6V9h-2v1.28c0.6,0.35 1,0.98 1,1.72c0,1.27 -1.17,2.25 -2.48,1.94c-0.71,-0.17 -1.3,-0.75 -1.47,-1.46c-0.22,-0.93 0.22,-1.78 0.95,-2.2V9c0,-1.1 0.9,-2 2,-2h2c1.1,0 2,0.9 2,2v6C17,16.1 16.1,17 15,17z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM19,20L5,20c-0.55,0 -1,-0.45 -1,-1L4,5c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v14c0,0.55 -0.45,1 -1,1zM16,6h-3c-1.1,0 -2,0.9 -2,2v2.28c-0.6,0.35 -1,0.98 -1,1.72 0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-0.74 -0.4,-1.38 -1,-1.72L13,8h3v7c0,0.55 -0.45,1 -1,1L9,16c-0.55,0 -1,-0.45 -1,-1L8,8h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,6c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,8c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/nights_stay.xml b/compose/material/material/icons/generator/raw-icons/rounded/nights_stay.xml
index 018efb7..af57e5d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/nights_stay.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/nights_stay.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.83,16.9c-3.15,-0.26 -6.12,-2.01 -7.82,-4.95C10.3,9 10.28,5.56 11.63,2.7c0.16,-0.35 -0.13,-0.73 -0.52,-0.69c-2.14,0.19 -4.3,1.06 -6.06,2.76c-2.09,2 -3.15,4.83 -3.03,7.65C2.63,12.15 3.3,12 4,12c1.65,0 3.17,0.83 4.1,2.15C9.77,14.63 11,16.17 11,18c0,1.49 -0.83,2.78 -2.04,3.46c2.59,0.83 5.5,0.61 8.04,-0.86c1.3,-0.75 2.37,-1.76 3.18,-2.92C20.4,17.38 20.22,16.93 19.83,16.9zM7,16H6.82C6.4,14.84 5.3,14 4,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3h3c1.1,0 2,-0.9 2,-2S8.1,16 7,16z"/>
+ android:pathData="M11.1,12.08c-2,-3.88 -0.92,-7.36 0.07,-9.27c0.19,-0.36 -0.12,-0.77 -0.53,-0.72C5.62,2.77 1.78,7.16 1.99,12.41c0.01,0 0.01,0 0.01,0.01C2.62,12.15 3.29,12 4,12c1.66,0 3.18,0.83 4.1,2.15C9.77,14.63 11,16.17 11,18c0,1.52 -0.87,2.83 -2.12,3.51c0.98,0.32 2.03,0.5 3.11,0.5c3.13,0 5.92,-1.44 7.76,-3.69c0.26,-0.32 0.04,-0.79 -0.37,-0.82C16.89,17.37 13.1,15.97 11.1,12.08z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,16l-0.18,0C6.4,14.84 5.3,14 4,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.62,0 2.49,0 3,0c1.1,0 2,-0.9 2,-2C9,16.9 8.1,16 7,16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/no_encryption.xml b/compose/material/material/icons/generator/raw-icons/rounded/no_encryption.xml
index 37dfadb..38f058b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/no_encryption.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/no_encryption.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2h-4.17L20,17.17V10c0,-1.1 -0.9,-2 -2,-2h-1V6c0,-2.76 -2.24,-5 -5,-5C9.79,1 7.93,2.45 7.27,4.44L9,6.17V6zM21.19,21.19L2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22L5.3,8.13C4.55,8.42 4,9.15 4,10v10c0,1.1 0.9,2 2,2h12c0.34,0 0.65,-0.09 0.93,-0.24l0.85,0.85c0.39,0.39 1.02,0.39 1.41,0C21.58,22.22 21.58,21.58 21.19,21.19zM12,17c-1.1,0 -2,-0.9 -2,-2c0,-0.59 0.27,-1.12 0.68,-1.49l2.81,2.81C13.12,16.73 12.59,17 12,17z"/>
+ android:pathData="M8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2h-4.66L20,17.56L20,10c0,-1.1 -0.9,-2 -2,-2h-1L17,6c0,-2.76 -2.24,-5 -5,-5 -2.32,0 -4.26,1.59 -4.82,3.74L8.9,6.46L8.9,6zM5.12,5.51c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l1.33,1.33C4.42,8.6 4,9.25 4,10v10c0,1.1 0.9,2 2,2h12.78l0.29,0.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.12,5.51z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/no_encryption_gmailerrorred.xml b/compose/material/material/icons/generator/raw-icons/rounded/no_encryption_gmailerrorred.xml
index 37dfadb..38f058b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/no_encryption_gmailerrorred.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/no_encryption_gmailerrorred.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2h-4.17L20,17.17V10c0,-1.1 -0.9,-2 -2,-2h-1V6c0,-2.76 -2.24,-5 -5,-5C9.79,1 7.93,2.45 7.27,4.44L9,6.17V6zM21.19,21.19L2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22L5.3,8.13C4.55,8.42 4,9.15 4,10v10c0,1.1 0.9,2 2,2h12c0.34,0 0.65,-0.09 0.93,-0.24l0.85,0.85c0.39,0.39 1.02,0.39 1.41,0C21.58,22.22 21.58,21.58 21.19,21.19zM12,17c-1.1,0 -2,-0.9 -2,-2c0,-0.59 0.27,-1.12 0.68,-1.49l2.81,2.81C13.12,16.73 12.59,17 12,17z"/>
+ android:pathData="M8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2h-4.66L20,17.56L20,10c0,-1.1 -0.9,-2 -2,-2h-1L17,6c0,-2.76 -2.24,-5 -5,-5 -2.32,0 -4.26,1.59 -4.82,3.74L8.9,6.46L8.9,6zM5.12,5.51c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l1.33,1.33C4.42,8.6 4,9.25 4,10v10c0,1.1 0.9,2 2,2h12.78l0.29,0.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.12,5.51z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/no_meeting_room.xml b/compose/material/material/icons/generator/raw-icons/rounded/no_meeting_room.xml
index 428456b..65f82f8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/no_meeting_room.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/no_meeting_room.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,6h3v8.17l2,2V5c0,-0.55 -0.45,-1 -1,-1h-4c0,-0.55 -0.45,-1 -1,-1H6C5.95,3 5.91,3.02 5.86,3.03L14,11.17V6zM20.49,20.49L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41L5,7.83V19H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h9c0.55,0 1,-0.45 1,-1v-3.17l5.07,5.07c0.39,0.39 1.02,0.39 1.41,0C20.88,21.51 20.88,20.88 20.49,20.49z"/>
+ android:pathData="M14,6h3v7.88l2,2L19,5c0,-0.55 -0.45,-1 -1,-1h-4c0,-0.55 -0.45,-1 -1,-1L6.12,3L14,10.88L14,6zM21.17,20.88L12,11.71L12,13h-2v-2h1.29L3.12,2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L5,7.54L5,19L4,19c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h9c0.55,0 1,-0.45 1,-1v-3.46l5.75,5.75c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.39 0.4,-1.02 0.01,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/no_sim.xml b/compose/material/material/icons/generator/raw-icons/rounded/no_sim.xml
index e0272d8..f292c9b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/no_sim.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/no_sim.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M1.39,2.81L1.39,2.81C1,3.2 1,3.83 1.39,4.22l3.19,3.19L4,8v12c0,1.1 0.9,2 2,2h12.01c0.34,0 0.65,-0.09 0.92,-0.24l0.85,0.85c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81C2.42,2.42 1.78,2.42 1.39,2.81z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,17.17L19.99,4c0,-1.1 -0.89,-2 -1.99,-2h-8L7.41,4.59L20,17.17z"/>
+ android:pathData="M3.09,4.44c-0.39,0.39 -0.39,1.02 0,1.41l2.03,2.03 -0.12,0.13V19c0,1.1 0.9,2 2,2h10c0.35,0 0.68,-0.1 0.97,-0.26l1.17,1.17c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.5,4.44c-0.39,-0.39 -1.02,-0.39 -1.41,0zM19,16.11V5c0,-1.1 -0.9,-2 -2,-2h-6.99L7.95,5.06 19,16.11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/not_interested.xml b/compose/material/material/icons/generator/raw-icons/rounded/not_interested.xml
index cb2d8a7..b5c518b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/not_interested.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/not_interested.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8c0,-1.85 0.63,-3.55 1.69,-4.9L16.9,18.31C15.55,19.37 13.85,20 12,20zM18.31,16.9L7.1,5.69C8.45,4.63 10.15,4 12,4c4.42,0 8,3.58 8,8C20,13.85 19.37,15.55 18.31,16.9z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8 0,-1.85 0.63,-3.55 1.69,-4.9L16.9,18.31C15.55,19.37 13.85,20 12,20zM18.31,16.9L7.1,5.69C8.45,4.63 10.15,4 12,4c4.42,0 8,3.58 8,8 0,1.85 -0.63,3.55 -1.69,4.9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/note.xml b/compose/material/material/icons/generator/raw-icons/rounded/note.xml
index f7e8db9..69b9f82 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/note.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/note.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.41,9.41l-4.83,-4.83C16.21,4.21 15.7,4 15.17,4H4C2.9,4 2,4.9 2,6v12.01C2,19.11 2.89,20 3.99,20H20c1.1,0 2,-0.9 2,-2v-7.17C22,10.3 21.79,9.79 21.41,9.41zM15,5.5l5.5,5.5H16c-0.55,0 -1,-0.45 -1,-1V5.5z"/>
+ android:pathData="M21.41,9.41l-4.83,-4.83c-0.37,-0.37 -0.88,-0.58 -1.41,-0.58H4c-1.1,0 -2,0.9 -2,2v12.01c0,1.1 0.89,1.99 1.99,1.99H20c1.1,0 2,-0.9 2,-2v-7.17c0,-0.53 -0.21,-1.04 -0.59,-1.42zM15,5.5l5.5,5.5H16c-0.55,0 -1,-0.45 -1,-1V5.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/note_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/note_add.xml
index 1875128..881b623 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/note_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/note_add.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.41,7.41l-4.83,-4.83C14.21,2.21 13.7,2 13.17,2H6C4.9,2 4.01,2.9 4.01,4L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8.83C20,8.3 19.79,7.79 19.41,7.41zM15,15h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2H9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1S15.55,15 15,15zM13,7V3.5L18.5,9H15C13.9,9 13,8.1 13,7z"/>
+ android:pathData="M14.59,2.59c-0.38,-0.38 -0.89,-0.59 -1.42,-0.59L6,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.82,-4.83zM15,16h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2L9,16c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM13,8L13,3.5L18.5,9L14,9c-0.55,0 -1,-0.45 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/notes.xml b/compose/material/material/icons/generator/raw-icons/rounded/notes.xml
index 960a487..fc3306c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/notes.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/notes.xml
@@ -7,11 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,11H4c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0C21,11.45 20.55,11 20,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,18h10c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,17.55 3.45,18 4,18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,6H4C3.45,6 3,6.45 3,7v0.01c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1V7C21,6.45 20.55,6 20,6z"/>
+ android:pathData="M20,11H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM4,18h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM20,6H4c-0.55,0 -1,0.45 -1,1v0.01c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/notification_important.xml b/compose/material/material/icons/generator/raw-icons/rounded/notification_important.xml
index 99e856c..4279646 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/notification_important.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/notification_important.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,17h-1v-7c0,-2.79 -1.91,-5.14 -4.5,-5.8V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5v0.7C7.91,4.86 6,7.21 6,10v7H5c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1C20,17.45 19.55,17 19,17zM12,16c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C13,15.55 12.55,16 12,16zM13,12c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V12z"/>
+ android:pathData="M12,23c1.1,0 1.99,-0.89 1.99,-1.99h-3.98c0,1.1 0.89,1.99 1.99,1.99zM20.29,18.29L19,17v-6c0,-3.35 -2.36,-6.15 -5.5,-6.83L13.5,3c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v1.17C7.36,4.85 5,7.65 5,11v6l-1.29,1.29c-0.63,0.63 -0.19,1.71 0.7,1.71h15.17c0.9,0 1.34,-1.08 0.71,-1.71zM13,16h-2v-2h2v2zM13,11c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/notifications.xml b/compose/material/material/icons/generator/raw-icons/rounded/notifications.xml
index 0961c2a..1ccc080 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/notifications.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/notifications.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,17v-7c0,-2.79 -1.91,-5.14 -4.5,-5.8V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5v0.7C7.91,4.86 6,7.21 6,10v7H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
+ android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-1.29,1.29c-0.63,0.63 -0.19,1.71 0.7,1.71h13.17c0.89,0 1.34,-1.08 0.71,-1.71L18,16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/notifications_active.xml b/compose/material/material/icons/generator/raw-icons/rounded/notifications_active.xml
index 7ea76ef..af6e83a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/notifications_active.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/notifications_active.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22zM18,10c0,-2.79 -1.91,-5.14 -4.5,-5.8V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5v0.7C7.91,4.86 6,7.21 6,10v7H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1V10zM6.15,3.15L6.15,3.15c-0.4,-0.4 -1.05,-0.39 -1.44,0.02C3.27,4.7 2.31,6.69 2.06,8.89C2,9.48 2.47,10 3.06,10h0c0.5,0 0.93,-0.37 0.99,-0.87c0.19,-1.77 0.97,-3.37 2.12,-4.61C6.54,4.14 6.53,3.53 6.15,3.15zM17.86,3.16L17.86,3.16c-0.38,0.38 -0.39,0.99 -0.02,1.38c1.16,1.23 1.93,2.83 2.12,4.6c0.05,0.5 0.49,0.87 0.99,0.87h0c0.6,0 1.07,-0.52 1,-1.11c-0.24,-2.2 -1.2,-4.18 -2.64,-5.71C18.91,2.77 18.26,2.76 17.86,3.16z"/>
+ android:pathData="M18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.68,-1.5 -1.51,-1.5S10.5,3.17 10.5,4v0.68C7.63,5.36 6,7.92 6,11v5l-1.3,1.29c-0.63,0.63 -0.19,1.71 0.7,1.71h13.17c0.89,0 1.34,-1.08 0.71,-1.71L18,16zM11.99,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM6.77,4.73c0.42,-0.38 0.43,-1.03 0.03,-1.43 -0.38,-0.38 -1,-0.39 -1.39,-0.02C3.7,4.84 2.52,6.96 2.14,9.34c-0.09,0.61 0.38,1.16 1,1.16 0.48,0 0.9,-0.35 0.98,-0.83 0.3,-1.94 1.26,-3.67 2.65,-4.94zM18.6,3.28c-0.4,-0.37 -1.02,-0.36 -1.4,0.02 -0.4,0.4 -0.38,1.04 0.03,1.42 1.38,1.27 2.35,3 2.65,4.94 0.07,0.48 0.49,0.83 0.98,0.83 0.61,0 1.09,-0.55 0.99,-1.16 -0.38,-2.37 -1.55,-4.48 -3.25,-6.05z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/notifications_none.xml b/compose/material/material/icons/generator/raw-icons/rounded/notifications_none.xml
index 0961c2a..0c3442b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/notifications_none.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/notifications_none.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,17v-7c0,-2.79 -1.91,-5.14 -4.5,-5.8V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5v0.7C7.91,4.86 6,7.21 6,10v7H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
+ android:pathData="M19.29,17.29L18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-1.29,1.29c-0.63,0.63 -0.19,1.71 0.7,1.71h13.17c0.9,0 1.34,-1.08 0.71,-1.71zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6zM12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/notifications_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/notifications_off.xml
index ad6de91..490cf79 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/notifications_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/notifications_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,10c0,-2.79 -1.91,-5.14 -4.5,-5.8V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5v0.7C9.64,4.42 8.87,4.84 8.21,5.38L18,15.17V10zM12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22zM20.49,20.49L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l4,4C6.04,9.28 6,9.63 6,10v7H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h11.17l2.9,2.9c0.39,0.39 1.02,0.39 1.41,0C20.88,21.51 20.88,20.88 20.49,20.49z"/>
+ android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.24,0.06 -0.47,0.15 -0.69,0.23L18,13.1L18,11zM5.41,3.35L4,4.76l2.81,2.81C6.29,8.57 6,9.73 6,11v5l-1.29,1.29c-0.63,0.63 -0.19,1.71 0.7,1.71h12.83l1.74,1.74 1.41,-1.41L5.41,3.35z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/notifications_paused.xml b/compose/material/material/icons/generator/raw-icons/rounded/notifications_paused.xml
index 8c7cea9..5dec0e2a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/notifications_paused.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/notifications_paused.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,17h-1v-7c0,-2.79 -1.91,-5.14 -4.5,-5.8V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5v0.7C7.91,4.86 6,7.21 6,10v7H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1S19.55,17 19,17zM13.85,14.2c0.5,0 0.9,0.4 0.9,0.9c0,0.5 -0.4,0.9 -0.9,0.9h-3.27c-0.73,0 -1.33,-0.6 -1.33,-1.33c0,-0.3 0.1,-0.6 0.3,-0.84L12,10.8h-1.85c-0.5,0 -0.9,-0.4 -0.9,-0.9c0,-0.5 0.4,-0.9 0.9,-0.9h3.27c0.73,0 1.33,0.6 1.33,1.33c0,0.3 -0.1,0.6 -0.3,0.84L12,14.2H13.85zM12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
+ android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM19.29,17.29L18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-1.29,1.29c-0.63,0.63 -0.19,1.71 0.7,1.71h13.17c0.9,0 1.34,-1.08 0.71,-1.71zM14.5,9.33c0,0.31 -0.11,0.6 -0.3,0.84l-2.5,3.03h1.9c0.5,0 0.9,0.4 0.9,0.9s-0.4,0.9 -0.9,0.9h-2.78c-0.73,0 -1.32,-0.59 -1.32,-1.32v-0.01c0,-0.31 0.11,-0.6 0.3,-0.84l2.5,-3.03h-1.9c-0.5,0 -0.9,-0.4 -0.9,-0.9s0.4,-0.9 0.9,-0.9h2.78c0.73,0 1.32,0.59 1.32,1.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/offline_bolt.xml b/compose/material/material/icons/generator/raw-icons/rounded/offline_bolt.xml
index ed13ce5..0a6275f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/offline_bolt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/offline_bolt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM11.39,16.93V13.5H9.08c-0.38,0 -0.62,-0.4 -0.44,-0.73l3.17,-5.99c0.24,-0.46 0.94,-0.29 0.94,0.23v3.49h2.18c0.37,0 0.62,0.4 0.44,0.73l-3.04,5.93C12.1,17.62 11.39,17.45 11.39,16.93z"/>
+ android:pathData="M12,2.02c-5.51,0 -9.98,4.47 -9.98,9.98s4.47,9.98 9.98,9.98 9.98,-4.47 9.98,-9.98S17.51,2.02 12,2.02zM11.48,17.88v-4.14L8.82,13.74c-0.37,0 -0.62,-0.4 -0.44,-0.73l3.68,-7.17c0.23,-0.47 0.94,-0.3 0.94,0.23v4.19h2.54c0.37,0 0.61,0.39 0.45,0.72l-3.56,7.12c-0.24,0.48 -0.95,0.31 -0.95,-0.22z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/offline_pin.xml b/compose/material/material/icons/generator/raw-icons/rounded/offline_pin.xml
index f029095..c141193 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/offline_pin.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/offline_pin.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM15,17H9c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v0C16,16.55 15.55,17 15,17zM10.23,13.29l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-4.24,4.24C11.26,13.68 10.62,13.68 10.23,13.29z"/>
+ android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10 10,-4.5 10,-10S17.5,2 12,2zM16,18L8,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM9.59,13.29L7.7,11.4c-0.39,-0.39 -0.39,-1.01 0,-1.4 0.39,-0.39 1.01,-0.39 1.4,0l1.2,1.2 4.6,-4.6c0.39,-0.39 1.01,-0.39 1.4,0 0.39,0.39 0.39,1.01 0,1.4l-5.29,5.29c-0.39,0.39 -1.03,0.39 -1.42,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/ondemand_video.xml b/compose/material/material/icons/generator/raw-icons/rounded/ondemand_video.xml
index 82b73d0..0b5376d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/ondemand_video.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/ondemand_video.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h4c1.1,0 1.99,-0.9 1.99,-2L22,5C22,3.9 21.1,3 20,3zM20,17H4V5h16V17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.5,8.33v5.34c0,0.79 0.88,1.27 1.54,0.84l4.15,-2.67c0.61,-0.39 0.61,-1.29 0,-1.68l-4.15,-2.67C10.38,7.06 9.5,7.54 9.5,8.33z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.11 -0.9,-2 -2,-2zM20,17L4,17c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1zM14.48,11.87l-3.98,2.28c-0.67,0.38 -1.5,-0.11 -1.5,-0.87L9,8.72c0,-0.77 0.83,-1.25 1.5,-0.87l3.98,2.28c0.67,0.39 0.67,1.35 0,1.74z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/open_in_browser.xml b/compose/material/material/icons/generator/raw-icons/rounded/open_in_browser.xml
index 40d4aa6..cccbfb0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/open_in_browser.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/open_in_browser.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.89,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5V7h14v12h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2V5C21,3.9 20.11,3 19,3zM11.65,11.35l-2.79,2.79C8.54,14.46 8.76,15 9.21,15H11v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79C12.16,11.16 11.84,11.16 11.65,11.35z"/>
+ android:pathData="M19,4L5,4c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,18L5,8h14v10h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.89,-2 -2,-2zM11.65,10.35l-2.79,2.79c-0.32,0.32 -0.1,0.86 0.35,0.86L11,14v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79c-0.19,-0.2 -0.51,-0.2 -0.7,-0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/open_in_new.xml b/compose/material/material/icons/generator/raw-icons/rounded/open_in_new.xml
index b5a083f..cb047ff 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/open_in_new.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/open_in_new.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,12L20,12c-0.55,0 -1,0.45 -1,1v6H5V5h6c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-6C21,12.45 20.55,12 20,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.5,3h-5.29c-0.45,0 -0.67,0.54 -0.35,0.85l1.94,1.94L9,13.59C8.61,13.98 8.61,14.61 9,15h0c0.39,0.39 1.02,0.39 1.41,0l7.79,-7.79l1.94,1.94C20.46,9.46 21,9.24 21,8.79V3.5C21,3.22 20.78,3 20.5,3z"/>
+ android:pathData="M18,19H6c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v5c0,0.55 -0.45,1 -1,1zM14,4c0,0.55 0.45,1 1,1h2.59l-9.13,9.13c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L19,6.41V9c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1h-5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/open_with.xml b/compose/material/material/icons/generator/raw-icons/rounded/open_with.xml
index b12a8dc..1d51634 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/open_with.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/open_with.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.5,9h3C13.78,9 14,8.78 14,8.5V6h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-3.79,-3.79c-0.2,-0.2 -0.51,-0.2 -0.71,0L7.85,5.15C7.54,5.46 7.76,6 8.21,6H10v2.5C10,8.78 10.22,9 10.5,9zM8.5,10H6V8.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-3.79,3.79c-0.2,0.2 -0.2,0.51 0,0.71l3.79,3.79C5.46,16.46 6,16.24 6,15.79V14h2.5C8.78,14 9,13.78 9,13.5v-3C9,10.22 8.78,10 8.5,10zM22.65,11.65l-3.79,-3.79C18.54,7.54 18,7.76 18,8.21V10h-2.5c-0.28,0 -0.5,0.22 -0.5,0.5v3c0,0.28 0.22,0.5 0.5,0.5H18v1.79c0,0.45 0.54,0.67 0.85,0.35l3.79,-3.79C22.84,12.16 22.84,11.84 22.65,11.65zM13.5,15h-3c-0.28,0 -0.5,0.22 -0.5,0.5V18H8.21c-0.45,0 -0.67,0.54 -0.35,0.85l3.79,3.79c0.2,0.2 0.51,0.2 0.71,0l3.79,-3.79C16.46,18.54 16.24,18 15.8,18H14v-2.5C14,15.22 13.78,15 13.5,15z"/>
+ android:pathData="M10.5,9h3c0.28,0 0.5,-0.22 0.5,-0.5L14,6h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-3.79,-3.79c-0.2,-0.2 -0.51,-0.2 -0.71,0L7.85,5.15c-0.31,0.31 -0.09,0.85 0.36,0.85L10,6v2.5c0,0.28 0.22,0.5 0.5,0.5zM8.5,10L6,10L6,8.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-3.79,3.79c-0.2,0.2 -0.2,0.51 0,0.71l3.79,3.79c0.31,0.31 0.85,0.09 0.85,-0.36L6,14h2.5c0.28,0 0.5,-0.22 0.5,-0.5v-3c0,-0.28 -0.22,-0.5 -0.5,-0.5zM22.65,11.65l-3.79,-3.79c-0.32,-0.32 -0.86,-0.1 -0.86,0.35L18,10h-2.5c-0.28,0 -0.5,0.22 -0.5,0.5v3c0,0.28 0.22,0.5 0.5,0.5L18,14v1.79c0,0.45 0.54,0.67 0.85,0.35l3.79,-3.79c0.2,-0.19 0.2,-0.51 0.01,-0.7zM13.5,15h-3c-0.28,0 -0.5,0.22 -0.5,0.5L10,18L8.21,18c-0.45,0 -0.67,0.54 -0.35,0.85l3.79,3.79c0.2,0.2 0.51,0.2 0.71,0l3.79,-3.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85L14,18v-2.5c0,-0.28 -0.22,-0.5 -0.5,-0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/outdoor_grill.xml b/compose/material/material/icons/generator/raw-icons/rounded/outdoor_grill.xml
index 9149c01..2c12759 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/outdoor_grill.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/outdoor_grill.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,22c1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3c-1.3,0 -2.4,0.84 -2.82,2H9.14l1.99,-3.06C11.42,14.98 11.71,15 12,15s0.58,-0.02 0.87,-0.06l1.02,1.57c0.42,-0.53 0.96,-0.95 1.6,-1.21l-0.6,-0.93c2.1,-0.95 3.64,-2.9 4.02,-5.24C19.01,8.54 18.52,8 17.92,8C15.31,8 8.69,8 6.08,8c-0.6,0 -1.09,0.54 -0.99,1.14c0.38,2.34 1.93,4.29 4.02,5.24l-3.95,6.08c-0.3,0.46 -0.17,1.08 0.29,1.38l0,0c0.46,0.3 1.08,0.17 1.38,-0.29l1,-1.55h6.34C14.6,21.16 15.7,22 17,22zM17,18c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S16.45,18 17,18z"/>
+ android:pathData="M17,22c1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3c-1.3,0 -2.4,0.84 -2.82,2H9.14l1.99,-3.06C11.42,14.98 11.71,15 12,15s0.58,-0.02 0.87,-0.06l1.02,1.57c0.42,-0.53 0.96,-0.95 1.6,-1.21l-0.6,-0.93c2.1,-0.95 3.64,-2.9 4.02,-5.24C19.01,8.54 18.52,8 17.92,8C15.31,8 8.69,8 6.08,8C5.48,8 4.99,8.54 5.09,9.14c0.38,2.34 1.93,4.29 4.02,5.24l-3.95,6.08c-0.3,0.46 -0.17,1.08 0.29,1.38h0c0.46,0.3 1.08,0.17 1.38,-0.29l1,-1.55h6.34C14.6,21.16 15.7,22 17,22zM17,18c0.55,0 1,0.45 1,1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1C16,18.45 16.45,18 17,18z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M9.5,6.47C9.48,6.75 9.68,7 9.96,7H10c0.24,0 0.44,-0.18 0.46,-0.42c0.1,-0.87 0.04,-1.39 -0.94,-2.54c-0.36,-0.43 -0.6,-0.69 -0.53,-1.55C9.02,2.23 8.8,2 8.53,2H8.48C8.24,2 8.03,2.19 8.01,2.43c-0.08,0.93 0.2,1.74 0.95,2.53C9.15,5.17 9.6,5.52 9.5,6.47z"/>
+ android:pathData="M9.5,6.47C9.48,6.75 9.68,7 9.96,7H10c0.24,0 0.44,-0.18 0.46,-0.42c0.1,-0.87 0.04,-1.39 -0.94,-2.54C9.16,3.61 8.92,3.35 8.99,2.49C9.02,2.23 8.8,2 8.53,2H8.48C8.24,2 8.03,2.19 8.01,2.43c-0.08,0.93 0.2,1.74 0.95,2.53C9.15,5.17 9.6,5.52 9.5,6.47z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M11.99,6.47C11.96,6.75 12.17,7 12.45,7h0.03c0.24,0 0.44,-0.18 0.46,-0.42c0.1,-0.87 0.04,-1.39 -0.94,-2.54c-0.36,-0.43 -0.61,-0.69 -0.53,-1.55C11.5,2.23 11.28,2 11.01,2h-0.05c-0.24,0 -0.45,0.19 -0.47,0.43c-0.08,0.93 0.2,1.74 0.95,2.53C11.63,5.17 12.08,5.52 11.99,6.47z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/outlined_flag.xml b/compose/material/material/icons/generator/raw-icons/rounded/outlined_flag.xml
index dabb708..adc2d01 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/outlined_flag.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/outlined_flag.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.4,6l-0.24,-1.2C14.07,4.34 13.66,4 13.18,4H6C5.45,4 5,4.45 5,5v15c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-6h5.6l0.24,1.2c0.09,0.47 0.5,0.8 0.98,0.8H19c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1H14.4z"/>
+ android:pathData="M14,6l-0.72,-1.45c-0.17,-0.34 -0.52,-0.55 -0.9,-0.55L6,4c-0.55,0 -1,0.45 -1,1v15c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-6h5l0.72,1.45c0.17,0.34 0.52,0.55 0.89,0.55L19,16c0.55,0 1,-0.45 1,-1L20,7c0,-0.55 -0.45,-1 -1,-1h-5zM18,14h-4l-1,-2L7,12L7,6h5l1,2h5v6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pages.xml b/compose/material/material/icons/generator/raw-icons/rounded/pages.xml
index 1aaf82b..bdeca29 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pages.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pages.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,5v6h5L7.4,8.62C7.22,7.88 7.88,7.22 8.62,7.4L11,8V3H5C3.9,3 3,3.9 3,5zM8,13H3v6c0,1.1 0.9,2 2,2h6v-5l-2.38,0.6c-0.73,0.18 -1.4,-0.48 -1.21,-1.21L8,13zM15.38,16.6L13,16v5h6c1.1,0 2,-0.9 2,-2v-6h-5l0.6,2.38C16.78,16.12 16.12,16.78 15.38,16.6zM19,3h-6v5l2.38,-0.6c0.73,-0.18 1.4,0.48 1.21,1.21L16,11h5V5C21,3.9 20.1,3 19,3z"/>
+ android:pathData="M3,5v6h5l-0.6,-2.38c-0.18,-0.74 0.48,-1.4 1.22,-1.22L11,8L11,3L5,3c-1.1,0 -2,0.9 -2,2zM8,13L3,13v6c0,1.1 0.9,2 2,2h6v-5l-2.38,0.6c-0.73,0.18 -1.4,-0.48 -1.21,-1.21L8,13zM15.38,16.6L13,16v5h6c1.1,0 2,-0.9 2,-2v-6h-5l0.6,2.38c0.18,0.74 -0.48,1.4 -1.22,1.22zM19,3h-6v5l2.38,-0.6c0.73,-0.18 1.4,0.48 1.21,1.21L16,11h5L21,5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pageview.xml b/compose/material/material/icons/generator/raw-icons/rounded/pageview.xml
index ef0b655..6e39997 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pageview.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pageview.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.5,9C10.12,9 9,10.12 9,11.5s1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5S12.88,9 11.5,9zM20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM16.08,17.5l-2.2,-2.2c-0.9,0.58 -2.03,0.84 -3.22,0.62c-1.88,-0.35 -3.38,-1.93 -3.62,-3.83c-0.38,-3.01 2.18,-5.52 5.21,-5.04c1.88,0.3 3.39,1.84 3.7,3.71c0.19,1.16 -0.08,2.23 -0.64,3.12l2.2,2.19c0.39,0.39 0.39,1.03 0,1.42C17.11,17.89 16.47,17.89 16.08,17.5z"/>
+ android:pathData="M11.5,9C10.12,9 9,10.12 9,11.5s1.12,2.5 2.5,2.5 2.5,-1.12 2.5,-2.5S12.88,9 11.5,9zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM16.08,17.5l-2.2,-2.2c-0.9,0.58 -2.03,0.84 -3.22,0.62 -1.88,-0.35 -3.38,-1.93 -3.62,-3.83 -0.38,-3.01 2.18,-5.52 5.21,-5.04 1.88,0.3 3.39,1.84 3.7,3.71 0.19,1.16 -0.08,2.23 -0.64,3.12l2.2,2.19c0.39,0.39 0.39,1.03 0,1.42 -0.4,0.4 -1.04,0.4 -1.43,0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pan_tool.xml b/compose/material/material/icons/generator/raw-icons/rounded/pan_tool.xml
index 11c5e0f..86704ee 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pan_tool.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pan_tool.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.5,4C20.67,4 20,4.67 20,5.5v5c0,0.28 -0.22,0.5 -0.5,0.5S19,10.78 19,10.5v-8C19,1.67 18.33,1 17.5,1S16,1.67 16,2.5v8c0,0.28 -0.22,0.5 -0.5,0.5S15,10.78 15,10.5v-9C15,0.67 14.33,0 13.5,0S12,0.67 12,1.5v8.99c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5V4.5C11,3.67 10.33,3 9.5,3S8,3.67 8,4.5v11.41l-4.12,-2.35c-0.58,-0.33 -1.3,-0.24 -1.78,0.22c-0.6,0.58 -0.62,1.54 -0.03,2.13l6.78,6.89C9.6,23.57 10.62,24 11.7,24H19c2.21,0 4,-1.79 4,-4V5.5C23,4.67 22.33,4 21.5,4z"/>
+ android:pathData="M21.5,4c-0.83,0 -1.5,0.67 -1.5,1.5v5c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5v-8c0,-0.83 -0.67,-1.5 -1.5,-1.5S16,1.67 16,2.5v8c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5v-9c0,-0.83 -0.67,-1.5 -1.5,-1.5S12,0.67 12,1.5v8.99c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5V4.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S8,3.67 8,4.5v11.41l-4.12,-2.35c-0.58,-0.33 -1.3,-0.24 -1.78,0.22 -0.6,0.58 -0.62,1.54 -0.03,2.13l6.78,6.89c0.75,0.77 1.77,1.2 2.85,1.2H19c2.21,0 4,-1.79 4,-4V5.5c0,-0.83 -0.67,-1.5 -1.5,-1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/panorama.xml b/compose/material/material/icons/generator/raw-icons/rounded/panorama.xml
index 2a386a1..f4772055 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/panorama.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/panorama.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM6.6,15.2l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,15l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67c0.25,0.33 0.01,0.8 -0.4,0.8H7C6.59,16 6.35,15.53 6.6,15.2z"/>
+ android:pathData="M23,18V6c0,-1.1 -0.9,-2 -2,-2H3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2zM8.9,12.98l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8H6.02c-0.42,0 -0.65,-0.48 -0.39,-0.81L8.12,13c0.19,-0.26 0.57,-0.27 0.78,-0.02z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/panorama_fish_eye.xml b/compose/material/material/icons/generator/raw-icons/rounded/panorama_fish_eye.xml
index 5d957c4..2d4d03b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/panorama_fish_eye.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/panorama_fish_eye.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"/>
+ android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/panorama_horizontal.xml b/compose/material/material/icons/generator/raw-icons/rounded/panorama_horizontal.xml
index 7b37a7a..050443c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/panorama_horizontal.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/panorama_horizontal.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,5.5c-3.89,0 -6.95,-0.84 -8.69,-1.43C2.67,3.85 2,4.33 2,5.02L2,19c0,0.68 0.66,1.17 1.31,0.95C5.36,19.26 8.1,18.5 12,18.5c3.87,0 6.66,0.76 8.69,1.45C21.34,20.16 22,19.68 22,19l0,-14c0,-0.68 -0.66,-1.17 -1.31,-0.95C18.66,4.73 15.86,5.5 12,5.5z"/>
+ android:pathData="M20,6.54v10.91c-2.6,-0.77 -5.28,-1.16 -8,-1.16s-5.4,0.39 -8,1.16V6.54c2.6,0.77 5.28,1.16 8,1.16 2.72,0.01 5.4,-0.38 8,-1.16M21.43,4c-0.1,0 -0.2,0.02 -0.31,0.06C18.18,5.16 15.09,5.7 12,5.7s-6.18,-0.55 -9.12,-1.64C2.77,4.02 2.66,4 2.57,4c-0.34,0 -0.57,0.23 -0.57,0.63v14.75c0,0.39 0.23,0.62 0.57,0.62 0.1,0 0.2,-0.02 0.31,-0.06 2.94,-1.1 6.03,-1.64 9.12,-1.64s6.18,0.55 9.12,1.64c0.11,0.04 0.21,0.06 0.31,0.06 0.33,0 0.57,-0.23 0.57,-0.63V4.63c0,-0.4 -0.24,-0.63 -0.57,-0.63z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/panorama_vertical.xml b/compose/material/material/icons/generator/raw-icons/rounded/panorama_vertical.xml
index a5cdcb2..e4a60b1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/panorama_vertical.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/panorama_vertical.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.5,12c0,-3.89 0.84,-6.95 1.43,-8.69C20.15,2.67 19.67,2 18.98,2L5,2C4.32,2 3.84,2.66 4.05,3.31C4.74,5.36 5.5,8.1 5.5,12c0,3.87 -0.76,6.66 -1.45,8.69C3.84,21.34 4.32,22 5,22h14c0.68,0 1.17,-0.66 0.95,-1.31C19.27,18.66 18.5,15.86 18.5,12z"/>
+ android:pathData="M19.94,21.12c-1.1,-2.94 -1.64,-6.03 -1.64,-9.12s0.55,-6.18 1.64,-9.12c0.04,-0.11 0.06,-0.22 0.06,-0.31 0,-0.34 -0.23,-0.57 -0.63,-0.57H4.63c-0.4,0 -0.63,0.23 -0.63,0.57 0,0.1 0.02,0.2 0.06,0.31C5.16,5.82 5.71,8.91 5.71,12s-0.55,6.18 -1.64,9.12c-0.05,0.11 -0.07,0.22 -0.07,0.31 0,0.33 0.23,0.57 0.63,0.57h14.75c0.39,0 0.63,-0.24 0.63,-0.57 -0.01,-0.1 -0.03,-0.2 -0.07,-0.31zM6.54,20c0.77,-2.6 1.16,-5.28 1.16,-8s-0.39,-5.4 -1.16,-8h10.91c-0.77,2.6 -1.16,5.28 -1.16,8s0.39,5.4 1.16,8H6.54z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/panorama_wide_angle.xml b/compose/material/material/icons/generator/raw-icons/rounded/panorama_wide_angle.xml
index e88dd33..5ad0e55a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/panorama_wide_angle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/panorama_wide_angle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4C8.03,4 5.15,4.63 3,5c-0.55,1.97 -1,3.92 -1,7c0,3.03 0.45,5.06 1,7c2.15,0.37 4.98,1 9,1c3.97,0 6.85,-0.63 9,-1c0.57,-2.02 1,-3.99 1,-7c0,-3.03 -0.45,-5.06 -1,-7C18.85,4.63 16.02,4 12,4z"/>
+ android:pathData="M12,6c2.45,0 4.71,0.2 7.29,0.64 0.47,1.78 0.71,3.58 0.71,5.36s-0.24,3.58 -0.71,5.36c-2.58,0.44 -4.84,0.64 -7.29,0.64s-4.71,-0.2 -7.29,-0.64C4.24,15.58 4,13.78 4,12s0.24,-3.58 0.71,-5.36C7.29,6.2 9.55,6 12,6m0,-2c-2.73,0 -5.22,0.24 -7.95,0.72l-0.93,0.16 -0.25,0.9C2.29,7.85 2,9.93 2,12s0.29,4.15 0.87,6.22l0.25,0.89 0.93,0.16c2.73,0.49 5.22,0.73 7.95,0.73s5.22,-0.24 7.95,-0.72l0.93,-0.16 0.25,-0.89c0.58,-2.08 0.87,-4.16 0.87,-6.23s-0.29,-4.15 -0.87,-6.22l-0.25,-0.89 -0.93,-0.16C17.22,4.24 14.73,4 12,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/party_mode.xml b/compose/material/material/icons/generator/raw-icons/rounded/party_mode.xml
index d787240..b26dd7d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/party_mode.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/party_mode.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-3.17l-1.24,-1.35C15.22,3.24 14.68,3 14.12,3H9.88c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM12,8.5c1.56,0 2.93,0.79 3.74,2H12c-1.38,0 -2.5,1.12 -2.5,2.5c0,0.17 0.02,0.34 0.05,0.5h-2C7.53,13.33 7.5,13.17 7.5,13C7.5,10.52 9.52,8.5 12,8.5zM12,17.5c-1.56,0 -2.93,-0.79 -3.74,-2H12c1.38,0 2.5,-1.12 2.5,-2.5c0,-0.17 -0.02,-0.34 -0.05,-0.5h2c0.02,0.17 0.05,0.33 0.05,0.5C16.5,15.48 14.48,17.5 12,17.5z"/>
+ android:pathData="M20,4h-3.17l-1.24,-1.35c-0.37,-0.41 -0.91,-0.65 -1.47,-0.65L9.88,2c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,7c1.63,0 3.06,0.79 3.98,2L12,9c-1.66,0 -3,1.34 -3,3 0,0.35 0.07,0.69 0.18,1L7.1,13c-0.06,-0.32 -0.1,-0.66 -0.1,-1 0,-2.76 2.24,-5 5,-5zM12,17c-1.63,0 -3.06,-0.79 -3.98,-2L12,15c1.66,0 3,-1.34 3,-3 0,-0.35 -0.07,-0.69 -0.18,-1h2.08c0.07,0.32 0.1,0.66 0.1,1 0,2.76 -2.24,5 -5,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pause.xml b/compose/material/material/icons/generator/raw-icons/rounded/pause.xml
index 8851dcc..3492405 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pause.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pause.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,19L8,19c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2l0,0C6.9,5 6,5.9 6,7v10C6,18.1 6.9,19 8,19zM14,7v10c0,1.1 0.9,2 2,2l0,0c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2l0,0C14.9,5 14,5.9 14,7z"/>
+ android:pathData="M8,19c1.1,0 2,-0.9 2,-2L10,7c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v10c0,1.1 0.9,2 2,2zM14,7v10c0,1.1 0.9,2 2,2s2,-0.9 2,-2L18,7c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pause_circle_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/pause_circle_outline.xml
index 2bd7a43..c11df56 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pause_circle_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pause_circle_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,16L10,16c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1l0,0C9.45,8 9,8.45 9,9v6C9,15.55 9.45,16 10,16zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM14,16L14,16c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v6C13,15.55 13.45,16 14,16z"/>
+ android:pathData="M10,16c0.55,0 1,-0.45 1,-1L11,9c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6c0,0.55 0.45,1 1,1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM14,16c0.55,0 1,-0.45 1,-1L15,9c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pause_presentation.xml b/compose/material/material/icons/generator/raw-icons/rounded/pause_presentation.xml
index e8a79f3f..7c7c450 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pause_presentation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pause_presentation.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,18H4V6h16V18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,8L10,8c0.55,0 1,0.45 1,1v6c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V9C9,8.45 9.45,8 10,8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14,8L14,8c0.55,0 1,0.45 1,1v6c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V9C13,8.45 13.45,8 14,8z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,18c0,0.55 -0.45,1 -1,1L4,19c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12zM10,8c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1s1,-0.45 1,-1L11,9c0,-0.55 -0.45,-1 -1,-1zM14,8c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1s1,-0.45 1,-1L15,9c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/payment.xml b/compose/material/material/icons/generator/raw-icons/rounded/payment.xml
index 4686dd7..6564c58 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/payment.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/payment.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2.01,4.89 2.01,6L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6C22,4.89 21.11,4 20,4zM20,12H4V8h16V12z"/>
+ android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM19,18L5,18c-0.55,0 -1,-0.45 -1,-1v-5h16v5c0,0.55 -0.45,1 -1,1zM20,8L4,8L4,7c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/payments.xml b/compose/material/material/icons/generator/raw-icons/rounded/payments.xml
index 11b8fd2..f4b1894 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/payments.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/payments.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,7L2,7C1.45,7 1,7.45 1,8v10c0,1.1 0.9,2 2,2h16c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H3V8C3,7.45 2.55,7 2,7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,4H7C5.9,4 5,4.9 5,6v8c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6C23,4.9 22.1,4 21,4zM7,14v-2c1.1,0 2,0.9 2,2H7zM7,8V6h2C9,7.1 8.1,8 7,8zM14,13c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S15.66,13 14,13zM21,14h-2c0,-1.1 0.9,-2 2,-2V14zM21,8c-1.1,0 -2,-0.9 -2,-2h2V8z"/>
+ android:pathData="M23,8v10c0,1.1 -0.9,2 -2,2H5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h16V8c0,-0.55 0.45,-1 1,-1S23,7.45 23,8zM4,16c-1.66,0 -3,-1.34 -3,-3V7c0,-1.66 1.34,-3 3,-3h12c1.66,0 3,1.34 3,3v7c0,1.1 -0.9,2 -2,2H4zM7,10c0,1.66 1.34,3 3,3s3,-1.34 3,-3s-1.34,-3 -3,-3S7,8.34 7,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pedal_bike.xml b/compose/material/material/icons/generator/raw-icons/rounded/pedal_bike.xml
index 2413b59..d4acc0b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pedal_bike.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pedal_bike.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.18,10l-1.7,-4.68C16.19,4.53 15.44,4 14.6,4H13c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h1.6l1.46,4h-4.81l-0.36,-1h0.09c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C7.45,7 7,7.45 7,8l0,0c0,0.55 0.45,1 1,1h0.75l1.82,5H9.9c-0.44,-2.23 -2.31,-3.88 -4.65,-3.99C2.45,9.87 0,12.2 0,15s2.2,5 5,5c2.46,0 4.45,-1.69 4.9,-4h4.2c0.44,2.23 2.31,3.88 4.65,3.99c2.8,0.13 5.25,-2.19 5.25,-5c0,-2.8 -2.2,-5 -5,-5h-0.82V10zM7.82,16c-0.42,1.23 -1.6,2.08 -3.02,1.99C3.31,17.9 2.07,16.64 2,15.14C1.93,13.39 3.27,12 5,12c1.33,0 2.42,0.83 2.82,2H6c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1H7.82zM14.1,14h-1.4l-0.73,-2H15C14.56,12.58 14.24,13.25 14.1,14zM18.88,18c-1.54,-0.06 -2.84,-1.37 -2.88,-2.92c-0.02,-0.96 0.39,-1.8 1.05,-2.36l0.62,1.7c0.19,0.52 0.76,0.79 1.28,0.6l0,0c0.52,-0.19 0.79,-0.76 0.6,-1.28l-0.63,-1.73c0,0 0,0 0.01,-0.01c1.72,-0.04 3.08,1.29 3.08,3C22,16.72 20.62,18.06 18.88,18z"/>
+ android:pathData="M18.18,10l-1.7,-4.68C16.19,4.53 15.44,4 14.6,4H13c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1.6l1.46,4h-4.81l-0.36,-1h0.09c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H8C7.45,7 7,7.45 7,8v0c0,0.55 0.45,1 1,1h0.75l1.82,5H9.9c-0.44,-2.23 -2.31,-3.88 -4.65,-3.99C2.45,9.87 0,12.2 0,15c0,2.8 2.2,5 5,5c2.46,0 4.45,-1.69 4.9,-4h4.2c0.44,2.23 2.31,3.88 4.65,3.99c2.8,0.13 5.25,-2.19 5.25,-5c0,-2.8 -2.2,-5 -5,-5H18.18zM7.82,16c-0.42,1.23 -1.6,2.08 -3.02,1.99C3.31,17.9 2.07,16.64 2,15.14C1.93,13.39 3.27,12 5,12c1.33,0 2.42,0.83 2.82,2H6c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1H7.82zM14.1,14h-1.4l-0.73,-2H15C14.56,12.58 14.24,13.25 14.1,14zM18.88,18c-1.54,-0.06 -2.84,-1.37 -2.88,-2.92c-0.02,-0.96 0.39,-1.8 1.05,-2.36l0.62,1.7c0.19,0.52 0.76,0.79 1.28,0.6l0,0c0.52,-0.19 0.79,-0.76 0.6,-1.28l-0.63,-1.73c0,0 0,0 0.01,-0.01c1.72,-0.04 3.08,1.29 3.08,3C22,16.72 20.62,18.06 18.88,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pending.xml b/compose/material/material/icons/generator/raw-icons/rounded/pending.xml
index 96630e5..ce424ec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pending.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pending.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S7.83,13.5 7,13.5zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S12.83,13.5 12,13.5zM17,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S17.83,13.5 17,13.5z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM7,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C8.5,12.83 7.83,13.5 7,13.5zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM17,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C18.5,12.83 17.83,13.5 17,13.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/people.xml b/compose/material/material/icons/generator/raw-icons/rounded/people.xml
index 44299d8..4ccf41a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/people.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/people.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.43,0 -0.84,-0.09 -1.23,-0.21c-0.03,-0.01 -0.06,-0.02 -0.1,-0.03C14.5,10.73 15,9.42 15,8zM16.66,13.13C18.03,14.06 19,15.32 19,17v3h4v-3C23,14.82 19.42,13.53 16.66,13.13zM9,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4s-4,-1.79 -4,-4S6.79,4 9,4zM9,13c2.67,0 8,1.34 8,4v3H1v-3C1,14.34 6.33,13 9,13z"/>
+ android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5s-3,1.34 -3,3 1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,18c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-1.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 0.02,0.01 0.03,0.03 0.04,0.04 1.14,0.83 1.93,1.94 1.93,3.41L17,18c0,0.35 -0.07,0.69 -0.18,1L22,19c0.55,0 1,-0.45 1,-1v-1.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/people_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/people_alt.xml
index 44299d8..00f8e40 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/people_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/people_alt.xml
@@ -6,5 +6,18 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.43,0 -0.84,-0.09 -1.23,-0.21c-0.03,-0.01 -0.06,-0.02 -0.1,-0.03C14.5,10.73 15,9.42 15,8zM16.66,13.13C18.03,14.06 19,15.32 19,17v3h4v-3C23,14.82 19.42,13.53 16.66,13.13zM9,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4s-4,-1.79 -4,-4S6.79,4 9,4zM9,13c2.67,0 8,1.34 8,4v3H1v-3C1,14.34 6.33,13 9,13z"/>
+ android:pathData="M16.67,13.13C18.04,14.06 19,15.32 19,17v3h3c0.55,0 1,-0.45 1,-1v-2C23,14.82 19.43,13.53 16.67,13.13z"
+ android:fillType="evenOdd"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,8m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"
+ android:fillType="evenOdd"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4c-0.47,0 -0.91,0.1 -1.33,0.24C14.5,5.27 15,6.58 15,8s-0.5,2.73 -1.33,3.76C14.09,11.9 14.53,12 15,12z"
+ android:fillType="evenOdd"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,13c-2.67,0 -8,1.34 -8,4v2c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-2C17,14.34 11.67,13 9,13z"
+ android:fillType="evenOdd"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/people_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/people_outline.xml
index 44299d8..a7b76015 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/people_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/people_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.43,0 -0.84,-0.09 -1.23,-0.21c-0.03,-0.01 -0.06,-0.02 -0.1,-0.03C14.5,10.73 15,9.42 15,8zM16.66,13.13C18.03,14.06 19,15.32 19,17v3h4v-3C23,14.82 19.42,13.53 16.66,13.13zM9,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4s-4,-1.79 -4,-4S6.79,4 9,4zM9,13c2.67,0 8,1.34 8,4v3H1v-3C1,14.34 6.33,13 9,13z"/>
+ android:pathData="M9,12c1.93,0 3.5,-1.57 3.5,-3.5S10.93,5 9,5 5.5,6.57 5.5,8.5 7.07,12 9,12zM9,7c0.83,0 1.5,0.67 1.5,1.5S9.83,10 9,10s-1.5,-0.67 -1.5,-1.5S8.17,7 9,7zM9,13.75c-2.34,0 -7,1.17 -7,3.5L2,18c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-0.75c0,-2.33 -4.66,-3.5 -7,-3.5zM4.34,17c0.84,-0.58 2.87,-1.25 4.66,-1.25s3.82,0.67 4.66,1.25L4.34,17zM16.04,13.81c1.16,0.84 1.96,1.96 1.96,3.44L18,19h3c0.55,0 1,-0.45 1,-1v-0.75c0,-2.02 -3.5,-3.17 -5.96,-3.44zM15,12c1.93,0 3.5,-1.57 3.5,-3.5S16.93,5 15,5c-0.54,0 -1.04,0.13 -1.5,0.35 0.63,0.89 1,1.98 1,3.15s-0.37,2.26 -1,3.15c0.46,0.22 0.96,0.35 1.5,0.35z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/perm_camera_mic.xml b/compose/material/material/icons/generator/raw-icons/rounded/perm_camera_mic.xml
index 3b08021..1775b8b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/perm_camera_mic.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/perm_camera_mic.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-3.17l-1.27,-1.36C15.18,3.23 14.65,3 14.1,3H9.85C9.29,3 8.74,3.24 8.36,3.67L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h7v-3.09c-2.45,-0.42 -4.41,-2.32 -4.89,-4.75C5.99,12.55 6.49,12 7.1,12h0c0.49,0 0.88,0.35 0.98,0.83C8.47,14.64 10.07,16 12,16s3.53,-1.36 3.91,-3.17c0.1,-0.48 0.5,-0.83 0.98,-0.83h0c0.61,0 1.11,0.55 0.99,1.16c-0.48,2.43 -2.44,4.34 -4.89,4.75V21h7c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM14,12c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2V8c0,-1.1 0.9,-2 2,-2s2,0.9 2,2V12z"/>
+ android:pathData="M20,5h-3.17l-1.24,-1.35c-0.37,-0.41 -0.91,-0.65 -1.47,-0.65L9.88,3c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5L4,5c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v-2.09c-2.45,-0.42 -4.41,-2.32 -4.89,-4.75 -0.12,-0.61 0.38,-1.16 0.99,-1.16 0.49,0 0.88,0.35 0.98,0.83C8.47,15.64 10.07,17 12,17s3.53,-1.36 3.91,-3.17c0.1,-0.48 0.5,-0.83 0.98,-0.83 0.61,0 1.11,0.55 0.99,1.16 -0.48,2.43 -2.44,4.34 -4.89,4.75L12.99,21h7c1.1,0 2,-0.9 2,-2L21.99,7C22,5.9 21.1,5 20,5zM14,13c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2L10,9c0,-1.1 0.9,-2 2,-2s2,0.9 2,2v4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/perm_contact_calendar.xml b/compose/material/material/icons/generator/raw-icons/rounded/perm_contact_calendar.xml
index 10fb610..2572c1b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/perm_contact_calendar.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/perm_contact_calendar.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4h-1V3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1h0C6.45,2 6,2.45 6,3v1H5C3.9,4 3,4.9 3,6v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM12,7c1.93,0 3.5,1.57 3.5,3.5S13.93,14 12,14s-3.5,-1.57 -3.5,-3.5S10.07,7 12,7zM19,20H5v-0.23c0,-0.62 0.28,-1.2 0.76,-1.58C7.47,16.82 9.64,16 12,16s4.53,0.82 6.24,2.19c0.48,0.38 0.76,0.97 0.76,1.58V20z"/>
+ android:pathData="M19,3h-1L18,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L8,3L8,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,6c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM18,18L6,18v-1c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/perm_data_setting.xml b/compose/material/material/icons/generator/raw-icons/rounded/perm_data_setting.xml
index c61c842..dad1480 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/perm_data_setting.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/perm_data_setting.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.98,11.3c1.42,-0.42 2.78,-0.37 4.01,0l0,-8.88c0,-0.89 -1.08,-1.34 -1.71,-0.71L1.71,18.29C1.08,18.92 1.52,20 2.41,20h8.88c-0.36,-1.22 -0.42,-2.57 -0.01,-3.98C11.93,13.77 13.73,11.96 15.98,11.3zM21.75,18c0,-0.22 -0.03,-0.42 -0.06,-0.63l0.84,-0.73c0.18,-0.16 0.22,-0.42 0.1,-0.63l-0.59,-1.02c-0.12,-0.21 -0.37,-0.3 -0.59,-0.22l-1.06,0.36c-0.32,-0.27 -0.68,-0.48 -1.08,-0.63l-0.22,-1.09c-0.05,-0.23 -0.25,-0.4 -0.49,-0.4h-1.18c-0.24,0 -0.44,0.17 -0.49,0.4l-0.22,1.09c-0.4,0.15 -0.76,0.36 -1.08,0.63l-1.06,-0.36c-0.23,-0.08 -0.47,0.02 -0.59,0.22l-0.59,1.02c-0.12,0.21 -0.08,0.47 0.1,0.63l0.84,0.73c-0.03,0.21 -0.06,0.41 -0.06,0.63s0.03,0.42 0.06,0.63l-0.84,0.73c-0.18,0.16 -0.22,0.42 -0.1,0.63l0.59,1.02c0.12,0.21 0.37,0.3 0.59,0.22l1.06,-0.36c0.32,0.27 0.68,0.48 1.08,0.63l0.22,1.09c0.05,0.23 0.25,0.4 0.49,0.4h1.18c0.24,0 0.44,-0.17 0.49,-0.4l0.22,-1.09c0.4,-0.15 0.76,-0.36 1.08,-0.63l1.06,0.36c0.23,0.08 0.47,-0.02 0.59,-0.22l0.59,-1.02c0.12,-0.21 0.08,-0.47 -0.1,-0.63l-0.84,-0.73C21.72,18.42 21.75,18.22 21.75,18zM18,20c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S19.1,20 18,20z"/>
+ android:pathData="M18.99,11.5c0.34,0 0.68,0.03 1.01,0.07L20,2.42c0,-0.89 -1.08,-1.34 -1.71,-0.71L1.71,18.29c-0.63,0.63 -0.19,1.71 0.7,1.71h9.15c-0.04,-0.33 -0.07,-0.66 -0.07,-1 0,-4.14 3.36,-7.5 7.5,-7.5zM22.7,19.49c0.02,-0.16 0.04,-0.32 0.04,-0.49s-0.01,-0.33 -0.04,-0.49l1.06,-0.83c0.09,-0.08 0.12,-0.21 0.06,-0.32l-1,-1.73c-0.06,-0.11 -0.19,-0.15 -0.31,-0.11l-1.24,0.5c-0.26,-0.2 -0.54,-0.37 -0.85,-0.49l-0.19,-1.32c-0.01,-0.12 -0.12,-0.21 -0.24,-0.21h-2c-0.12,0 -0.23,0.09 -0.25,0.21l-0.19,1.32c-0.3,0.13 -0.59,0.29 -0.85,0.49l-1.24,-0.5c-0.11,-0.04 -0.24,0 -0.31,0.11l-1,1.73c-0.06,0.11 -0.04,0.24 0.06,0.32l1.06,0.83c-0.02,0.16 -0.03,0.32 -0.03,0.49s0.01,0.33 0.03,0.49l-1.06,0.83c-0.09,0.08 -0.12,0.21 -0.06,0.32l1,1.73c0.06,0.11 0.19,0.15 0.31,0.11l1.24,-0.5c0.26,0.2 0.54,0.37 0.85,0.49l0.19,1.32c0.02,0.12 0.12,0.21 0.25,0.21h2c0.12,0 0.23,-0.09 0.25,-0.21l0.19,-1.32c0.3,-0.13 0.59,-0.29 0.84,-0.49l1.25,0.5c0.11,0.04 0.24,0 0.31,-0.11l1,-1.73c0.06,-0.11 0.03,-0.24 -0.06,-0.32l-1.07,-0.83zM18.99,20.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/perm_device_information.xml b/compose/material/material/icons/generator/raw-icons/rounded/perm_device_information.xml
index a8a0210..6139265 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/perm_device_information.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/perm_device_information.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7L12,7c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v0C13,7.45 12.55,7 12,7zM12,11c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4C13,11.45 12.55,11 12,11zM17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,18H7V6h10V18z"/>
+ android:pathData="M13,7h-2v2h2L13,7zM12,11c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1zM17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/perm_identity.xml b/compose/material/material/icons/generator/raw-icons/rounded/perm_identity.xml
index 20a9658..528642b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/perm_identity.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/perm_identity.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S8,5.79 8,8C8,10.21 9.79,12 12,12zM18.39,14.56C16.71,13.7 14.53,13 12,13c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,15.07 4,16.1 4,17.22L4,19c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1l0,-1.78C20,16.1 19.39,15.07 18.39,14.56z"/>
+ android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,6c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2zM12,13c-2.67,0 -8,1.34 -8,4v2c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-2c0,-2.66 -5.33,-4 -8,-4zM18,18L6,18v-0.99c0.2,-0.72 3.3,-2.01 6,-2.01s5.8,1.29 6,2v1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/perm_phone_msg.xml b/compose/material/material/icons/generator/raw-icons/rounded/perm_phone_msg.xml
index 6ccc336..0746d2b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/perm_phone_msg.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/perm_phone_msg.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4v7.79c0,0.45 0.54,0.67 0.85,0.35L15,10h5c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1h-7C12.45,3 12,3.45 12,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.2,14.87l-3.67,-0.73c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.54,2.56c-2.5,-1.43 -4.58,-3.52 -6.01,-6.01l2.52,-2.58c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03c0.17,2.89 1.03,5.66 2.41,8.03c1.58,2.73 3.85,5.01 6.57,6.59c2.37,1.37 5.1,2.19 7.99,2.36c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15C21,15.37 20.66,14.96 20.2,14.87z"/>
+ android:pathData="M20,3h-7c-0.55,0 -1,0.45 -1,1v9l3,-3h5c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1zM19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77L5.03,3.01c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/perm_scan_wifi.xml b/compose/material/material/icons/generator/raw-icons/rounded/perm_scan_wifi.xml
index ddd5975..9fa7088 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/perm_scan_wifi.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/perm_scan_wifi.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22.29,7.48C19.44,5.3 15.87,4 12,4C8.13,4 4.56,5.3 1.71,7.48c-0.96,0.74 -1.06,2.15 -0.2,3.01l9.08,9.09c0.78,0.78 2.05,0.78 2.83,0l9.08,-9.09C23.35,9.63 23.25,8.22 22.29,7.48zM13,14c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V14zM12,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,9 12,9z"/>
+ android:pathData="M12,3C7.41,3 3.86,4.53 0.89,6.59c-0.49,0.33 -0.59,1 -0.22,1.46l9.78,12.04c0.8,0.98 2.3,0.99 3.1,0l9.78,-12.02c0.37,-0.46 0.27,-1.13 -0.22,-1.46C20.14,4.54 16.59,3 12,3zM12,16c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1zM11,8L11,6h2v2h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/person.xml b/compose/material/material/icons/generator/raw-icons/rounded/person.xml
index 59918ca..64194a2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/person.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/person.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.39,14.56C16.71,13.7 14.53,13 12,13c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,15.07 4,16.1 4,17.22V20h16v-2.78C20,16.1 19.39,15.07 18.39,14.56z"/>
+ android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/person_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/person_add.xml
index e021785..edb87ec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/person_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/person_add.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.39,14.56C13.71,13.7 11.53,13 9,13c-2.53,0 -4.71,0.7 -6.39,1.56C1.61,15.07 1,16.1 1,17.22V20h16v-2.78C17,16.1 16.39,15.07 15.39,14.56zM9,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S5,5.79 5,8C5,10.21 6.79,12 9,12zM20,9V7c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H20z"/>
+ android:pathData="M15,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM6,10L6,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2L2,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,10zM15,14c-2.67,0 -8,1.34 -8,4v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/person_add_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/person_add_disabled.xml
index 19e9a1c..90454b1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/person_add_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/person_add_disabled.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.59,9.76C12.85,9.23 13,8.63 13,8c0,-2.21 -1.79,-4 -4,-4C8.37,4 7.77,4.15 7.24,4.41L12.59,9.76z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,9V7c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2h-2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l2.92,2.92C5.01,7.9 5,7.95 5,8c0,2.21 1.79,4 4,4c0.05,0 0.1,-0.01 0.16,-0.02l1.08,1.08C9.83,13.03 9.42,13 9,13c-2.53,0 -4.71,0.7 -6.39,1.56C1.61,15.07 1,16.1 1,17.22L1,20l16.17,0l1.9,1.9c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M14.48,11.95c0.17,0.02 0.34,0.05 0.52,0.05 2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4c0,0.18 0.03,0.35 0.05,0.52l3.43,3.43zM16.69,14.16l5.74,5.74c0.33,-0.17 0.57,-0.5 0.57,-0.9v-1c0,-2.14 -3.56,-3.5 -6.31,-3.84zM2.12,2.42c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L4,7.12L4,10L2,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2.88l2.51,2.51C9.19,15.11 7,16.3 7,18v1c0,0.55 0.45,1 1,1h8.88l3.29,3.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L2.12,2.42zM6,10v-0.88l0.88,0.88L6,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/person_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/person_outline.xml
index a9926aa..d0a38d0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/person_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/person_outline.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S8,5.79 8,8C8,10.21 9.79,12 12,12zM12,6c1.1,0 2,0.9 2,2c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2C10,6.9 10.9,6 12,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.39,14.56C16.71,13.7 14.53,13 12,13c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,15.07 4,16.1 4,17.22V20h16v-2.78C20,16.1 19.39,15.07 18.39,14.56zM18,18H6v-0.78c0,-0.38 0.2,-0.72 0.52,-0.88C7.71,15.73 9.63,15 12,15c2.37,0 4.29,0.73 5.48,1.34C17.8,16.5 18,16.84 18,17.22V18z"/>
+ android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L5.9,18.1L5.9,17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v2c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/person_pin.xml b/compose/material/material/icons/generator/raw-icons/rounded/person_pin.xml
index 5fd0aaf..6618262 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/person_pin.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/person_pin.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,2H5C3.9,2 3,2.9 3,4v14c0,1.1 0.9,2 2,2h4l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0L15,20h4c1.1,0 2,-0.9 2,-2V4C21,2.9 20.1,2 19,2zM12,5c1.93,0 3.5,1.57 3.5,3.5S13.93,12 12,12s-3.5,-1.57 -3.5,-3.5S10.07,5 12,5zM19,18H5v-0.23c0,-0.62 0.28,-1.2 0.76,-1.58C7.47,14.82 9.64,14 12,14s4.53,0.82 6.24,2.19c0.48,0.38 0.76,0.97 0.76,1.58V18z"/>
+ android:pathData="M19,2L5,2c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h4l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0L15,20h4c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,5.3c1.49,0 2.7,1.21 2.7,2.7s-1.21,2.7 -2.7,2.7S9.3,9.49 9.3,8s1.21,-2.7 2.7,-2.7zM18,16L6,16v-0.9c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v0.9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/person_remove.xml b/compose/material/material/icons/generator/raw-icons/rounded/person_remove.xml
index 1b8b8ce..b6fad420 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/person_remove.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/person_remove.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,10h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4c0.55,0 1,-0.45 1,-1S22.55,10 22,10zM9,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S5,5.79 5,8C5,10.21 6.79,12 9,12zM15.39,14.56C13.71,13.7 11.53,13 9,13c-2.53,0 -4.71,0.7 -6.39,1.56C1.61,15.07 1,16.1 1,17.22V20h16v-2.78C17,16.1 16.39,15.07 15.39,14.56z"/>
+ android:pathData="M14,8c0,-2.21 -1.79,-4 -4,-4S6,5.79 6,8s1.79,4 4,4S14,10.21 14,8zM2,18v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1c0,-2.66 -5.33,-4 -8,-4S2,15.34 2,18zM18,10h4c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1v0C17,10.45 17.45,10 18,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/personal_injury.xml b/compose/material/material/icons/generator/raw-icons/rounded/personal_injury.xml
new file mode 100644
index 0000000..22c5d7b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/personal_injury.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,6c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S8,8.21 8,6zM17,22h1c1.1,0 2,-0.9 2,-2l0,-4.78c0,-1.12 -0.61,-2.15 -1.61,-2.66c-0.43,-0.22 -0.9,-0.43 -1.39,-0.62L17,22zM12.34,17L15,11.33C14.07,11.12 13.07,11 12,11c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,13.07 4,14.1 4,15.22L4,22h2.34C6.12,21.55 6,21.04 6,20.5C6,18.57 7.57,17 9.5,17H12.34zM10,22l1.41,-3H9.5C8.67,19 8,19.67 8,20.5S8.67,22 9.5,22H10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/personal_video.xml b/compose/material/material/icons/generator/raw-icons/rounded/personal_video.xml
index 3129718..e741592 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/personal_video.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/personal_video.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h4c1.1,0 1.99,-0.9 1.99,-2L22,5C22,3.9 21.1,3 20,3zM20,17H4V5h16V17z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.11 -0.9,-2 -2,-2zM20,17L4,17c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pets.xml b/compose/material/material/icons/generator/raw-icons/rounded/pets.xml
index de1bbbd..7adc005 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pets.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pets.xml
@@ -18,5 +18,5 @@
android:pathData="M19.5,9.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17.35,14.86c-0.87,-1.02 -1.61,-2.39 -2.49,-3.41C13.61,9.98 12.73,10 12,10c-0.78,0 -1.61,0.01 -2.87,1.46c-0.87,1.02 -1.59,2.39 -2.47,3.41c-1.31,1.31 -2.92,2.76 -2.62,4.79c0.29,1.02 1.02,2.03 2.33,2.32c0.73,0.15 3.15,-0.44 5.63,-0.44c2.77,0 4.89,0.58 5.63,0.44c1.31,-0.29 2.04,-1.31 2.33,-2.32C20.27,17.62 18.66,16.17 17.35,14.86z"/>
+ android:pathData="M17.34,14.86c-0.87,-1.02 -1.6,-1.89 -2.48,-2.91 -0.46,-0.54 -1.05,-1.08 -1.75,-1.32 -0.11,-0.04 -0.22,-0.07 -0.33,-0.09 -0.25,-0.04 -0.52,-0.04 -0.78,-0.04s-0.53,0 -0.79,0.05c-0.11,0.02 -0.22,0.05 -0.33,0.09 -0.7,0.24 -1.28,0.78 -1.75,1.32 -0.87,1.02 -1.6,1.89 -2.48,2.91 -1.31,1.31 -2.92,2.76 -2.62,4.79 0.29,1.02 1.02,2.03 2.33,2.32 0.73,0.15 3.06,-0.44 5.54,-0.44h0.18c2.48,0 4.81,0.58 5.54,0.44 1.31,-0.29 2.04,-1.31 2.33,-2.32 0.31,-2.04 -1.3,-3.49 -2.61,-4.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone.xml
index 324cfc7..0c2d257 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77H5.03c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_android.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_android.xml
index da0d8490..26aacf1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_android.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_android.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1 17,1zM13.5,20h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5S13.78,20 13.5,20zM17,16H7V6h10V16z"/>
+ android:pathData="M16,1L8,1C6.34,1 5,2.34 5,4v16c0,1.66 1.34,3 3,3h8c1.66,0 3,-1.34 3,-3L19,4c0,-1.66 -1.34,-3 -3,-3zM13.5,21h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5s-0.22,0.5 -0.5,0.5zM17,18L7,18L7,4h10v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_bluetooth_speaker.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_bluetooth_speaker.xml
index dcc2c64..8b7ff87 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_bluetooth_speaker.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_bluetooth_speaker.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.21,7l1.83,-1.83c0.09,-0.09 0.15,-0.22 0.15,-0.36s-0.05,-0.26 -0.15,-0.36l-2.18,-2.18c-0.14,-0.14 -0.36,-0.19 -0.55,-0.11S17,2.42 17,2.62v3.15l-1.95,-1.95c-0.2,-0.2 -0.52,-0.2 -0.71,0c-0.2,0.2 -0.2,0.52 0,0.71l2.45,2.46l-2.45,2.45c-0.2,0.2 -0.2,0.52 0,0.71c0.2,0.2 0.52,0.2 0.71,0L17,8.21v3.15c0,0.2 0.12,0.39 0.31,0.47c0.06,0.03 0.13,0.04 0.19,0.04c0.13,0 0.26,-0.05 0.36,-0.15l2.18,-2.18c0.2,-0.2 0.2,-0.52 0,-0.71L18.21,7zM18.01,3.84l0.96,0.96l-0.96,0.96V3.84zM18.01,10.13V8.21l0.96,0.96L18.01,10.13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77L5.03,3.01c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98zM16.79,6.01l-2.45,2.45c-0.2,0.2 -0.2,0.52 0,0.71 0.2,0.2 0.52,0.2 0.71,0L17,7.23v3.15c0,0.2 0.12,0.39 0.31,0.47 0.06,0.03 0.13,0.04 0.19,0.04 0.13,0 0.26,-0.05 0.36,-0.15l2.18,-2.18c0.2,-0.2 0.2,-0.52 0,-0.71l-1.83,-1.83 1.83,-1.83c0.09,-0.09 0.15,-0.22 0.15,-0.36s-0.05,-0.26 -0.15,-0.36l-2.18,-2.18c-0.14,-0.14 -0.36,-0.19 -0.55,-0.11 -0.19,0.08 -0.31,0.26 -0.31,0.46v3.15l-1.95,-1.95c-0.2,-0.2 -0.52,-0.2 -0.71,0 -0.2,0.2 -0.2,0.52 0,0.71l2.45,2.46zM18.01,2.86l0.96,0.96 -0.96,0.96L18.01,2.86zM18.01,7.23l0.96,0.96 -0.96,0.96L18.01,7.23z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_callback.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_callback.xml
index 4418817..55bb6e7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_callback.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_callback.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.5,11h4.29c0.45,0 0.67,-0.54 0.35,-0.85l-1.44,-1.44l4,-4c0.39,-0.39 0.39,-1.02 0,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4,4l-1.44,-1.44C13.54,5.54 13,5.76 13,6.21v4.29C13,10.78 13.22,11 13.5,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77H5.03c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98zM13,11h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1.59l4.31,-4.31c0.39,-0.39 0.39,-1.02 0,-1.41s-1.02,-0.39 -1.41,0L14,7.59V6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_disabled.xml
index cab352f..355e3bd2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_disabled.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2.1,4.93l10.71,10.71c-0.6,0.46 -1.22,0.89 -1.88,1.26l-2.52,-2.52c-0.24,-0.24 -0.58,-0.34 -0.9,-0.27l-3.67,0.73c-0.47,0.09 -0.8,0.5 -0.8,0.98l0,4.15c0,0.56 0.47,1.03 1.03,1c2.89,-0.17 5.6,-1.03 7.97,-2.4c0.77,-0.45 1.51,-0.96 2.2,-1.51l4.84,4.84c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.71,3.91 1.71,4.54 2.1,4.93z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.93,10.9c-0.38,0.67 -0.82,1.31 -1.29,1.91l1.42,1.42c0.56,-0.7 1.08,-1.45 1.54,-2.23c1.37,-2.37 2.23,-5.08 2.4,-7.97C21.03,3.47 20.56,3 20,3h-4.15c-0.48,0 -0.89,0.34 -0.98,0.8l-0.73,3.67c-0.07,0.33 0.04,0.67 0.27,0.9L16.93,10.9z"/>
+ android:pathData="M14.54,17.37c-2.63,2.08 -5.89,3.39 -9.45,3.61c-1.13,0.07 -2.07,-0.87 -2.07,-2v-1.73c-0.01,-1.01 0.75,-1.86 1.76,-1.98l2.54,-0.29c0.61,-0.07 1.21,0.14 1.64,0.57l1.84,1.84c0.81,-0.41 1.59,-0.9 2.31,-1.45L2.1,4.93c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.03,-0.39 1.42,0L20.49,20.5c0.39,0.39 0.39,1.02 0,1.41s-1.02,0.39 -1.41,0L14.54,17.37zM17.39,10.8l-1.85,-1.85c-0.43,-0.43 -0.64,-1.03 -0.57,-1.64l0.29,-2.52c0.12,-1.01 0.97,-1.77 1.99,-1.77h1.73c1.13,0 2.07,0.94 2,2.07c-0.22,3.57 -1.54,6.83 -3.62,9.47l-1.43,-1.43C16.48,12.4 16.97,11.62 17.39,10.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_enabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_enabled.xml
index c55135f..b388329 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_enabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_enabled.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.4,8.37l2.5,2.52c-1.43,2.5 -3.5,4.57 -6,6l-2.52,-2.5c-0.24,-0.23 -0.57,-0.33 -0.9,-0.27L3.8,14.87C3.34,14.96 3,15.37 3,15.85L3,20c0,0.56 0.47,1.03 1.03,1c2.89,-0.17 5.6,-1.05 7.97,-2.43c2.73,-1.58 4.99,-3.85 6.57,-6.57c1.37,-2.37 2.26,-5.08 2.43,-7.97C21.03,3.47 20.56,3 20,3l-4.15,0c-0.48,0 -0.89,0.34 -0.98,0.8l-0.73,3.67C14.07,7.8 14.17,8.14 14.4,8.37z"/>
+ android:pathData="M4.78,15.27l2.54,-0.29c0.61,-0.07 1.21,0.14 1.64,0.57l1.84,1.84c2.83,-1.44 5.15,-3.75 6.59,-6.59l-1.85,-1.85c-0.43,-0.43 -0.64,-1.03 -0.57,-1.64l0.29,-2.52c0.12,-1.01 0.97,-1.77 1.99,-1.77h1.73c1.13,0 2.07,0.94 2,2.07c-0.53,8.54 -7.36,15.36 -15.89,15.89c-1.13,0.07 -2.07,-0.87 -2.07,-2v-1.73C3.01,16.24 3.77,15.39 4.78,15.27z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_forwarded.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_forwarded.xml
index ff7605c..67a2264 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_forwarded.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_forwarded.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.65,5.66l-2.8,-2.8c-0.32,-0.32 -0.86,-0.09 -0.85,0.36L18,5h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4l-0.01,1.79c0,0.45 0.54,0.67 0.85,0.36l2.8,-2.78C21.84,6.17 21.84,5.85 21.65,5.66z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M22.65,5.65l-3.79,-3.79c-0.32,-0.32 -0.86,-0.1 -0.86,0.35L18,4h-3.5c-0.28,0 -0.5,0.22 -0.5,0.5v3c0,0.28 0.22,0.5 0.5,0.5L18,8v1.79c0,0.45 0.54,0.67 0.85,0.35l3.79,-3.79c0.2,-0.19 0.2,-0.51 0.01,-0.7zM19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77L5.03,3.01c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_in_talk.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_in_talk.xml
index 49dded9..a9d5476 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_in_talk.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_in_talk.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.88,5.05c3.18,0.4 5.67,2.89 6.07,6.07c0.06,0.51 0.49,0.88 0.99,0.88c0.04,0 0.08,0 0.12,-0.01c0.55,-0.07 0.94,-0.57 0.87,-1.12c-0.51,-4.09 -3.72,-7.3 -7.81,-7.81C12.57,3 12.07,3.39 12.01,3.94C11.94,4.49 12.33,4.99 12.88,5.05z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.26,7.16c-0.53,-0.14 -1.08,0.18 -1.22,0.72c-0.14,0.54 0.18,1.08 0.72,1.22c1.05,0.27 1.87,1.09 2.15,2.15C15.03,11.7 15.43,12 15.88,12c0.08,0 0.17,-0.01 0.25,-0.03c0.53,-0.14 0.85,-0.69 0.72,-1.22C16.38,8.98 15.01,7.61 13.26,7.16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M12.88,5.05c3.18,0.4 5.67,2.89 6.07,6.07 0.06,0.51 0.49,0.88 0.99,0.88 0.04,0 0.08,0 0.12,-0.01 0.55,-0.07 0.94,-0.57 0.87,-1.12 -0.51,-4.09 -3.72,-7.3 -7.81,-7.81 -0.55,-0.06 -1.05,0.33 -1.11,0.88 -0.07,0.55 0.32,1.05 0.87,1.11zM13.26,7.16c-0.53,-0.14 -1.08,0.18 -1.22,0.72s0.18,1.08 0.72,1.22c1.05,0.27 1.87,1.09 2.15,2.15 0.12,0.45 0.52,0.75 0.97,0.75 0.08,0 0.17,-0.01 0.25,-0.03 0.53,-0.14 0.85,-0.69 0.72,-1.22 -0.47,-1.77 -1.84,-3.14 -3.59,-3.59zM19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77L5.03,3.01c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_iphone.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_iphone.xml
index fe9f33a..23ef826 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_iphone.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_iphone.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1 17,1zM12,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,20.5 12,20.5zM17,16H7V6h10V16z"/>
+ android:pathData="M15.5,1h-8C6.12,1 5,2.12 5,3.5v17C5,21.88 6.12,23 7.5,23h8c1.38,0 2.5,-1.12 2.5,-2.5v-17C18,2.12 16.88,1 15.5,1zM11.5,22c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM16,18L7,18L7,4h9v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_missed.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_missed.xml
index 094a469..99ed568 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_missed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_missed.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M22.91,16.71C18.58,12.1 13.09,12 12,12s-6.58,0.1 -10.91,4.71c-0.38,0.4 -0.38,1.02 0.01,1.41l2.29,2.27c0.35,0.35 0.91,0.39 1.3,0.09L7.6,18.3C7.85,18.11 8,17.81 8,17.5v-2.87C9.26,14.23 10.6,14 12,14s2.74,0.23 4,0.63v2.87c0,0.31 0.15,0.61 0.4,0.8l2.91,2.18c0.4,0.3 0.95,0.26 1.3,-0.09l2.29,-2.27C23.29,17.73 23.29,17.11 22.91,16.71zM12.65,10.66L18.31,5c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.03,-0.39 -1.42,0l-4.95,4.95L8.7,5.3l1.45,-1.45C10.46,3.54 10.24,3 9.79,3H5.5C5.22,3 5,3.22 5,3.5v4.29c0,0.45 0.54,0.67 0.85,0.35l1.43,-1.43l3.95,3.95C11.62,11.05 12.26,11.05 12.65,10.66z"/>
+ android:pathData="M23.09,16.2c-6.33,-5.59 -15.86,-5.59 -22.18,0 -0.84,0.74 -0.84,2.05 -0.05,2.84l1.2,1.2c0.71,0.71 1.84,0.77 2.62,0.15l1.97,-1.57c0.47,-0.37 0.75,-0.94 0.75,-1.55V14.7c2.98,-0.97 6.21,-0.98 9.2,0v2.58c0,0.6 0.28,1.17 0.75,1.55l1.96,1.56c0.79,0.62 1.91,0.56 2.62,-0.15l1.2,-1.2c0.8,-0.79 0.79,-2.1 -0.04,-2.84zM6,9c0.55,0 1,-0.45 1,-1V6.43l4.24,4.24c0.39,0.39 1.02,0.39 1.41,0l5.66,-5.66c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0l-4.95,4.95L8.4,5H10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phone_paused.xml b/compose/material/material/icons/generator/raw-icons/rounded/phone_paused.xml
index 64893ae..c77de43 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phone_paused.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phone_paused.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,10c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v5C15,9.55 15.45,10 16,10z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,3c-0.55,0 -1,0.45 -1,1v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4C21,3.45 20.55,3 20,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M16,3c-0.55,0 -1,0.45 -1,1v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1L17,4c0,-0.55 -0.45,-1 -1,-1zM19,4v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM19.23,15.26l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.03 0.57,-1.64l-0.29,-2.52c-0.12,-1.01 -0.97,-1.77 -1.99,-1.77L5.03,3.01c-1.13,0 -2.07,0.94 -2,2.07 0.53,8.54 7.36,15.36 15.89,15.89 1.13,0.07 2.07,-0.87 2.07,-2v-1.73c0.01,-1.01 -0.75,-1.86 -1.76,-1.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phonelink.xml b/compose/material/material/icons/generator/raw-icons/rounded/phonelink.xml
index 8417337..6d3f0dc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phonelink.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phonelink.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,6h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H6C4.9,4 4,4.9 4,6v11H3.5C2.67,17 2,17.67 2,18.5v0C2,19.33 2.67,20 3.5,20h7c0.83,0 1.5,-0.67 1.5,-1.5v0c0,-0.83 -0.67,-1.5 -1.5,-1.5H6V6zM21,8h-6c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1V9C22,8.45 21.55,8 21,8zM20,17h-4v-7h4V17z"/>
+ android:pathData="M4,7c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,4c-1.1,0 -2,0.9 -2,2v11h-0.5c-0.83,0 -1.5,0.67 -1.5,1.5S0.67,20 1.5,20h11c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5L4,17L4,7zM23,8h-6c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1L24,9c0,-0.55 -0.45,-1 -1,-1zM22,17h-4v-7h4v7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_erase.xml b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_erase.xml
index 7767974..58474f7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_erase.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_erase.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.71,15.3L13.71,15.3c-0.39,-0.39 -0.39,-1.02 0,-1.41L15.59,12l-1.89,-1.89c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0L17,10.59l1.89,-1.89c0.39,-0.39 1.02,-0.39 1.41,0v0c0.39,0.39 0.39,1.02 0,1.41L18.41,12l1.89,1.89c0.39,0.39 0.39,1.02 0,1.41v0c-0.39,0.39 -1.02,0.39 -1.41,0L17,13.41l-1.89,1.89C14.73,15.68 14.09,15.68 13.71,15.3zM4,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-4h-2v1H6V6h10v1h2V3c0,-1.1 -0.9,-2 -2,-2L6,1.01C4.9,1.01 4,1.9 4,3z"/>
+ android:pathData="M12.5,7.7c-0.28,-0.28 -0.72,-0.28 -1,0L8,11.2 4.5,7.7c-0.28,-0.28 -0.72,-0.28 -1,0s-0.28,0.72 0,1L7,12.2l-3.5,3.5c-0.28,0.28 -0.28,0.72 0,1s0.72,0.28 1,0L8,13.2l3.5,3.5c0.28,0.28 0.72,0.28 1,0s0.28,-0.72 0,-1L9,12.2l3.5,-3.5c0.28,-0.28 0.28,-0.72 0,-1zM19,1H9c-1.1,0 -2,0.9 -2,2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4h10v16H9v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_off.xml
index b1cb7a0..5ece215 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_off.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,5L21,5c0,-0.55 -0.45,-1 -1,-1H6.83l2,2H20C20.55,6 21,5.55 21,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,8h-6c-0.55,0 -1,0.45 -1,1v2.17l2,2V10h4v7.17l2,2V9C22,8.45 21.55,8 21,8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,4.93L4,6.83V17H3.5C2.67,17 2,17.67 2,18.5v0C2,19.33 2.67,20 3.5,20h7c0.83,0 1.5,-0.67 1.5,-1.5v0c0,-0.83 -0.67,-1.5 -1.5,-1.5H6V8.83l8,8V19c0,0.55 0.45,1 1,1h2.17l1.9,1.9c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.71,3.91 1.71,4.54 2.1,4.93z"/>
+ android:pathData="M24,19V9c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1v3.61l2,2V10h4v7h-1.61l2.93,2.93c0.39,-0.13 0.68,-0.49 0.68,-0.93zM21,6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H7.39l2,2H21zM1.36,2.21c-0.39,0.39 -0.39,1.02 0,1.41l1.11,1.11C2.18,5.08 2,5.52 2,6v11h-0.5c-0.83,0 -1.5,0.67 -1.5,1.5S0.67,20 1.5,20h16.23l1.64,1.64c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L2.77,2.21c-0.39,-0.39 -1.02,-0.39 -1.41,0zM4,17V6.27L14.73,17H4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_ring.xml b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_ring.xml
index 765e637..f876967 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_ring.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_ring.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,18H7V6h10v1h2V3c0,-1.1 -0.9,-2 -2,-2L7,1.01C5.9,1.01 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-4h-2V18zM19.1,13.75c0.54,-1.11 0.54,-2.41 -0.01,-3.52C18.8,9.64 18,9.5 17.52,9.98l-0.1,0.1c-0.27,0.27 -0.3,0.68 -0.12,1.02c0.14,0.28 0.21,0.59 0.21,0.9c0,0.31 -0.07,0.61 -0.21,0.89c-0.19,0.37 -0.07,0.82 0.22,1.12l0,0C17.99,14.49 18.8,14.36 19.1,13.75zM20.05,7.46L20.05,7.46c-0.34,0.34 -0.39,0.88 -0.1,1.28c1.42,1.93 1.42,4.59 0,6.52c-0.29,0.39 -0.24,0.93 0.11,1.27l0,0c0.43,0.43 1.15,0.39 1.51,-0.1c1.93,-2.63 1.93,-6.25 0,-8.87C21.19,7.08 20.47,7.04 20.05,7.46z"/>
+ android:pathData="M14,1L4,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L16,3c0,-1.1 -0.9,-2 -2,-2zM14,20L4,20L4,4h10v16zM20.63,8.26c-0.26,-0.32 -0.74,-0.36 -1.04,-0.06l-0.03,0.03c-0.25,0.25 -0.26,0.65 -0.05,0.93 1.26,1.64 1.25,3.87 -0.02,5.57 -0.21,0.28 -0.19,0.67 0.05,0.92l0.05,0.05c0.29,0.29 0.76,0.26 1.03,-0.05 1.8,-2.13 1.8,-5.19 0.01,-7.39zM17.42,10.37l-0.06,0.06c-0.2,0.2 -0.26,0.5 -0.15,0.76 0.21,0.49 0.21,1.03 0,1.52 -0.11,0.26 -0.05,0.56 0.15,0.76l0.08,0.08c0.32,0.32 0.87,0.25 1.09,-0.15 0.49,-0.89 0.49,-1.94 -0.01,-2.86 -0.22,-0.42 -0.77,-0.5 -1.1,-0.17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_setup.xml b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_setup.xml
index a4fec84..1367b7d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/phonelink_setup.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/phonelink_setup.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,18H7V6h10v1h2V3c0,-1.1 -0.9,-2 -2,-2L7,1.01C5.9,1.01 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-4h-2V18zM21,12c0,-0.13 -0.02,-0.26 -0.04,-0.39l0.64,-0.48c0.2,-0.15 0.26,-0.44 0.13,-0.66l-0.57,-0.96c-0.13,-0.21 -0.39,-0.3 -0.62,-0.2l-0.72,0.3c-0.2,-0.15 -0.42,-0.29 -0.65,-0.39l-0.1,-0.77c-0.03,-0.25 -0.24,-0.43 -0.49,-0.44l-1.12,-0.02c-0.26,0 -0.47,0.18 -0.5,0.44l-0.1,0.79c-0.24,0.1 -0.45,0.23 -0.65,0.39l-0.72,-0.3c-0.23,-0.1 -0.5,-0.01 -0.62,0.2l-0.57,0.96c-0.13,0.22 -0.08,0.5 0.13,0.66l0.64,0.48C15.02,11.74 15,11.87 15,12c0,0.13 0.02,0.25 0.04,0.37l-0.64,0.49c-0.2,0.15 -0.26,0.43 -0.13,0.65l0.56,0.97c0.13,0.22 0.39,0.31 0.63,0.21l0.73,-0.31c0.2,0.16 0.42,0.3 0.67,0.4l0.1,0.77c0.03,0.25 0.24,0.44 0.5,0.44h1.12c0.25,0 0.46,-0.19 0.5,-0.44l0.1,-0.77c0.24,-0.1 0.46,-0.24 0.67,-0.4l0.73,0.31c0.23,0.1 0.5,0.01 0.63,-0.21l0.56,-0.97c0.13,-0.22 0.07,-0.5 -0.13,-0.65l-0.64,-0.49C20.98,12.25 21,12.13 21,12zM18,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S18.83,13.5 18,13.5z"/>
+ android:pathData="M7,3v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1L9,4h10v16L9,20v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L21,3c0,-1.1 -0.9,-2 -2,-2L9,1c-1.1,0 -2,0.9 -2,2zM9.5,15.5c0.29,-0.12 0.55,-0.29 0.8,-0.48l-0.02,0.03 1.01,0.39c0.23,0.09 0.49,0 0.61,-0.22l0.84,-1.46c0.12,-0.21 0.07,-0.49 -0.12,-0.64l-0.85,-0.68 -0.02,0.03c0.02,-0.16 0.05,-0.32 0.05,-0.48s-0.03,-0.32 -0.05,-0.48l0.02,0.03 0.85,-0.68c0.19,-0.15 0.24,-0.43 0.12,-0.64l-0.84,-1.46c-0.12,-0.21 -0.38,-0.31 -0.61,-0.22l-1.01,0.39 0.02,0.03c-0.25,-0.17 -0.51,-0.34 -0.8,-0.46l-0.17,-1.08C9.3,7.18 9.09,7 8.84,7L7.16,7c-0.25,0 -0.46,0.18 -0.49,0.42L6.5,8.5c-0.29,0.12 -0.55,0.29 -0.8,0.48l0.02,-0.03 -1.02,-0.39c-0.23,-0.09 -0.49,0 -0.61,0.22l-0.84,1.46c-0.12,0.21 -0.07,0.49 0.12,0.64l0.85,0.68 0.02,-0.03c-0.02,0.15 -0.05,0.31 -0.05,0.47s0.03,0.32 0.05,0.48l-0.02,-0.03 -0.85,0.68c-0.19,0.15 -0.24,0.43 -0.12,0.64l0.84,1.46c0.12,0.21 0.38,0.31 0.61,0.22l1.01,-0.39 -0.01,-0.04c0.25,0.19 0.51,0.36 0.8,0.48l0.17,1.07c0.03,0.25 0.24,0.43 0.49,0.43h1.68c0.25,0 0.46,-0.18 0.49,-0.42l0.17,-1.08zM6,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2 -0.9,2 -2,2 -2,-0.9 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo.xml
index 6e55f90..08f6184 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM6.6,16.2l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,16l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67c0.25,0.33 0.01,0.8 -0.4,0.8H7C6.59,17 6.35,16.53 6.6,16.2z"/>
+ android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.9,13.98l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8H6.02c-0.42,0 -0.65,-0.48 -0.39,-0.81L8.12,14c0.19,-0.26 0.57,-0.27 0.78,-0.02z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo_album.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo_album.xml
index a83bd10..ef90e9d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo_album.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo_album.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM16.24,10.55L14.5,9.5l-1.74,1.05c-0.33,0.2 -0.76,-0.04 -0.76,-0.43V4h5v6.12C17,10.51 16.58,10.75 16.24,10.55zM7.6,17.2l1.38,-1.83c0.2,-0.27 0.6,-0.27 0.8,0L11,17l2.23,-2.97c0.2,-0.27 0.6,-0.27 0.8,0l2.38,3.17c0.25,0.33 0.01,0.8 -0.4,0.8H8C7.59,18 7.35,17.53 7.6,17.2z"/>
+ android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM15.24,10.55L13.5,9.5l-1.74,1.05c-0.33,0.2 -0.76,-0.04 -0.76,-0.43V4h5v6.12C16,10.51 15.58,10.75 15.24,10.55zM7.6,17.2l1.38,-1.83c0.2,-0.27 0.6,-0.27 0.8,0L11,17l2.23,-2.97c0.2,-0.27 0.6,-0.27 0.8,0l2.38,3.17c0.25,0.33 0.01,0.8 -0.4,0.8H8C7.59,18 7.35,17.53 7.6,17.2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo_camera.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo_camera.xml
index 9969066..ddeb49b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo_camera.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo_camera.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,13m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+ android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-3.17l-1.24,-1.35C15.22,3.24 14.68,3 14.12,3H9.88c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM12,17.5c-2.48,0 -4.5,-2.02 -4.5,-4.5S9.52,8.5 12,8.5s4.5,2.02 4.5,4.5S14.48,17.5 12,17.5z"/>
+ android:pathData="M20,4h-3.17l-1.24,-1.35c-0.37,-0.41 -0.91,-0.65 -1.47,-0.65L9.88,2c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo_filter.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo_filter.xml
index 01d5c4c..9a36777 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo_filter.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo_filter.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.02,10.99V19H5V5h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5.02c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2H19c1.1,0 2,-0.89 2,-2v-8.01c0,-0.55 -0.44,-0.99 -0.99,-0.99l0,0C19.46,10 19.02,10.44 19.02,10.99zM13.25,10.75L12.46,9c-0.18,-0.39 -0.73,-0.39 -0.91,0l-0.79,1.75L9,11.54c-0.39,0.18 -0.39,0.73 0,0.91l1.75,0.79L11.54,15c0.18,0.39 0.73,0.39 0.91,0l0.79,-1.75L15,12.46c0.39,-0.18 0.39,-0.73 0,-0.91L13.25,10.75zM17.94,6.06l-0.6,-1.32c-0.13,-0.29 -0.55,-0.29 -0.69,0l-0.6,1.32l-1.32,0.6c-0.29,0.13 -0.29,0.55 0,0.69l1.32,0.6l0.6,1.32c0.13,0.29 0.55,0.29 0.69,0l0.6,-1.32l1.32,-0.6c0.29,-0.13 0.29,-0.55 0,-0.69L17.94,6.06z"/>
+ android:pathData="M19.02,10.99L19.02,18c0,0.55 -0.45,1 -1,1L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5.02,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2L19,21c1.1,0 2,-0.89 2,-2v-8.01c0,-0.55 -0.44,-0.99 -0.99,-0.99s-0.99,0.44 -0.99,0.99zM13.25,10.75L12.46,9c-0.18,-0.39 -0.73,-0.39 -0.91,0l-0.79,1.75 -1.76,0.79c-0.39,0.18 -0.39,0.73 0,0.91l1.75,0.79 0.79,1.76c0.18,0.39 0.73,0.39 0.91,0l0.79,-1.75 1.76,-0.79c0.39,-0.18 0.39,-0.73 0,-0.91l-1.75,-0.8zM17.94,6.06l-0.6,-1.32c-0.13,-0.29 -0.55,-0.29 -0.69,0l-0.6,1.32 -1.32,0.6c-0.29,0.13 -0.29,0.55 0,0.69l1.32,0.6 0.6,1.32c0.13,0.29 0.55,0.29 0.69,0l0.6,-1.32 1.32,-0.6c0.29,-0.13 0.29,-0.55 0,-0.69l-1.32,-0.6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo_library.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo_library.xml
index f9ae294..6690de0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo_library.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo_library.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM9.6,13.2l1.38,-1.83c0.2,-0.27 0.6,-0.27 0.8,0L13,13l2.23,-2.97c0.2,-0.27 0.6,-0.27 0.8,0l2.38,3.17c0.25,0.33 0.01,0.8 -0.4,0.8h-8C9.59,14 9.35,13.53 9.6,13.2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M22,16L22,4c0,-1.1 -0.9,-2 -2,-2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zM11.4,12.53l1.63,2.18 2.58,-3.22c0.2,-0.25 0.58,-0.25 0.78,0l2.96,3.7c0.26,0.33 0.03,0.81 -0.39,0.81L9,16c-0.41,0 -0.65,-0.47 -0.4,-0.8l2,-2.67c0.2,-0.26 0.6,-0.26 0.8,0zM2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_actual.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_actual.xml
index 6e55f90..d70b496 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_actual.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_actual.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM6.6,16.2l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,16l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67c0.25,0.33 0.01,0.8 -0.4,0.8H7C6.59,17 6.35,16.53 6.6,16.2z"/>
+ android:pathData="M21,3H3C2,3 1,4 1,5v14c0,1.1 0.9,2 2,2h18c1,0 2,-1 2,-2V5c0,-1 -1,-2 -2,-2zM5.63,16.19l2.49,-3.2c0.2,-0.25 0.58,-0.26 0.78,-0.01l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8H6.02c-0.41,-0.01 -0.65,-0.49 -0.39,-0.82z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_large.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_large.xml
index 56b7716..8ac7995 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_large.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_large.xml
@@ -6,32 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,3C4,3 3,4 3,5h2V3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,3h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,3h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,3v2h2C21,4 20,3 19,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,7h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,15h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,21c1,0 2,-1 2,-2h-2V21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,11h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,3h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,7H3v12c0,1.1 0.9,2 2,2h12V9C17,7.9 16.1,7 15,7zM14,18H6c-0.41,0 -0.65,-0.47 -0.4,-0.8l1.38,-1.83c0.2,-0.27 0.6,-0.27 0.8,0L9,17l2.22,-2.97c0.2,-0.27 0.6,-0.27 0.8,0l2.38,3.17C14.65,17.53 14.41,18 14,18z"/>
+ android:pathData="M21,15h2v2h-2v-2zM21,11h2v2h-2v-2zM23,19h-2v2c1,0 2,-1 2,-2zM13,3h2v2h-2L13,3zM21,7h2v2h-2L21,7zM21,3v2h2c0,-1 -1,-2 -2,-2zM1,7h2v2L1,9L1,7zM17,3h2v2h-2L17,3zM17,19h2v2h-2v-2zM3,3C2,3 1,4 1,5h2L3,3zM9,3h2v2L9,5L9,3zM5,3h2v2L5,5L5,3zM1,11v8c0,1.1 0.9,2 2,2h12v-8c0,-1.1 -0.9,-2 -2,-2L1,11zM3.63,18.19l1.49,-1.91c0.2,-0.25 0.57,-0.26 0.78,-0.01l1.39,1.67 2.1,-2.7c0.2,-0.26 0.6,-0.26 0.79,0.01l2.22,2.96c0.25,0.33 0.01,0.8 -0.4,0.8L4.02,19.01c-0.41,-0.01 -0.65,-0.49 -0.39,-0.82z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_small.xml b/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_small.xml
index ffcf26d..7938f8a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_small.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/photo_size_select_small.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,3C4,3 3,4 3,5h2V3zM3,19c0,1.1 0.9,2 2,2h8v-8c0,-1.1 -0.9,-2 -2,-2H3V19zM3,7h2v2H3V7zM19,3v2h2C21,4 20,3 19,3zM7,3h2v2H7V3zM11,3h2v2h-2V3zM19,15h2v2h-2V15zM19,7h2v2h-2V7zM19,11h2v2h-2V11zM19,21c1,0 2,-1 2,-2h-2V21zM15,19h2v2h-2V19zM15,3h2v2h-2V3zM6.52,16.7L7.5,18l1.48,-1.97c0.2,-0.27 0.6,-0.27 0.8,0l1.62,2.17c0.25,0.33 0.01,0.8 -0.4,0.8H5c-0.41,0 -0.65,-0.47 -0.4,-0.8l1.12,-1.5C5.93,16.43 6.32,16.43 6.52,16.7z"/>
+ android:pathData="M23,15h-2v2h2v-2zM23,11h-2v2h2v-2zM23,19h-2v2c1,0 2,-1 2,-2zM15,3h-2v2h2L15,3zM23,7h-2v2h2L23,7zM21,3v2h2c0,-1 -1,-2 -2,-2zM3,21h8v-4c0,-1.1 -0.9,-2 -2,-2L1,15v4c0,1.1 0.9,2 2,2zM3,7L1,7v2h2L3,7zM15,19h-2v2h2v-2zM19,3h-2v2h2L19,3zM19,19h-2v2h2v-2zM3,3C2,3 1,4 1,5h2L3,3zM3,11L1,11v2h2v-2zM11,3L9,3v2h2L11,3zM7,3L5,3v2h2L7,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/picture_as_pdf.xml b/compose/material/material/icons/generator/raw-icons/rounded/picture_as_pdf.xml
index 859143f..96c630de 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/picture_as_pdf.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/picture_as_pdf.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,12h1V9h-1V12zM10,10h1V9h-1V10zM20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM12,10c0,0.55 -0.45,1 -1,1h-1v1.5c0,0.28 -0.22,0.5 -0.5,0.5h0C9.22,13 9,12.78 9,12.5v-4C9,8.22 9.22,8 9.5,8H11c0.55,0 1,0.45 1,1V10zM16,12c0,0.55 -0.45,1 -1,1h-1.5c-0.28,0 -0.5,-0.22 -0.5,-0.5v-4C13,8.22 13.22,8 13.5,8H15c0.55,0 1,0.45 1,1V12zM18.5,9H18v1h0.5c0.28,0 0.5,0.22 0.5,0.5v0c0,0.28 -0.22,0.5 -0.5,0.5H18v1.5c0,0.28 -0.22,0.5 -0.5,0.5l0,0c-0.28,0 -0.5,-0.22 -0.5,-0.5v-4C17,8.22 17.22,8 17.5,8h1C18.78,8 19,8.22 19,8.5v0C19,8.78 18.78,9 18.5,9zM3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM11.5,9.5c0,0.83 -0.67,1.5 -1.5,1.5L9,11v1.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75L7.5,8c0,-0.55 0.45,-1 1,-1L10,7c0.83,0 1.5,0.67 1.5,1.5v1zM16.5,11.5c0,0.83 -0.67,1.5 -1.5,1.5h-2c-0.28,0 -0.5,-0.22 -0.5,-0.5v-5c0,-0.28 0.22,-0.5 0.5,-0.5h2c0.83,0 1.5,0.67 1.5,1.5v3zM20.5,7.75c0,0.41 -0.34,0.75 -0.75,0.75L19,8.5v1h0.75c0.41,0 0.75,0.34 0.75,0.75s-0.34,0.75 -0.75,0.75L19,11v1.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75L17.5,8c0,-0.55 0.45,-1 1,-1h1.25c0.41,0 0.75,0.34 0.75,0.75zM9,9.5h1v-1L9,8.5v1zM3,6c-0.55,0 -1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1zM14,11.5h1v-3h-1v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture.xml b/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture.xml
index 6c1c313..e6ee1b9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,18.02V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v12.02C2,19.12 2.9,20 4,20h16C21.1,20 22,19.12 22,18.02zM19,8v4c0,0.55 -0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h6C18.55,7 19,7.45 19,8z"/>
+ android:pathData="M18,7h-6c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1L19,8c0,-0.55 -0.45,-1 -1,-1zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM20,19.01L4,19.01c-0.55,0 -1,-0.45 -1,-1L3,5.98c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12.03c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture_alt.xml
index bfb9f5d..cc48534 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/picture_in_picture_alt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.88 2,5.98V18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V5.98C22,4.88 21.1,4 20,4zM18,17h-6c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v4C19,16.55 18.55,17 18,17z"/>
+ android:pathData="M18,11h-6c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1zM23,19L23,4.98C23,3.88 22.1,3 21,3L3,3c-1.1,0 -2,0.88 -2,1.98L1,19c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2zM20,19.02L4,19.02c-0.55,0 -1,-0.45 -1,-1L3,5.97c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12.05c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pie_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/pie_chart.xml
index 404b94b..ff69f48 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pie_chart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pie_chart.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,2v20c-5.07,-0.5 -9,-4.79 -9,-10S5.93,2.5 11,2zM13.03,2v8.99H22C21.53,6.25 17.76,2.47 13.03,2zM13.03,13.01V22c4.74,-0.47 8.5,-4.25 8.97,-8.99H13.03z"/>
+ android:pathData="M11,3.18v17.64c0,0.64 -0.59,1.12 -1.21,0.98C5.32,20.8 2,16.79 2,12s3.32,-8.8 7.79,-9.8c0.62,-0.14 1.21,0.34 1.21,0.98zM13.03,3.18v6.81c0,0.55 0.45,1 1,1h6.79c0.64,0 1.12,-0.59 0.98,-1.22 -0.85,-3.76 -3.8,-6.72 -7.55,-7.57 -0.63,-0.14 -1.22,0.34 -1.22,0.98zM13.03,14.01v6.81c0,0.64 0.59,1.12 1.22,0.98 3.76,-0.85 6.71,-3.82 7.56,-7.58 0.14,-0.62 -0.35,-1.22 -0.98,-1.22h-6.79c-0.56,0.01 -1.01,0.46 -1.01,1.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pie_chart_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/pie_chart_outline.xml
index f6fade3..99e3633 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pie_chart_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pie_chart_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM13,4.07c3.61,0.45 6.48,3.33 6.93,6.93H13V4.07zM4,12c0,-4.06 3.07,-7.44 7,-7.93v15.87C7.07,19.44 4,16.06 4,12zM13,19.93V13h6.93C19.48,16.61 16.61,19.48 13,19.93z"/>
+ android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10 10,-4.5 10,-10S17.5,2 12,2zM13,4.07c3.61,0.45 6.48,3.33 6.93,6.93L14,11c-0.55,0 -1,-0.45 -1,-1L13,4.07zM4,12c0,-4.06 3.07,-7.44 7,-7.93v15.87c-3.93,-0.5 -7,-3.88 -7,-7.94zM13,19.93L13,14c0,-0.55 0.45,-1 1,-1h5.93c-0.45,3.61 -3.32,6.48 -6.93,6.93z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pin_end.xml b/compose/material/material/icons/generator/raw-icons/rounded/pin_end.xml
new file mode 100644
index 0000000..b1cb9d6
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pin_end.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,12V6H4v12h10l0,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h16c1.1,0 2,0.9 2,2v6H20zM19,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c1.66,0 3,-1.34 3,-3S20.66,14 19,14zM14.66,13.66c0.39,-0.39 0.39,-1.02 0,-1.41l-2.12,-2.12l1.27,-1.27C14.12,8.54 13.9,8 13.45,8H9.5C9.22,8 9,8.22 9,8.5v3.95c0,0.45 0.54,0.67 0.85,0.35l1.27,-1.27l2.12,2.12C13.63,14.05 14.27,14.05 14.66,13.66z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pin_invoke.xml b/compose/material/material/icons/generator/raw-icons/rounded/pin_invoke.xml
new file mode 100644
index 0000000..d7851dc
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pin_invoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12v6c0,1.1 -0.9,2 -2,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10l0,2H4v12h16v-6H22zM22,7c0,-1.66 -1.34,-3 -3,-3c-1.66,0 -3,1.34 -3,3s1.34,3 3,3C20.66,10 22,8.66 22,7zM9.34,15.66c0.39,0.39 1.02,0.39 1.41,0l2.12,-2.12l1.27,1.27C14.46,15.12 15,14.9 15,14.45V10.5c0,-0.28 -0.22,-0.5 -0.5,-0.5h-3.95c-0.45,0 -0.67,0.54 -0.35,0.85l1.27,1.27l-2.12,2.12C8.95,14.63 8.95,15.27 9.34,15.66z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/plagiarism.xml b/compose/material/material/icons/generator/raw-icons/rounded/plagiarism.xml
index fc5861d..0147471 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/plagiarism.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/plagiarism.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8L14,2zM14.89,19.3l-1.73,-1.73c-1.51,0.81 -3.47,0.46 -4.55,-1.1c-0.81,-1.17 -0.8,-2.79 0.02,-3.96c1.3,-1.84 3.84,-2 5.36,-0.48c1.12,1.12 1.31,2.8 0.59,4.13l1.73,1.73c0.39,0.39 0.39,1.02 0,1.41l0,0C15.91,19.68 15.27,19.68 14.89,19.3zM13,8V3.5L18.5,9H14C13.45,9 13,8.55 13,8z"/>
+ android:pathData="M19.41,7.41l-4.83,-4.83C14.21,2.21 13.7,2 13.17,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V8.83C20,8.3 19.79,7.79 19.41,7.41zM15.74,18.74L15.74,18.74c-0.39,0.39 -1.02,0.39 -1.41,0l-1.18,-1.18c-1.33,0.71 -3.01,0.53 -4.13,-0.59c-1.52,-1.52 -1.35,-4.08 0.5,-5.37c1.16,-0.81 2.78,-0.81 3.95,0c1.55,1.08 1.9,3.04 1.09,4.55l1.18,1.18C16.13,17.72 16.13,18.35 15.74,18.74zM14,9c-0.55,0 -1,-0.45 -1,-1V3.5L18.5,9H14z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M11.5,14.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/play_circle_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/play_circle_outline.xml
index d933dcc..9dd6f83b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/play_circle_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/play_circle_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM11.04,15.51l4.15,-2.67c0.61,-0.39 0.61,-1.29 0,-1.68l-4.15,-2.67C10.38,8.06 9.5,8.54 9.5,9.33v5.34C9.5,15.46 10.38,15.94 11.04,15.51z"/>
+ android:pathData="M10.8,15.9l4.67,-3.5c0.27,-0.2 0.27,-0.6 0,-0.8L10.8,8.1c-0.33,-0.25 -0.8,-0.01 -0.8,0.4v7c0,0.41 0.47,0.65 0.8,0.4zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/play_for_work.xml b/compose/material/material/icons/generator/raw-icons/rounded/play_for_work.xml
index 81527b9..2b66e20 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/play_for_work.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/play_for_work.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.9,14c-0.49,0 -0.88,0.35 -0.98,0.83C15.53,16.64 13.93,18 12,18s-3.53,-1.36 -3.91,-3.17C7.99,14.35 7.59,14 7.1,14h0c-0.61,0 -1.11,0.55 -0.99,1.15C6.65,17.91 9.08,20 12,20s5.35,-2.09 5.89,-4.85C18.01,14.55 17.51,14 16.9,14L16.9,14zM14.79,11H13V6c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v5H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79C15.46,11.54 15.24,11 14.79,11z"/>
+ android:pathData="M11,6v4.59L8.71,10.59c-0.45,0 -0.67,0.54 -0.35,0.85l3.29,3.29c0.2,0.2 0.51,0.2 0.71,0l3.29,-3.29c0.31,-0.31 0.09,-0.85 -0.35,-0.85L13,10.59L13,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM7.1,14c-0.61,0 -1.11,0.55 -0.99,1.15C6.65,17.91 9.08,20 12,20s5.35,-2.09 5.89,-4.85c0.12,-0.6 -0.38,-1.15 -0.99,-1.15 -0.49,0 -0.88,0.35 -0.98,0.83C15.53,16.64 13.93,18 12,18s-3.53,-1.36 -3.91,-3.17c-0.1,-0.48 -0.5,-0.83 -0.99,-0.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/playlist_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add.xml
index 2f36cc5..82a08b0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/playlist_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,10H4c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h9c0.55,0 1,-0.45 1,-1v0C14,10.45 13.55,10 13,10zM13,6H4C3.45,6 3,6.45 3,7v0c0,0.55 0.45,1 1,1h9c0.55,0 1,-0.45 1,-1v0C14,6.45 13.55,6 13,6zM18,14v-3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v3h-3c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H18zM4,16h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,15.55 3.45,16 4,16z"/>
+ android:pathData="M13,10L3,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM13,6L3,6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM18,14v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3zM3,16h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_check.xml b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_check.xml
index 9dedde7..919bff6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_check.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_check.xml
@@ -7,14 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,10H4c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h9c0.55,0 1,-0.45 1,-1v0C14,10.45 13.55,10 13,10z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,6H4C3.45,6 3,6.45 3,7v0c0,0.55 0.45,1 1,1h9c0.55,0 1,-0.45 1,-1v0C14,6.45 13.55,6 13,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,16h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,15.55 3.45,16 4,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.88,12.64l-3.54,3.54l-1.41,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l2.12,2.12c0.39,0.39 1.02,0.39 1.41,0l4.24,-4.24c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C20.9,12.25 20.27,12.25 19.88,12.64z"/>
+ android:pathData="M13,10L3,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM13,6L3,6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM3,16h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM22.21,12.21l0.09,0.09c0.39,0.39 0.39,1.02 0,1.41l-5.58,5.59c-0.39,0.39 -1.02,0.39 -1.41,0l-3.09,-3.09c-0.39,-0.39 -0.39,-1.02 0,-1.41l0.09,-0.09c0.39,-0.39 1.02,-0.39 1.41,0l2.3,2.3 4.78,-4.79c0.38,-0.4 1.02,-0.4 1.41,-0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_check_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_check_circle.xml
new file mode 100644
index 0000000..addd436
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_check_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM7,8c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H8C7.45,9 7,8.55 7,8L7,8zM7,11c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H8C7.45,12 7,11.55 7,11L7,11zM10,14c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h1C9.55,13 10,13.45 10,14L10,14zM18.29,14.12l-3.54,3.54c-0.39,0.39 -1.02,0.39 -1.41,0l-1.41,-1.41c-0.39,-0.39 -0.39,-1.02 0,-1.41c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71l2.83,-2.83c0.39,-0.39 1.02,-0.39 1.41,0C18.68,13.1 18.68,13.73 18.29,14.12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_circle.xml
new file mode 100644
index 0000000..10a0825
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/playlist_add_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7,8c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H8C7.45,9 7,8.55 7,8L7,8zM10,14c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h1C9.55,13 10,13.45 10,14L10,14zM8,12c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H8zM18,15h-1v1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-1h-1c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h1v-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v1h1c0.55,0 1,0.45 1,1S18.55,15 18,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/playlist_play.xml b/compose/material/material/icons/generator/raw-icons/rounded/playlist_play.xml
index 95ce461..4c2be06 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/playlist_play.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/playlist_play.xml
@@ -7,14 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,12h9c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,11.55 3.45,12 4,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,8h9c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4C3.45,6 3,6.45 3,7v0C3,7.55 3.45,8 4,8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,16h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v0C3,15.55 3.45,16 4,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,13.93v6.13c0,0.4 0.45,0.64 0.78,0.42l4.6,-3.07c0.3,-0.2 0.3,-0.63 0,-0.83l-4.6,-3.07C16.45,13.3 16,13.53 16,13.93z"/>
+ android:pathData="M5,10h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM5,6h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM5,14h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,16c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM14,14.88v4.23c0,0.39 0.42,0.63 0.76,0.43l3.53,-2.12c0.32,-0.19 0.32,-0.66 0,-0.86l-3.53,-2.12c-0.34,-0.19 -0.76,0.05 -0.76,0.44z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/plus_one.xml b/compose/material/material/icons/generator/raw-icons/rounded/plus_one.xml
index ac79cfe..0545630 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/plus_one.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/plus_one.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,12H8v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1S10.55,12 10,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.81,5c-0.25,0 -0.49,0.08 -0.7,0.23l-2.99,2.16c-0.45,0.33 -0.57,0.95 -0.26,1.42c0.33,0.49 1,0.62 1.48,0.27l1.41,-1.02v9.82c0,0.62 0.5,1.13 1.13,1.13C17.5,19 18,18.5 18,17.87V6.19C18,5.53 17.47,5 16.81,5z"/>
+ android:pathData="M9,8c-0.55,0 -1,0.45 -1,1v3L5,12c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L10,9c0,-0.55 -0.45,-1 -1,-1zM14.5,6.79c0,0.57 0.52,1 1.08,0.89L17,7.4L17,17c0,0.55 0.45,1 1,1s1,-0.45 1,-1L19,6.27c0,-0.65 -0.6,-1.12 -1.23,-0.97l-2.57,0.62c-0.41,0.09 -0.7,0.46 -0.7,0.87z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/policy.xml b/compose/material/material/icons/generator/raw-icons/rounded/policy.xml
index 2f8383c..49a8176 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/policy.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/policy.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.7,4.51l-6,-2.25c-0.45,-0.17 -0.95,-0.17 -1.4,0l-6,2.25C4.52,4.81 4,5.55 4,6.39v4.7c0,4.83 3.13,9.37 7.43,10.75c0.37,0.12 0.77,0.12 1.14,0c1.81,-0.58 3.4,-1.72 4.65,-3.2l-3.2,-3.2c-1.53,0.9 -3.53,0.71 -4.85,-0.61c-1.56,-1.56 -1.56,-4.09 0,-5.66c1.56,-1.56 4.09,-1.56 5.66,0c1.32,1.32 1.51,3.32 0.61,4.85l2.96,2.96c1.02,-1.75 1.61,-3.79 1.61,-5.89v-4.7C20,5.55 19.48,4.81 18.7,4.51z"/>
+ android:pathData="M21,6.3c0,-0.79 -0.47,-1.51 -1.19,-1.83l-7,-3.11c-0.52,-0.23 -1.11,-0.23 -1.62,0l-7,3.11C3.47,4.79 3,5.51 3,6.3V11c0,5.55 3.84,10.74 9,12c2.3,-0.56 4.33,-1.9 5.88,-3.71l-3.12,-3.12c-1.94,1.29 -4.58,1.07 -6.29,-0.64c-1.95,-1.95 -1.95,-5.12 0,-7.07c1.95,-1.95 5.12,-1.95 7.07,0c1.71,1.71 1.92,4.35 0.64,6.29l2.9,2.9C20.29,15.69 21,13.38 21,11V6.3z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M13.41,10.59c-0.78,-0.78 -2.05,-0.78 -2.83,0c-0.78,0.78 -0.78,2.05 0,2.83c0.78,0.78 2.05,0.78 2.83,0C14.2,12.63 14.2,11.37 13.41,10.59z"/>
+ android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/poll.xml b/compose/material/material/icons/generator/raw-icons/rounded/poll.xml
index d1c937d..6899ce1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/poll.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/poll.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM8,17L8,17c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v5C9,16.55 8.55,17 8,17zM12,17L12,17c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v8C13,16.55 12.55,17 12,17zM16,17L16,17c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v2C17,16.55 16.55,17 16,17z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM8,17c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5c0,0.55 -0.45,1 -1,1zM12,17c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8c0,0.55 -0.45,1 -1,1zM16,17c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/polymer.xml b/compose/material/material/icons/generator/raw-icons/rounded/polymer.xml
index 379f224..b7134f8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/polymer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/polymer.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4h-4L7.11,16.63L4.5,12L9,4H5l-4.5,8L5,20h4l7.89,-12.63L19.5,12L15,20h4l4.5,-8L19,4z"/>
+ android:pathData="M19,4h-4L7.11,16.63 4.5,12 9,4H5L0.5,12 5,20h4l7.89,-12.63L19.5,12 15,20h4l4.5,-8L19,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pool.xml b/compose/material/material/icons/generator/raw-icons/rounded/pool.xml
index 467b0d4..134d6d2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pool.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pool.xml
@@ -6,13 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.11,5.56C7.3,5.7 8.14,6.14 9,7l1,1l-3.25,3.25c0.31,0.12 0.56,0.27 0.77,0.39C7.89,11.87 8.11,12 8.67,12s0.78,-0.13 1.15,-0.36C10.28,11.37 10.9,11 12.01,11s1.73,0.37 2.18,0.64c0.37,0.22 0.6,0.36 1.15,0.36c0.55,0 0.78,-0.13 1.15,-0.36c0.12,-0.07 0.26,-0.15 0.41,-0.23L10.48,5C9.22,3.74 8.04,3.2 6.3,3.05C5.6,2.99 5,3.56 5,4.26v0.09C5,4.98 5.49,5.48 6.11,5.56z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.35,18.91c-0.17,-0.06 -0.32,-0.15 -0.5,-0.27C20.4,18.37 19.78,18 18.67,18s-1.73,0.37 -2.18,0.64c-0.37,0.23 -0.6,0.36 -1.15,0.36c-0.55,0 -0.78,-0.14 -1.15,-0.36C13.74,18.37 13.12,18 12.01,18s-1.73,0.37 -2.19,0.64C9.45,18.87 9.23,19 8.67,19s-0.78,-0.13 -1.15,-0.36C7.07,18.37 6.45,18 5.34,18s-1.73,0.37 -2.19,0.64c-0.18,0.11 -0.33,0.2 -0.5,0.27C2.27,19.04 2,19.36 2,19.76v0.12c0,0.67 0.66,1.13 1.3,0.91c0.37,-0.13 0.65,-0.3 0.89,-0.44C4.56,20.13 4.79,20 5.34,20s0.78,0.13 1.15,0.36C6.94,20.63 7.56,21 8.67,21s1.73,-0.37 2.19,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36c0.55,0 0.78,0.14 1.15,0.36c0.45,0.27 1.07,0.64 2.18,0.64s1.72,-0.37 2.18,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36c0.55,0 0.78,0.14 1.15,0.36c0.23,0.14 0.51,0.31 0.88,0.44c0.63,0.22 1.3,-0.24 1.3,-0.91v-0.12C22,19.36 21.73,19.04 21.35,18.91z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.11,16.35c0.47,-0.13 0.81,-0.33 1.09,-0.49c0.37,-0.23 0.6,-0.36 1.15,-0.36s0.78,0.14 1.15,0.36c0.45,0.27 1.07,0.64 2.18,0.64s1.73,-0.37 2.18,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36c0.55,0 0.78,0.14 1.15,0.36c0.45,0.27 1.07,0.64 2.18,0.64s1.73,-0.37 2.18,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36c0.55,0 0.78,0.14 1.15,0.36c0.23,0.14 0.5,0.3 0.85,0.43c0.63,0.23 1.31,-0.24 1.31,-0.91v-0.12c0,-0.4 -0.27,-0.72 -0.64,-0.86c-0.17,-0.06 -0.32,-0.15 -0.51,-0.26c-0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.18,0.64c-0.37,0.23 -0.6,0.36 -1.15,0.36s-0.78,-0.14 -1.15,-0.36c-0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.18,0.64c-0.37,0.23 -0.59,0.36 -1.15,0.36c-0.55,0 -0.78,-0.14 -1.15,-0.36c-0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.18,0.64c-0.18,0.11 -0.33,0.2 -0.5,0.27C2.27,14.54 2,14.86 2,15.26v0.23C2,16.07 2.55,16.51 3.11,16.35z"/>
+ android:pathData="M6.11,5.56C7.3,5.7 8.14,6.14 9,7l1,1 -3.25,3.25c0.31,0.12 0.56,0.27 0.77,0.39 0.37,0.23 0.59,0.36 1.15,0.36s0.78,-0.13 1.15,-0.36c0.46,-0.27 1.08,-0.64 2.19,-0.64s1.73,0.37 2.18,0.64c0.37,0.22 0.6,0.36 1.15,0.36 0.55,0 0.78,-0.13 1.15,-0.36 0.12,-0.07 0.26,-0.15 0.41,-0.23L10.48,5C9.22,3.74 8.04,3.2 6.3,3.05 5.6,2.99 5,3.56 5,4.26v0.09c0,0.63 0.49,1.13 1.11,1.21zM21.35,18.91c-0.17,-0.06 -0.32,-0.15 -0.5,-0.27 -0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.18,0.64c-0.37,0.23 -0.6,0.36 -1.15,0.36 -0.55,0 -0.78,-0.14 -1.15,-0.36 -0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.19,0.64c-0.37,0.23 -0.59,0.36 -1.15,0.36s-0.78,-0.13 -1.15,-0.36c-0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.19,0.64c-0.18,0.11 -0.33,0.2 -0.5,0.27 -0.38,0.13 -0.65,0.45 -0.65,0.85v0.12c0,0.67 0.66,1.13 1.3,0.91 0.37,-0.13 0.65,-0.3 0.89,-0.44 0.37,-0.22 0.6,-0.35 1.15,-0.35 0.55,0 0.78,0.13 1.15,0.36 0.45,0.27 1.07,0.64 2.18,0.64s1.73,-0.37 2.19,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36 0.55,0 0.78,0.14 1.15,0.36 0.45,0.27 1.07,0.64 2.18,0.64s1.72,-0.37 2.18,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36 0.55,0 0.78,0.14 1.15,0.36 0.23,0.14 0.51,0.31 0.88,0.44 0.63,0.22 1.3,-0.24 1.3,-0.91v-0.12c0,-0.41 -0.27,-0.73 -0.65,-0.86zM3.11,16.35c0.47,-0.13 0.81,-0.33 1.09,-0.49 0.37,-0.23 0.6,-0.36 1.15,-0.36 0.55,0 0.78,0.14 1.15,0.36 0.45,0.27 1.07,0.64 2.18,0.64s1.73,-0.37 2.18,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36 0.55,0 0.78,0.14 1.15,0.36 0.45,0.27 1.07,0.64 2.18,0.64s1.73,-0.37 2.18,-0.64c0.37,-0.23 0.59,-0.36 1.15,-0.36 0.55,0 0.78,0.14 1.15,0.36 0.23,0.14 0.5,0.3 0.85,0.43 0.63,0.23 1.31,-0.24 1.31,-0.91v-0.12c0,-0.4 -0.27,-0.72 -0.64,-0.86 -0.17,-0.06 -0.32,-0.15 -0.51,-0.26 -0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.18,0.64c-0.37,0.23 -0.6,0.36 -1.15,0.36s-0.78,-0.14 -1.15,-0.36c-0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.18,0.64c-0.37,0.23 -0.59,0.36 -1.15,0.36 -0.55,0 -0.78,-0.14 -1.15,-0.36 -0.45,-0.27 -1.07,-0.64 -2.18,-0.64s-1.73,0.37 -2.18,0.64c-0.18,0.11 -0.33,0.2 -0.5,0.27 -0.38,0.13 -0.65,0.45 -0.65,0.85v0.23c0,0.58 0.55,1.02 1.11,0.86z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M16.5,5.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/portable_wifi_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/portable_wifi_off.xml
index de3e083..e5eed00 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/portable_wifi_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/portable_wifi_off.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.94,5.11c0.75,-0.45 1.57,-0.78 2.45,-0.95C15.5,3.16 20,7.06 20,12c0,1.48 -0.41,2.87 -1.11,4.06l1.46,1.46c1.21,-1.82 1.83,-4.06 1.62,-6.45c-0.42,-4.66 -4.17,-8.49 -8.82,-9C10.67,1.79 8.37,2.43 6.5,3.67L7.94,5.11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10.69,6.14c-0.45,0.09 -0.87,0.26 -1.28,0.45l1.55,1.55c0.02,0 0.04,-0.01 0.06,-0.02C13.65,7.49 16,9.48 16,12c0,0.36 -0.05,0.7 -0.14,1.03l1.56,1.56C17.79,13.8 18,12.93 18,12C18,8.26 14.58,5.32 10.69,6.14z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l1.57,1.57C2.62,8.08 2,9.96 2,12c0,2.36 0.82,4.53 2.18,6.24c0.37,0.47 1.07,0.5 1.5,0.08c0.36,-0.36 0.39,-0.93 0.07,-1.32c-1.4,-1.74 -2.08,-4.08 -1.6,-6.57C4.32,9.54 4.66,8.7 5.11,7.94l1.47,1.47C6.4,9.8 6.25,10.2 6.15,10.63C5.77,12.36 6.13,14 6.98,15.29c0.35,0.54 1.1,0.62 1.56,0.17h0c0.34,-0.34 0.37,-0.87 0.11,-1.28c-0.58,-0.89 -0.81,-2.03 -0.51,-3.22L19.07,21.9c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51z"/>
+ android:pathData="M2.71,3.07c-0.39,0.39 -0.39,1.02 0,1.41L4.1,5.87C2.79,7.57 2,9.69 2,12c0,3.3 1.6,6.22 4.06,8.04 0.48,0.35 1.16,0.21 1.46,-0.31 0.25,-0.43 0.14,-0.99 -0.26,-1.29C5.29,16.98 4,14.65 4,12c0,-1.76 0.57,-3.38 1.53,-4.69l1.43,1.44C6.36,9.68 6,10.8 6,12c0,1.8 0.8,3.41 2.06,4.51 0.46,0.4 1.19,0.25 1.5,-0.28l0.01,-0.01c0.24,-0.42 0.13,-0.94 -0.23,-1.26C8.52,14.23 8,13.18 8,12c0,-0.65 0.17,-1.25 0.44,-1.79l1.58,1.58L10,12c0,1.1 0.9,2 2,2l0.21,-0.02 6.81,6.81c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.13,3.07c-0.39,-0.39 -1.03,-0.39 -1.42,0zM17.71,13.82c0.18,-0.57 0.29,-1.19 0.29,-1.82 0,-3.31 -2.69,-6 -6,-6 -0.63,0 -1.25,0.11 -1.82,0.29l1.72,1.72c0.03,0 0.06,-0.01 0.1,-0.01 2.21,0 4,1.79 4,4 0,0.04 -0.01,0.07 -0.01,0.11l1.72,1.71zM12,4c4.42,0 8,3.58 8,8 0,1.2 -0.29,2.32 -0.77,3.35l1.49,1.49C21.53,15.4 22,13.76 22,12c0,-5.52 -4.48,-10 -10,-10 -1.76,0 -3.4,0.48 -4.84,1.28l1.48,1.48C9.66,4.28 10.8,4 12,4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/portrait.xml b/compose/material/material/icons/generator/raw-icons/rounded/portrait.xml
index 32f6b3f..b5f6d48 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/portrait.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/portrait.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,6c1.93,0 3.5,1.57 3.5,3.5c0,1.93 -1.57,3.5 -3.5,3.5s-3.5,-1.57 -3.5,-3.5C8.5,7.57 10.07,6 12,6zM19,19H5v-0.23c0,-0.62 0.28,-1.2 0.76,-1.58C7.47,15.82 9.64,15 12,15s4.53,0.82 6.24,2.19c0.48,0.38 0.76,0.97 0.76,1.58V19z"/>
+ android:pathData="M12,12.25c1.24,0 2.25,-1.01 2.25,-2.25S13.24,7.75 12,7.75 9.75,8.76 9.75,10s1.01,2.25 2.25,2.25zM16.5,16.25c0,-1.5 -3,-2.25 -4.5,-2.25s-4.5,0.75 -4.5,2.25L7.5,17h9v-0.75zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/post_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/post_add.xml
index 3fb0b82..6fc983c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/post_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/post_add.xml
@@ -6,17 +6,17 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,9H9c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v0C16,9.45 15.55,9 15,9z"/>
+ android:pathData="M18,12c-0.55,0 -1,0.45 -1,1v5.22c0,0.55 -0.45,1 -1,1H6c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1H5C3.9,5 3,5.9 3,7v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-6C19,12.45 18.55,12 18,12z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15,12H9c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v0C16,12.45 15.55,12 15,12z"/>
+ android:pathData="M21.02,5H19V2.98C19,2.44 18.56,2 18.02,2h-0.03C17.44,2 17,2.44 17,2.98V5h-2.01C14.45,5 14.01,5.44 14,5.98c0,0.01 0,0.02 0,0.03C14,6.56 14.44,7 14.99,7H17v2.01c0,0.54 0.44,0.99 0.99,0.98c0.01,0 0.02,0 0.03,0c0.54,0 0.98,-0.44 0.98,-0.98V7h2.02C21.56,7 22,6.56 22,6.02V5.98C22,5.44 21.56,5 21.02,5z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M9,17h6c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H9c-0.55,0 -1,0.45 -1,1v0C8,16.55 8.45,17 9,17z"/>
+ android:pathData="M14,9H8c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1C15,9.45 14.55,9 14,9z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19,19H5V5h8c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-8c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1V19z"/>
+ android:pathData="M14,12H8c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1C15,12.45 14.55,12 14,12z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19,5V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1h-1c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1v1c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V7h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H19z"/>
+ android:pathData="M14,15H8c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1C15,15.45 14.55,15 14,15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/power.xml b/compose/material/material/icons/generator/raw-icons/rounded/power.xml
index baa78ec..4ffcef2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/power.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/power.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.01,7L16,4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v3h-4V4c0,-0.55 -0.45,-1 -1,-1l0,0C8.45,3 8,3.45 8,4v3H7.99C6.9,7 6,7.9 6,8.99v4.66c0,0.53 0.21,1.04 0.58,1.41L9.5,18v2c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-2l2.92,-2.92C17.79,14.7 18,14.19 18,13.66V8.99C18,7.89 17.11,7 16.01,7L16.01,7z"/>
+ android:pathData="M16.01,7L16,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-4V4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-0.01C6.9,7 6,7.9 6,8.99v4.66c0,0.53 0.21,1.04 0.58,1.41L9.5,18v2c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-2l2.92,-2.92c0.37,-0.38 0.58,-0.89 0.58,-1.42V8.99C18,7.89 17.11,7 16.01,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/power_input.xml b/compose/material/material/icons/generator/raw-icons/rounded/power_input.xml
index c3f93eb..998ecd3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/power_input.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/power_input.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,10L3,10c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,9 3,9.45 3,10zM4,15h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,14.55 3.45,15 4,15zM11,15h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1l0,0C10,14.55 10.45,15 11,15zM18,15h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1l0,0C17,14.55 17.45,15 18,15z"/>
+ android:pathData="M2,10c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,9c-0.55,0 -1,0.45 -1,1zM3,15h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L3,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM10,15h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM17,15h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/power_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/power_off.xml
index 55858e5..119c3d4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/power_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/power_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.64,14.81c0.23,-0.34 0.36,-0.74 0.36,-1.15V8.99C18,7.89 17.11,7 16.01,7L16,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-4V4c0,-0.55 -0.45,-1 -1,-1S8,3.45 8,4v1.17L17.64,14.81z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.25,16.25L7.18,7.18h0L5.35,5.35L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l3.91,3.91C6.01,8.89 6,8.94 6,8.99v4.66c0,0.53 0.21,1.04 0.58,1.41L9.5,18v2c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-2l0.34,-0.34l4.24,4.24c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L16.25,16.25z"/>
+ android:pathData="M18,13.66L18,8.99c0,-1 -1.01,-2 -2,-1.99L16,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-3.88l7.63,7.63c0.15,-0.3 0.25,-0.63 0.25,-0.97zM10,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v0.88l2,2L10,4zM20.15,19.86l-7.66,-7.66 -5.1,-5.1 -2.56,-2.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.63,2.63c-0.03,0.13 -0.05,0.27 -0.05,0.41v4.66c0,0.53 0.21,1.04 0.58,1.41L9.5,18v2c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-2l0.48,-0.48 3.76,3.76c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.03 0,-1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/power_settings_new.xml b/compose/material/material/icons/generator/raw-icons/rounded/power_settings_new.xml
index 4308622..b9c4730 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/power_settings_new.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/power_settings_new.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,3L12,3c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V4C13,3.45 12.55,3 12,3zM17.14,5.86L17.14,5.86c-0.39,0.39 -0.38,1 -0.01,1.39c1.13,1.2 1.83,2.8 1.87,4.57c0.09,3.83 -3.08,7.13 -6.91,7.17C8.18,19.05 5,15.9 5,12c0,-1.84 0.71,-3.51 1.87,-4.76c0.37,-0.39 0.37,-1 -0.01,-1.38l0,0c-0.4,-0.4 -1.05,-0.39 -1.43,0.02C3.98,7.42 3.07,9.47 3,11.74c-0.14,4.88 3.83,9.1 8.71,9.25c5.1,0.16 9.29,-3.93 9.29,-9c0,-2.37 -0.92,-4.51 -2.42,-6.11C18.2,5.47 17.54,5.46 17.14,5.86z"/>
+ android:pathData="M12,3c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1s1,-0.45 1,-1L13,4c0,-0.55 -0.45,-1 -1,-1zM17.14,5.86c-0.39,0.39 -0.38,1 -0.01,1.39 1.13,1.2 1.83,2.8 1.87,4.57 0.09,3.83 -3.08,7.13 -6.91,7.17C8.18,19.05 5,15.9 5,12c0,-1.84 0.71,-3.51 1.87,-4.76 0.37,-0.39 0.37,-1 -0.01,-1.38 -0.4,-0.4 -1.05,-0.39 -1.43,0.02C3.98,7.42 3.07,9.47 3,11.74c-0.14,4.88 3.83,9.1 8.71,9.25 5.1,0.16 9.29,-3.93 9.29,-9 0,-2.37 -0.92,-4.51 -2.42,-6.11 -0.38,-0.41 -1.04,-0.42 -1.44,-0.02z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/precision_manufacturing.xml b/compose/material/material/icons/generator/raw-icons/rounded/precision_manufacturing.xml
index 4530b37..51e3957 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/precision_manufacturing.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/precision_manufacturing.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.93,8.21l-3.6,1.68L14,7.7V6.3l2.33,-2.19l3.6,1.68c0.38,0.18 0.82,0.01 1,-0.36c0.18,-0.38 0.01,-0.82 -0.36,-1L16.65,2.6c-0.38,-0.18 -0.83,-0.1 -1.13,0.2l-1.74,1.6C13.6,4.16 13.32,4 13,4c-0.55,0 -1,0.45 -1,1v1H8.82C8.3,4.55 6.77,3.6 5.04,4.17c-0.89,0.29 -1.61,1.01 -1.89,1.9C2.67,7.57 3.4,8.9 4.52,9.58L7.08,18H5.5C4.67,18 4,18.67 4,19.5v0C4,20.33 4.67,21 5.5,21h10c0.83,0 1.5,-0.67 1.5,-1.5v0c0,-0.83 -0.67,-1.5 -1.5,-1.5h-2.12L8.41,8.77C8.58,8.53 8.72,8.28 8.82,8H12v1c0,0.55 0.45,1 1,1c0.32,0 0.6,-0.16 0.78,-0.4l1.74,1.6c0.3,0.3 0.75,0.38 1.13,0.2l3.92,-1.83c0.38,-0.18 0.54,-0.62 0.36,-1C20.75,8.2 20.31,8.03 19.93,8.21zM6,8C5.45,8 5,7.55 5,7s0.45,-1 1,-1s1,0.45 1,1S6.55,8 6,8z"/>
+ android:pathData="M19.93,8.35l-3.6,1.68L14,7.7V6.3l2.33,-2.33l3.6,1.68c0.38,0.18 0.82,0.01 1,-0.36c0.18,-0.38 0.01,-0.82 -0.36,-1l-3.92,-1.83c-0.38,-0.18 -0.83,-0.1 -1.13,0.2L13.78,4.4C13.6,4.16 13.32,4 13,4c-0.55,0 -1,0.45 -1,1v1H8.82C8.34,4.66 6.96,3.75 5.4,4.06C4.23,4.29 3.27,5.25 3.05,6.42C2.8,7.76 3.45,8.96 4.48,9.58L7.08,18H5.5C4.67,18 4,18.67 4,19.5v0C4,20.33 4.67,21 5.5,21h10c0.83,0 1.5,-0.67 1.5,-1.5v0c0,-0.83 -0.67,-1.5 -1.5,-1.5h-2.12L8.41,8.77C8.58,8.53 8.72,8.28 8.82,8H12v1c0,0.55 0.45,1 1,1c0.32,0 0.6,-0.16 0.78,-0.4l1.74,1.74c0.3,0.3 0.75,0.38 1.13,0.2l3.92,-1.83c0.38,-0.18 0.54,-0.62 0.36,-1C20.75,8.34 20.31,8.17 19.93,8.35zM6,8C5.45,8 5,7.55 5,7c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C7,7.55 6.55,8 6,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/pregnant_woman.xml b/compose/material/material/icons/generator/raw-icons/rounded/pregnant_woman.xml
index 9d4c047..b724be2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/pregnant_woman.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/pregnant_woman.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,4c0,-1.11 0.89,-2 2,-2s2,0.89 2,2s-0.89,2 -2,2S9,5.11 9,4zM16,13c-0.01,-1.34 -0.83,-2.51 -2,-3c0,-1.71 -1.42,-3.08 -3.16,-3C9.22,7.09 8,8.54 8,10.16V16c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5V17h2c0.55,0 1,-0.45 1,-1V13z"/>
+ android:pathData="M9,4c0,-1.11 0.89,-2 2,-2s2,0.89 2,2 -0.89,2 -2,2 -2,-0.89 -2,-2zM16,13c-0.01,-1.34 -0.83,-2.51 -2,-3 0,-1.71 -1.42,-3.08 -3.16,-3C9.22,7.09 8,8.54 8,10.16L8,16c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L13,17h2c0.55,0 1,-0.45 1,-1v-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/present_to_all.xml b/compose/material/material/icons/generator/raw-icons/rounded/present_to_all.xml
index 359eae4..ad0e792c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/present_to_all.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/present_to_all.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2,4.89 2,6v12c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6C22,4.89 21.11,4 20,4zM20,18.02H4V5.98h16V18.02z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11,12H9.21c-0.45,0 -0.67,-0.54 -0.35,-0.85l2.79,-2.79c0.2,-0.2 0.51,-0.2 0.71,0l2.79,2.79c0.31,0.31 0.09,0.85 -0.35,0.85H13v3c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V12z"/>
+ android:pathData="M21,3L3,3c-1.11,0 -2,0.89 -2,2v14c0,1.11 0.89,2 2,2h18c1.11,0 2,-0.89 2,-2L23,5c0,-1.11 -0.89,-2 -2,-2zM20,19.02L4,19.02c-0.55,0 -1,-0.45 -1,-1L3,5.98c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12.04c0,0.55 -0.45,1 -1,1zM10,12L8,12l3.65,-3.65c0.2,-0.2 0.51,-0.2 0.71,0L16,12h-2v4h-4v-4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/print.xml b/compose/material/material/icons/generator/raw-icons/rounded/print.xml
index 280de1a..063cd55 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/print.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/print.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7V4c0,-0.55 -0.45,-1 -1,-1H7C6.45,3 6,3.45 6,4v3H18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,8H5c-1.66,0 -3,1.34 -3,3v5c0,0.55 0.45,1 1,1h3v2c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-2h3c0.55,0 1,-0.45 1,-1v-5C22,9.34 20.66,8 19,8zM16,19H8v-4h8V19zM18,12.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S18.55,12.5 18,12.5z"/>
+ android:pathData="M19,8L5,8c-1.66,0 -3,1.34 -3,3v4c0,1.1 0.9,2 2,2h2v2c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-2h2c1.1,0 2,-0.9 2,-2v-4c0,-1.66 -1.34,-3 -3,-3zM15,19L9,19c-0.55,0 -1,-0.45 -1,-1v-4h8v4c0,0.55 -0.45,1 -1,1zM19,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM17,3L7,3c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1L18,4c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/print_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/print_disabled.xml
index 88ff219..b979a49 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/print_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/print_disabled.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7V4c0,-0.55 -0.45,-1 -1,-1H5.82l4.01,4H18zM2.1,4.93L5.17,8H5c-1.66,0 -3,1.34 -3,3v5c0,0.55 0.45,1 1,1h3v3c0,0.55 0.45,1 1,1h11.17l0.9,0.9c0.39,0.39 1.03,0.39 1.42,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.71,3.9 1.71,4.54 2.1,4.93zM8,15h4.17L16,18.83V19H8V15zM10.83,8l9,9H21c0.55,0 1,-0.45 1,-1v-5c0,-1.66 -1.34,-3 -3,-3H10.83zM18,12.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S18.55,12.5 18,12.5z"/>
+ android:pathData="M2.12,2.32c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L4.98,8C3.33,8.01 2,9.35 2,11v4c0,1.1 0.9,2 2,2h2v2c0,1.1 0.9,2 2,2h8c0.55,0 1.04,-0.22 1.4,-0.58l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L2.12,2.32zM15,19L9,19c-0.55,0 -1,-0.45 -1,-1v-4h2.98l4.72,4.72c-0.19,0.17 -0.43,0.28 -0.7,0.28zM19,8h-8.37l9,9L20,17c1.1,0 2,-0.9 2,-2v-4c0,-1.66 -1.34,-3 -3,-3zM19,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM17,7c0.55,0 1,-0.45 1,-1L18,4c0,-0.55 -0.45,-1 -1,-1L7,3c-0.37,0 -0.68,0.21 -0.85,0.51L9.63,7L17,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/priority_high.xml b/compose/material/material/icons/generator/raw-icons/rounded/priority_high.xml
index 2a92a60..0a7e4e5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/priority_high.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/priority_high.xml
@@ -9,5 +9,5 @@
android:pathData="M12,19m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,3c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2s2,-0.9 2,-2V5C14,3.9 13.1,3 12,3z"/>
+ android:pathData="M12,3c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2s2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/private_connectivity.xml b/compose/material/material/icons/generator/raw-icons/rounded/private_connectivity.xml
new file mode 100644
index 0000000..73cdc5d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/private_connectivity.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12c0,-0.55 -0.45,-1 -1,-1h-2.07c-0.49,-3.39 -3.4,-6 -6.93,-6s-6.44,2.61 -6.93,6H3c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2.07c0.49,3.39 3.4,6 6.93,6s6.44,-2.61 6.93,-6H21C21.55,13 22,12.55 22,12zM15,14.5c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1v-1c0,-1.21 1.08,-2.18 2.34,-1.97C13.32,7.69 14,8.61 14,9.61v0.89c0.55,0 1,0.45 1,1V14.5zM12.75,13c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75c0,-0.41 0.34,-0.75 0.75,-0.75S12.75,12.59 12.75,13zM13,9.5v1h-2v-1c0,-0.55 0.45,-1 1,-1S13,8.95 13,9.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/psychology.xml b/compose/material/material/icons/generator/raw-icons/rounded/psychology.xml
index e7e590f..bd1c63c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/psychology.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/psychology.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,10m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ android:pathData="M13,8.57c-0.79,0 -1.43,0.64 -1.43,1.43s0.64,1.43 1.43,1.43s1.43,-0.64 1.43,-1.43S13.79,8.57 13,8.57z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M13.21,3C9.37,2.89 6.21,5.87 6.02,9.64L4.1,12.2C3.85,12.53 4.09,13 4.5,13H6v3c0,1.1 0.9,2 2,2H9l0,2c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1l0,-3.68c2.44,-1.16 4.1,-3.68 4,-6.58C19.86,6.12 16.82,3.11 13.21,3zM16,10c0,0.13 -0.02,0.25 -0.04,0.38l0.65,0.49c0.2,0.15 0.26,0.43 0.13,0.65l-0.56,0.97c-0.13,0.22 -0.4,0.31 -0.63,0.21l-0.75,-0.32c-0.2,0.15 -0.42,0.29 -0.66,0.39l-0.1,0.79c-0.03,0.25 -0.24,0.44 -0.5,0.44h-1.12c-0.25,0 -0.46,-0.19 -0.5,-0.44l-0.1,-0.79c-0.24,-0.1 -0.45,-0.24 -0.66,-0.39l-0.75,0.32c-0.23,0.1 -0.5,0.01 -0.63,-0.21l-0.56,-0.97c-0.13,-0.22 -0.07,-0.5 0.13,-0.65l0.65,-0.49C10.02,10.25 10,10.13 10,10s0.02,-0.25 0.04,-0.38L9.38,9.13C9.18,8.98 9.13,8.7 9.25,8.48l0.56,-0.97c0.13,-0.22 0.4,-0.31 0.63,-0.21l0.75,0.32c0.2,-0.15 0.42,-0.29 0.66,-0.39l0.1,-0.79C11.97,6.19 12.18,6 12.44,6h1.12c0.25,0 0.46,0.19 0.5,0.44l0.1,0.79c0.24,0.1 0.45,0.24 0.66,0.39l0.75,-0.32c0.23,-0.1 0.5,-0.01 0.63,0.21l0.56,0.97c0.13,0.22 0.07,0.5 -0.13,0.65l-0.65,0.49C15.97,9.75 16,9.87 16,10z"/>
+ android:pathData="M13.21,3c-3.84,-0.11 -7,2.87 -7.19,6.64L4.1,12.2C3.85,12.53 4.09,13 4.5,13H6v3c0,1.1 0.9,2 2,2h1v2c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1v-3.68c2.44,-1.16 4.1,-3.68 4,-6.58C19.86,6.12 16.82,3.11 13.21,3zM16,10c0,0.13 -0.01,0.26 -0.02,0.39l0.83,0.66c0.08,0.06 0.1,0.16 0.05,0.25l-0.8,1.39c-0.05,0.09 -0.16,0.12 -0.24,0.09l-0.99,-0.4c-0.21,0.16 -0.43,0.29 -0.67,0.39L14,13.83c-0.01,0.1 -0.1,0.17 -0.2,0.17h-1.6c-0.1,0 -0.18,-0.07 -0.2,-0.17l-0.15,-1.06c-0.25,-0.1 -0.47,-0.23 -0.68,-0.39l-0.99,0.4c-0.09,0.03 -0.2,0 -0.25,-0.09l-0.8,-1.39c-0.05,-0.08 -0.03,-0.19 0.05,-0.25l0.84,-0.66C10.01,10.26 10,10.13 10,10c0,-0.13 0.02,-0.27 0.04,-0.39L9.19,8.95c-0.08,-0.06 -0.1,-0.16 -0.05,-0.26l0.8,-1.38c0.05,-0.09 0.15,-0.12 0.24,-0.09l1,0.4c0.2,-0.15 0.43,-0.29 0.67,-0.39l0.15,-1.06C12.02,6.07 12.1,6 12.2,6h1.6c0.1,0 0.18,0.07 0.2,0.17l0.15,1.06c0.24,0.1 0.46,0.23 0.67,0.39l1,-0.4c0.09,-0.03 0.2,0 0.24,0.09l0.8,1.38c0.05,0.09 0.03,0.2 -0.05,0.26l-0.85,0.66C15.99,9.73 16,9.86 16,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/public.xml b/compose/material/material/icons/generator/raw-icons/rounded/public.xml
index 3dc5190..19fb425 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/public.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/public.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM11,19.93C7.05,19.44 4,16.08 4,12c0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2V19.93zM17.9,17.39C17.64,16.58 16.9,16 16,16h-1v-3c0,-0.55 -0.45,-1 -1,-1H8v-2h2c0.55,0 1,-0.45 1,-1V7h2c1.1,0 2,-0.9 2,-2V4.59c2.93,1.19 5,4.06 5,7.41C20,14.08 19.2,15.97 17.9,17.39z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/publish.xml b/compose/material/material/icons/generator/raw-icons/rounded/publish.xml
index a82c09c..242565b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/publish.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/publish.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.41,14H9v5c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-5h1.59c0.89,0 1.34,-1.08 0.71,-1.71L12.71,7.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59C6.08,12.92 6.52,14 7.41,14zM19,4c0,-0.55 -0.45,-1 -1,-1H6C5.45,3 5,3.45 5,4s0.45,1 1,1h12C18.55,5 19,4.55 19,4z"/>
+ android:pathData="M5,5c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,4c-0.55,0 -1,0.45 -1,1zM7.41,14L9,14v5c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-5h1.59c0.89,0 1.34,-1.08 0.71,-1.71L12.71,7.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.63,0.63 -0.19,1.71 0.7,1.71z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/query_builder.xml b/compose/material/material/icons/generator/raw-icons/rounded/query_builder.xml
index b82761b..07b7ee3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/query_builder.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/query_builder.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM16,16c-0.39,0.39 -1.02,0.39 -1.41,0l-3.29,-3.29C11.11,12.52 11,12.27 11,12V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3.59l3,3C16.39,14.98 16.39,15.61 16,16z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM11.78,7h-0.06c-0.4,0 -0.72,0.32 -0.72,0.72v4.72c0,0.35 0.18,0.68 0.49,0.86l4.15,2.49c0.34,0.2 0.78,0.1 0.98,-0.24 0.21,-0.34 0.1,-0.79 -0.25,-0.99l-3.87,-2.3L12.5,7.72c0,-0.4 -0.32,-0.72 -0.72,-0.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/question_answer.xml b/compose/material/material/icons/generator/raw-icons/rounded/question_answer.xml
index aa4a202..e63e167 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/question_answer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/question_answer.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-1v9H6v1c0,1.1 0.9,2 2,2h10l3.15,3.15c0.31,0.31 0.85,0.09 0.85,-0.35V8C22,6.9 21.1,6 20,6zM17,11V4c0,-1.1 -0.9,-2 -2,-2H4C2.9,2 2,2.9 2,4v11.79c0,0.45 0.54,0.67 0.85,0.35L6,13h9C16.1,13 17,12.1 17,11z"/>
+ android:pathData="M20,6h-1v8c0,0.55 -0.45,1 -1,1L6,15v1c0,1.1 0.9,2 2,2h10l4,4L22,8c0,-1.1 -0.9,-2 -2,-2zM17,11L17,4c0,-1.1 -0.9,-2 -2,-2L4,2c-1.1,0 -2,0.9 -2,2v13l4,-4h9c1.1,0 2,-0.9 2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/queue.xml b/compose/material/material/icons/generator/raw-icons/rounded/queue.xml
index fe89126..1fee4b6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/queue.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/queue.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,11h-2v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-2h-2c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h2V7c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2h2c0.55,0 1,0.45 1,1v0C18,10.55 17.55,11 17,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
+ android:pathData="M3,6c-0.55,0 -1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,11h-3v3c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3L13,6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/queue_music.xml b/compose/material/material/icons/generator/raw-icons/rounded/queue_music.xml
index 8c78e63..f5013dd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/queue_music.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/queue_music.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,6h-3c-0.55,0 -1,0.45 -1,1v7.18C16.69,14.07 16.35,14 16,14c-1.84,0 -3.28,1.64 -2.95,3.54c0.21,1.21 1.2,2.2 2.41,2.41C17.36,20.28 19,18.84 19,17V8h2c0.55,0 1,-0.45 1,-1v0C22,6.45 21.55,6 21,6zM14,6H4C3.45,6 3,6.45 3,7v0c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1v0C15,6.45 14.55,6 14,6zM14,10H4c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1v0C15,10.45 14.55,10 14,10zM10,14H4c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v0C11,14.45 10.55,14 10,14z"/>
+ android:pathData="M14,6L4,6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM14,10L4,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM4,16h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM19,6c-1.1,0 -2,0.9 -2,2v6.18c-0.31,-0.11 -0.65,-0.18 -1,-0.18 -1.84,0 -3.28,1.64 -2.95,3.54 0.21,1.21 1.2,2.2 2.41,2.41 1.9,0.33 3.54,-1.11 3.54,-2.95L19,8h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/queue_play_next.xml b/compose/material/material/icons/generator/raw-icons/rounded/queue_play_next.xml
index e34b5a5..89842c2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/queue_play_next.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/queue_play_next.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.75,14.25L18.75,14.25c-0.41,0.41 -0.41,1.09 0,1.5L21,18l-2.25,2.25c-0.41,0.41 -0.41,1.09 0,1.5l0,0c0.41,0.41 1.09,0.41 1.5,0l3.04,-3.04c0.39,-0.39 0.39,-1.02 0,-1.41l-3.04,-3.04C19.84,13.84 19.16,13.84 18.75,14.25z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,17H4V5h16v6c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5c0,-1.1 -0.9,-2 -2,-2H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1v-1h1c0.55,0 1,-0.45 1,-1v0C17,17.45 16.55,17 16,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,14v-2h2c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-2V8c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v2H9c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h2v2c0,0.55 0.45,1 1,1h0C12.55,15 13,14.55 13,14z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,17c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v6c0,0.55 0.45,1 1,1s1,-0.45 1,-1L23,5c0,-1.1 -0.9,-2 -2,-2zM13,10L13,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2L9,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h2v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2zM23.29,18.71l-3.04,3.04c-0.41,0.41 -1.09,0.41 -1.5,0 -0.41,-0.41 -0.41,-1.09 0,-1.5L21,18l-2.25,-2.25c-0.41,-0.41 -0.41,-1.09 0,-1.5 0.41,-0.41 1.09,-0.41 1.5,0l3.04,3.04c0.39,0.39 0.39,1.03 0,1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/radio.xml b/compose/material/material/icons/generator/raw-icons/rounded/radio.xml
index bef60b6..fa61e45 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/radio.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/radio.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6H8.3l7.43,-3c0.46,-0.19 0.68,-0.71 0.49,-1.17l0,0c-0.19,-0.46 -0.71,-0.68 -1.17,-0.49L3.24,6.15C2.51,6.43 2,7.17 2,8v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM8,18.98c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S9.38,18.98 8,18.98zM20,11h-2v-1c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1H4V8h16V11z"/>
+ android:pathData="M3.24,6.15C2.51,6.43 2,7.17 2,8v12c0,1.1 0.9,2 2,2h16c1.11,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2L8.3,6l7.43,-3c0.46,-0.19 0.68,-0.71 0.49,-1.17 -0.19,-0.46 -0.71,-0.68 -1.17,-0.49L3.24,6.15zM7,20c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM20,12h-2v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L4,12L4,9c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/radio_button_checked.xml b/compose/material/material/icons/generator/raw-icons/rounded/radio_button_checked.xml
index 3d04232..6d654e3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/radio_button_checked.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/radio_button_checked.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-5,0a5,5 0,1 1,10 0a5,5 0,1 1,-10 0"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/radio_button_unchecked.xml b/compose/material/material/icons/generator/raw-icons/rounded/radio_button_unchecked.xml
index 11cee48..bcb6fc9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/radio_button_unchecked.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/radio_button_unchecked.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rate_review.xml b/compose/material/material/icons/generator/raw-icons/rounded/rate_review.xml
index 62b1a1a..9da9b39 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rate_review.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rate_review.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4.01c-1.1,0 -2,0.89 -2,2L2,19.58c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM17,14h-6.5l2,-2H17c0.55,0 1,0.45 1,1S17.55,14 17,14zM6,13.5v-1.76c0,-0.13 0.05,-0.26 0.15,-0.35l5.73,-5.74c0.2,-0.2 0.51,-0.2 0.71,0l1.77,1.77c0.2,0.2 0.19,0.51 0,0.71l-5.74,5.73C8.52,13.95 8.39,14 8.26,14H6.5C6.22,14 6,13.78 6,13.5z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM6,14v-2.47l6.88,-6.88c0.2,-0.2 0.51,-0.2 0.71,0l1.77,1.77c0.2,0.2 0.2,0.51 0,0.71L8.47,14L6,14zM17,14h-6.5l2,-2L17,12c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/real_estate_agent.xml b/compose/material/material/icons/generator/raw-icons/rounded/real_estate_agent.xml
new file mode 100644
index 0000000..e136f7d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/real_estate_agent.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,22c1.1,0 2,-0.9 2,-2v-7c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v7C1,21.1 1.9,22 3,22zM11.37,16.43l1.47,0.51c0.11,0.04 0.22,0.06 0.33,0.06h6.83c1.11,0 2,0.89 2.01,2l0,0l-7.39,2.77c-0.4,0.15 -0.84,0.17 -1.25,0.05L7,20.02V11H8.6c0.24,0 0.48,0.04 0.7,0.13l6.93,2.59c0.46,0.17 0.77,0.61 0.77,1.11v0c0,0.65 -0.53,1.18 -1.18,1.18h-2.63c-0.12,0 -0.24,-0.02 -0.36,-0.07l-1.12,-0.43c-0.26,-0.1 -0.55,0.04 -0.64,0.3C10.98,16.06 11.11,16.34 11.37,16.43zM20.16,5.9l-5,-3.57c-0.7,-0.5 -1.63,-0.5 -2.32,0l-5,3.57C7.31,6.28 7,6.88 7,7.53V9h1.61c0.25,0 0.51,0.05 0.74,0.14l7.79,3.11C18.26,12.71 19,13.79 19,15h2V7.53C21,6.88 20.69,6.28 20.16,5.9zM13,10c-0.28,0 -0.5,-0.22 -0.5,-0.5C12.5,9.22 12.72,9 13,9s0.5,0.22 0.5,0.5C13.5,9.78 13.28,10 13,10zM13,8c-0.28,0 -0.5,-0.22 -0.5,-0.5C12.5,7.22 12.72,7 13,7s0.5,0.22 0.5,0.5C13.5,7.78 13.28,8 13,8zM15,10c-0.28,0 -0.5,-0.22 -0.5,-0.5C14.5,9.22 14.72,9 15,9s0.5,0.22 0.5,0.5C15.5,9.78 15.28,10 15,10zM15,8c-0.28,0 -0.5,-0.22 -0.5,-0.5C14.5,7.22 14.72,7 15,7s0.5,0.22 0.5,0.5C15.5,7.78 15.28,8 15,8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/receipt.xml b/compose/material/material/icons/generator/raw-icons/rounded/receipt.xml
index ca1e5df..1d34513 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/receipt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/receipt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,2.21c-0.13,0 -0.26,0.05 -0.35,0.15l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.8,-0.8c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.8c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.8c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.8c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.8C3.26,2.26 3.13,2.21 3,2.21V21.8c0.13,0 0.26,-0.05 0.35,-0.15l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.1,0.1 0.23,0.15 0.35,0.15V2.21H21zM17,17H7c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1C18,16.55 17.55,17 17,17zM17,13H7c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1S17.55,13 17,13zM17,9H7C6.45,9 6,8.55 6,8s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1S17.55,9 17,9z"/>
+ android:pathData="M21,2.21c-0.13,0 -0.26,0.05 -0.35,0.15l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.79c-0.2,0.2 -0.51,0.2 -0.71,0l-0.8,-0.8c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.8c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.8c-0.2,-0.2 -0.51,-0.2 -0.71,0l-0.79,0.8c-0.2,0.2 -0.51,0.2 -0.71,0l-0.79,-0.8c-0.09,-0.09 -0.22,-0.14 -0.35,-0.14L3,21.8c0.13,0 0.26,-0.05 0.35,-0.15l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.2,0.2 0.51,0.2 0.71,0l0.79,-0.79c0.2,-0.2 0.51,-0.2 0.71,0l0.79,0.79c0.1,0.1 0.23,0.15 0.35,0.15L20.99,2.21zM17,17L7,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,13L7,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,9L7,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h10c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/receipt_long.xml b/compose/material/material/icons/generator/raw-icons/rounded/receipt_long.xml
index 28c9f93..47867c7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/receipt_long.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/receipt_long.xml
@@ -7,17 +7,17 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,9.1h-4c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1l0,0C15,8.65 14.55,9.1 14,9.1z"/>
+ android:pathData="M14,9h-4C9.45,9 9,8.55 9,8v0c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1v0C15,8.55 14.55,9 14,9z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M14,12.1h-4c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1l0,0C15,11.65 14.55,12.1 14,12.1z"/>
+ android:pathData="M14,12h-4c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1v0C15,11.55 14.55,12 14,12z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19.5,3.6l-1.15,-1.15c-0.2,-0.2 -0.51,-0.2 -0.71,0L16.5,3.6l-1.15,-1.15c-0.2,-0.2 -0.51,-0.2 -0.71,0L13.5,3.6l-1.15,-1.15c-0.2,-0.2 -0.51,-0.2 -0.71,0L10.5,3.6L9.35,2.46c-0.2,-0.2 -0.51,-0.2 -0.71,0L7.5,3.6L6.43,2.53C6.27,2.37 6,2.48 6,2.71v13.4H4c-0.55,0 -1,0.45 -1,1v2c0,1.66 1.34,3 3,3h12c1.66,0 3,-1.34 3,-3V2.71c0,-0.22 -0.27,-0.33 -0.43,-0.18L19.5,3.6zM19,19.1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2c0,-0.55 -0.45,-1 -1,-1h-2h-2H8v-11h11V19.1z"/>
+ android:pathData="M19.5,3.5L18,2l-1.5,1.5L15,2l-1.5,1.5L12,2l-1.5,1.5L9,2L7.5,3.5L6,2v14H4c-0.55,0 -1,0.45 -1,1v2c0,1.66 1.34,3 3,3h12c1.66,0 3,-1.34 3,-3V2L19.5,3.5zM15,20H6c-0.55,0 -1,-0.45 -1,-1v-1h3h4h3V20zM19,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2c0,-0.55 -0.45,-1 -1,-1h-2h-2H8V5h11V19z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17,8.1m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M17,8m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17,11.1m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M17,11m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/recent_actors.xml b/compose/material/material/icons/generator/raw-icons/rounded/recent_actors.xml
index 9ec9a18..f678902 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/recent_actors.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/recent_actors.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,5H3C1.9,5 1,5.9 1,7v10c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V7C15,5.9 14.1,5 13,5zM8,7.75c1.52,0 2.75,1.23 2.75,2.75c0,1.52 -1.23,2.75 -2.75,2.75s-2.75,-1.23 -2.75,-2.75C5.25,8.98 6.48,7.75 8,7.75zM13,17H3v-0.4c0,-0.79 0.46,-1.53 1.19,-1.83C5.36,14.27 6.65,14 8,14s2.64,0.27 3.81,0.76C12.54,15.07 13,15.8 13,16.6V17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,6v12c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h0C21.45,5 21,5.45 21,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,19L18,19c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v12C17,18.55 17.45,19 18,19z"/>
+ android:pathData="M21,6v12c0,0.55 0.45,1 1,1s1,-0.45 1,-1L23,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM18,19c0.55,0 1,-0.45 1,-1L19,6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v12c0,0.55 0.45,1 1,1zM14,5L2,5c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1L15,6c0,-0.55 -0.45,-1 -1,-1zM8,7.75c1.24,0 2.25,1.01 2.25,2.25S9.24,12.25 8,12.25 5.75,11.24 5.75,10 6.76,7.75 8,7.75zM12.5,17h-9v-0.75c0,-1.5 3,-2.25 4.5,-2.25s4.5,0.75 4.5,2.25L12.5,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/record_voice_over.xml b/compose/material/material/icons/generator/raw-icons/rounded/record_voice_over.xml
index ddd1e2b..859ed75 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/record_voice_over.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/record_voice_over.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.46,7.72c0.34,0.82 0.34,1.72 0,2.54c-0.19,0.45 -0.1,0.96 0.24,1.3l0.1,0.1c0.56,0.56 1.51,0.44 1.88,-0.26c0.8,-1.48 0.79,-3.24 -0.03,-4.79c-0.37,-0.69 -1.31,-0.83 -1.86,-0.27l-0.1,0.1C15.35,6.78 15.27,7.28 15.46,7.72zM19.18,2.89L19.18,2.89c-0.4,0.4 -0.46,1.02 -0.13,1.48c1.97,2.73 1.96,6.39 -0.01,9.23c-0.32,0.47 -0.26,1.1 0.14,1.5l0,0c0.5,0.5 1.34,0.46 1.78,-0.1c2.73,-3.54 2.73,-8.36 -0.02,-12C20.51,2.44 19.67,2.4 19.18,2.89zM9,13c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S5,6.79 5,9C5,11.21 6.79,13 9,13zM15.39,15.56C13.71,14.7 11.53,14 9,14c-2.53,0 -4.71,0.7 -6.39,1.56C1.61,16.07 1,17.1 1,18.22L1,20c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1l0,-1.78C17,17.1 16.39,16.07 15.39,15.56z"/>
+ android:pathData="M9,9m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,15c-2.67,0 -8,1.34 -8,4v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1c0,-2.66 -5.33,-4 -8,-4zM15.47,7.77c0.32,0.79 0.32,1.67 0,2.46 -0.19,0.47 -0.11,1 0.25,1.36l0.03,0.03c0.58,0.58 1.57,0.46 1.95,-0.27 0.76,-1.45 0.76,-3.15 -0.02,-4.66 -0.38,-0.74 -1.38,-0.88 -1.97,-0.29l-0.01,0.01c-0.34,0.35 -0.42,0.89 -0.23,1.36zM19.18,2.89c-0.4,0.4 -0.46,1.02 -0.13,1.48 1.97,2.74 1.96,6.41 -0.03,9.25 -0.32,0.45 -0.25,1.07 0.14,1.46l0.03,0.03c0.49,0.49 1.32,0.45 1.74,-0.1 2.75,-3.54 2.76,-8.37 0,-12.02 -0.42,-0.55 -1.26,-0.59 -1.75,-0.1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/recycling.xml b/compose/material/material/icons/generator/raw-icons/rounded/recycling.xml
new file mode 100644
index 0000000..2de3949
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/recycling.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.2,7.41C5.97,7.27 5.89,6.96 6.03,6.73L7.2,4.78l1.03,-1.71c0.39,-0.65 1.33,-0.65 1.72,0l1.48,2.46l-1.23,2.06l-0.72,1.2C9.32,9.02 9.01,9.1 8.77,8.96L6.2,7.41zM21.72,12.97l-1.34,-2.24c-0.14,-0.23 -0.44,-0.31 -0.68,-0.18l-2.6,1.5c-0.24,0.14 -0.32,0.45 -0.18,0.69L18.87,16l1.09,0c0.61,0 1.2,-0.26 1.59,-0.73C21.85,14.9 22,14.45 22,14C22,13.64 21.9,13.29 21.72,12.97zM16,21h1.5c0.76,0 1.45,-0.43 1.79,-1.11L20.74,17H16v-0.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.35V21zM9.5,17H5.7l-0.84,1.41c-0.3,0.5 -0.32,1.12 -0.06,1.65l0,0C5.08,20.63 5.67,21 6.32,21H9.5c0.28,0 0.5,-0.22 0.5,-0.5v-3C10,17.22 9.78,17 9.5,17zM6.12,14.35l0.7,0.42c0.38,0.23 0.85,-0.12 0.74,-0.55L6.6,10.38C6.54,10.12 6.27,9.95 6,10.02l-3.83,0.96c-0.43,0.11 -0.52,0.68 -0.14,0.91l0.66,0.4l-0.41,0.69c-0.35,0.59 -0.38,1.31 -0.07,1.92l1.63,3.26L6.12,14.35zM17.02,5.14l-1.3,-2.17C15.35,2.37 14.7,2 14,2h-3.53l3.12,5.2L12.9,7.61c-0.38,0.23 -0.3,0.81 0.14,0.91l3.83,0.96c0.27,0.07 0.54,-0.1 0.61,-0.36l0.96,-3.83c0.11,-0.43 -0.36,-0.78 -0.74,-0.55L17.02,5.14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/redeem.xml b/compose/material/material/icons/generator/raw-icons/rounded/redeem.xml
index 43db4ab..309157d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/redeem.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/redeem.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-2.18C17.93,5.69 18,5.35 18,5c0,-1.66 -1.34,-3 -3,-3c-1.05,0 -1.96,0.54 -2.5,1.35L12,4.02l-0.5,-0.68C10.96,2.54 10.05,2 9,2C7.34,2 6,3.34 6,5c0,0.35 0.07,0.69 0.18,1H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM15,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S14.45,4 15,4zM9,4c0.55,0 1,0.45 1,1S9.55,6 9,6S8,5.55 8,5S8.45,4 9,4zM20,19H4v-2h16V19zM20,14H4V8h5.08L7.6,10.02c-0.33,0.45 -0.23,1.08 0.22,1.4c0.44,0.32 1.07,0.22 1.39,-0.22L12,7.4l2.79,3.8c0.32,0.44 0.95,0.54 1.39,0.22c0.45,-0.32 0.55,-0.95 0.22,-1.4L14.92,8H20V14z"/>
+ android:pathData="M20,6h-2.18c0.11,-0.31 0.18,-0.65 0.18,-1 0,-1.66 -1.34,-3 -3,-3 -1.05,0 -1.96,0.54 -2.5,1.35l-0.5,0.67 -0.5,-0.68C10.96,2.54 10.05,2 9,2 7.34,2 6,3.34 6,5c0,0.35 0.07,0.69 0.18,1L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM15,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM9,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,19L5,19c-0.55,0 -1,-0.45 -1,-1v-1h16v1c0,0.55 -0.45,1 -1,1zM20,14L4,14L4,9c0,-0.55 0.45,-1 1,-1h4.08L7.6,10.02c-0.33,0.45 -0.23,1.08 0.22,1.4 0.44,0.32 1.07,0.22 1.39,-0.22L12,7.4l2.79,3.8c0.32,0.44 0.95,0.54 1.39,0.22 0.45,-0.32 0.55,-0.95 0.22,-1.4L14.92,8L19,8c0.55,0 1,0.45 1,1v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/redo.xml b/compose/material/material/icons/generator/raw-icons/rounded/redo.xml
index cfde59f5..f2eb4e6e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/redo.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/redo.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.05,10.91c-3.9,-3.88 -10.23,-3.88 -14.12,0.02c-1.09,1.09 -1.9,2.4 -2.39,3.82C2.33,15.36 2.8,16 3.45,16h0.11c0.42,0 0.77,-0.28 0.91,-0.67c0.39,-1.11 1.02,-2.13 1.88,-2.99c3.11,-3.11 8.18,-3.12 11.3,-0.02l-1.97,1.97C15.04,14.92 15.49,16 16.38,16h4.59c0.55,0 1,-0.45 1,-1v-4.59c0,-0.89 -1.08,-1.34 -1.71,-0.71L19.05,10.91z"/>
+ android:pathData="M18.4,10.6C16.55,8.99 14.15,8 11.5,8c-4.16,0 -7.74,2.42 -9.44,5.93 -0.32,0.67 0.04,1.47 0.75,1.71 0.59,0.2 1.23,-0.08 1.5,-0.64 1.3,-2.66 4.03,-4.5 7.19,-4.5 1.95,0 3.73,0.72 5.12,1.88l-1.91,1.91c-0.63,0.63 -0.19,1.71 0.7,1.71H21c0.55,0 1,-0.45 1,-1V9.41c0,-0.89 -1.08,-1.34 -1.71,-0.71l-1.89,1.9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/refresh.xml b/compose/material/material/icons/generator/raw-icons/rounded/refresh.xml
index 5b41eb3..5cdbeb0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/refresh.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/refresh.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.65,6.35c-1.63,-1.63 -3.94,-2.57 -6.48,-2.31c-3.67,0.37 -6.69,3.35 -7.1,7.02C3.52,15.91 7.27,20 12,20c3.19,0 5.93,-1.87 7.21,-4.56c0.32,-0.67 -0.16,-1.44 -0.9,-1.44l0,0c-0.37,0 -0.72,0.2 -0.88,0.53c-1.13,2.43 -3.84,3.97 -6.8,3.31c-2.22,-0.49 -4.01,-2.3 -4.48,-4.52C5.31,9.44 8.26,6 12,6c1.66,0 3.14,0.69 4.22,1.78l-1.51,1.51C14.08,9.92 14.52,11 15.41,11H19c0.55,0 1,-0.45 1,-1V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L17.65,6.35z"/>
+ android:pathData="M17.65,6.35c-1.63,-1.63 -3.94,-2.57 -6.48,-2.31 -3.67,0.37 -6.69,3.35 -7.1,7.02C3.52,15.91 7.27,20 12,20c3.19,0 5.93,-1.87 7.21,-4.56 0.32,-0.67 -0.16,-1.44 -0.9,-1.44 -0.37,0 -0.72,0.2 -0.88,0.53 -1.13,2.43 -3.84,3.97 -6.8,3.31 -2.22,-0.49 -4.01,-2.3 -4.48,-4.52C5.31,9.44 8.26,6 12,6c1.66,0 3.14,0.69 4.22,1.78l-1.51,1.51c-0.63,0.63 -0.19,1.71 0.7,1.71H19c0.55,0 1,-0.45 1,-1V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71l-0.64,0.65z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/remove.xml b/compose/material/material/icons/generator/raw-icons/rounded/remove.xml
index 6c00c74..a4437b7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/remove.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/remove.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,13H6c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1l0,0C19,12.55 18.55,13 18,13z"/>
+ android:pathData="M18,13H6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h12c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/remove_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/remove_circle.xml
index 3f1ee44..68d8599 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/remove_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/remove_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM16,13H8c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1l0,0C17,12.55 16.55,13 16,13z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM16,13L8,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/remove_circle_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/remove_circle_outline.xml
index 5691e36..dbd6450 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/remove_circle_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/remove_circle_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,12L7,12c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H8C7.45,11 7,11.45 7,12zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/>
+ android:pathData="M7,12c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L8,11c-0.55,0 -1,0.45 -1,1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/remove_from_queue.xml b/compose/material/material/icons/generator/raw-icons/rounded/remove_from_queue.xml
index 3e3a747..7ce659d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/remove_from_queue.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/remove_from_queue.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h4c1.1,0 2,-0.9 2,-2V5C22,3.89 21.1,3 20,3zM20,17H4V5h16V17zM16,11L16,11c0,0.55 -0.45,1 -1,1H9c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1h6C15.55,10 16,10.45 16,11z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h5c1.1,0 2,-0.9 2,-2L23,5c0,-1.11 -0.9,-2 -2,-2zM20,17L4,17c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1zM16,11c0,0.55 -0.45,1 -1,1L9,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/remove_red_eye.xml b/compose/material/material/icons/generator/raw-icons/rounded/remove_red_eye.xml
index 06decf9..a3e222a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/remove_red_eye.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/remove_red_eye.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4C7.31,4 3.26,6.74 1.35,10.7c-0.24,0.5 -0.24,1.1 0,1.6C3.26,16.26 7.31,19 12,19s8.74,-2.74 10.65,-6.7c0.24,-0.5 0.24,-1.1 0,-1.6C20.74,6.74 16.69,4 12,4zM12,16c-2.48,0 -4.5,-2.02 -4.5,-4.5S9.52,7 12,7s4.5,2.02 4.5,4.5S14.48,16 12,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,11.5m-2.7,0a2.7,2.7 0,1 1,5.4 0a2.7,2.7 0,1 1,-5.4 0"/>
+ android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/remove_shopping_cart.xml b/compose/material/material/icons/generator/raw-icons/rounded/remove_shopping_cart.xml
index fc7abaa..bd92646 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/remove_shopping_cart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/remove_shopping_cart.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,13c0.36,0 0.7,-0.2 0.87,-0.51l3.89,-7C21.13,4.82 20.65,4 19.89,4H6.83l9,9H16zM21.19,21.19L2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22l3.7,3.7l1.8,4.05l-1.07,2.13c-0.31,0.62 -0.28,1.35 0.09,1.95s1,0.95 1.7,0.95h6.55l1.51,1.51C15.27,18.87 15,19.4 15,20c0,1.1 0.9,2 2,2c0.6,0 1.13,-0.27 1.49,-0.68l1.29,1.29c0.39,0.39 1.02,0.39 1.41,0C21.58,22.22 21.58,21.58 21.19,21.19zM7.62,15l1,-2h1.55l2,2H7.62zM7,18c-1.1,0 -2,0.9 -2,2c0,1.1 0.9,2 2,2s2,-0.9 2,-2C9,18.9 8.1,18 7,18z"/>
+ android:pathData="M0.71,1.83c-0.39,0.39 -0.39,1.02 0,1.41l3.68,3.68 2.21,4.66 -1.35,2.45c-0.19,0.33 -0.28,0.73 -0.24,1.15 0.1,1.06 1.06,1.82 2.12,1.82h7.33l1.38,1.38c-0.5,0.36 -0.83,0.95 -0.83,1.62 0,1.1 0.89,2 1.99,2 0.67,0 1.26,-0.33 1.62,-0.84l2.13,2.13c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L2.12,1.83c-0.39,-0.39 -1.02,-0.39 -1.41,0zM7,15l1.1,-2h2.36l2,2L7,15zM16.05,12.94c0.54,-0.14 0.99,-0.49 1.25,-0.97l3.58,-6.49C21.25,4.82 20.76,4 20,4L7.12,4l8.93,8.94zM7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/reorder.xml b/compose/material/material/icons/generator/raw-icons/rounded/reorder.xml
index bd815f6..fe18307 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/reorder.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/reorder.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,15h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,15 4,15zM4,19h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,19 4,19zM4,11h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,11 4,11zM3,6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6z"/>
+ android:pathData="M4,15h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,19h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,11h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/repeat.xml b/compose/material/material/icons/generator/raw-icons/rounded/repeat.xml
index 68bccc8..a63feb7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/repeat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/repeat.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,7h10v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C17.54,2.54 17,2.76 17,3.21V5H6C5.45,5 5,5.45 5,6v4c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V7zM17,17H7v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C6.46,21.46 7,21.24 7,20.79V19h11c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1V17z"/>
+ android:pathData="M7,7h10v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L17,5L6,5c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1L7,7zM17,17L7,17v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.36L7,19h11c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/repeat_one.xml b/compose/material/material/icons/generator/raw-icons/rounded/repeat_one.xml
index c4b48e4..c62ab9f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/repeat_one.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/repeat_one.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,13c-0.55,0 -1,0.45 -1,1v3H7v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C6.46,21.46 7,21.24 7,20.79V19h11c0.55,0 1,-0.45 1,-1v-4C19,13.45 18.55,13 18,13zM20.64,5.64l-2.79,-2.79C17.54,2.54 17,2.76 17,3.21V5H6C5.45,5 5,5.45 5,6v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7h10v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79C20.84,6.15 20.84,5.84 20.64,5.64zM12.25,15c0.41,0 0.75,-0.34 0.75,-0.75v-4.5C13,9.34 12.66,9 12.25,9h-1.5C10.34,9 10,9.34 10,9.75s0.34,0.75 0.75,0.75h0.75v3.75C11.5,14.66 11.84,15 12.25,15z"/>
+ android:pathData="M7,7h10v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L17,5L6,5c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1L7,7zM17,17L7,17v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.36L7,19h11c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3zM13,14.25L13,9.81c0,-0.45 -0.36,-0.81 -0.81,-0.81 -0.13,0 -0.25,0.03 -0.36,0.09l-1.49,0.74c-0.21,0.1 -0.34,0.32 -0.34,0.55 0,0.34 0.28,0.62 0.62,0.62h0.88v3.25c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/replay.xml b/compose/material/material/icons/generator/raw-icons/rounded/replay.xml
index 40633d1..af52268 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/replay.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/replay.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.07,13c0.5,0 0.92,0.36 0.98,0.86c0.43,3.49 3.44,6.19 7.05,6.14c3.71,-0.05 6.84,-3.18 6.9,-6.9C19.06,9.2 15.89,6 12,6v1.79c0,0.45 -0.54,0.67 -0.85,0.35L8.35,5.35c-0.2,-0.2 -0.2,-0.51 0,-0.71l2.79,-2.79C11.46,1.54 12,1.76 12,2.21V4c5.06,0 9.14,4.17 9,9.25c-0.13,4.7 -4.04,8.61 -8.74,8.74c-4.7,0.13 -8.62,-3.35 -9.19,-7.87C3,13.53 3.47,13 4.07,13z"/>
+ android:pathData="M12,5V2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-3.8,3.79c-0.2,0.2 -0.2,0.51 0,0.71l3.79,3.79c0.32,0.31 0.86,0.09 0.86,-0.36V7c3.73,0 6.68,3.42 5.86,7.29 -0.47,2.27 -2.31,4.1 -4.57,4.57 -3.57,0.75 -6.75,-1.7 -7.23,-5.01 -0.07,-0.48 -0.49,-0.85 -0.98,-0.85 -0.6,0 -1.08,0.53 -1,1.13 0.62,4.39 4.8,7.64 9.53,6.72 3.12,-0.61 5.63,-3.12 6.24,-6.24C20.84,9.48 16.94,5 12,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/replay_10.xml b/compose/material/material/icons/generator/raw-icons/rounded/replay_10.xml
index 60548c2..c4e3831 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/replay_10.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/replay_10.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4V2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L8.35,4.65c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C11.46,8.46 12,8.24 12,7.79V6c3.89,0 7.06,3.2 7,7.1c-0.05,3.71 -3.18,6.84 -6.9,6.9c-3.62,0.05 -6.62,-2.65 -7.05,-6.14C4.99,13.36 4.57,13 4.07,13c-0.6,0 -1.07,0.53 -1,1.12c0.56,4.52 4.48,8 9.19,7.87c4.7,-0.13 8.61,-4.05 8.74,-8.74C21.14,8.17 17.06,4 12,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.75,16L9.75,16c0.41,0 0.75,-0.34 0.75,-0.75V11c0,-0.55 -0.45,-1 -1,-1H8.25c-0.41,0 -0.75,0.34 -0.75,0.75v0c0,0.41 0.34,0.75 0.75,0.75H9v3.75C9,15.66 9.34,16 9.75,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.5,16h2c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v4C11.5,15.55 11.95,16 12.5,16zM13,11.5h1v3h-1V11.5z"/>
+ android:pathData="M11.99,5L11.99,2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L7.35,5.65c-0.2,0.2 -0.2,0.51 0,0.71l3.79,3.79c0.31,0.31 0.85,0.09 0.85,-0.35L11.99,7c3.73,0 6.68,3.42 5.86,7.29 -0.47,2.27 -2.31,4.1 -4.57,4.57 -3.57,0.75 -6.75,-1.7 -7.23,-5.01 -0.06,-0.48 -0.48,-0.85 -0.98,-0.85 -0.6,0 -1.08,0.53 -1,1.13 0.62,4.39 4.8,7.64 9.53,6.72 3.12,-0.61 5.63,-3.12 6.24,-6.24 0.99,-5.13 -2.9,-9.61 -7.85,-9.61zM10.89,16h-0.85v-3.26l-1.01,0.31v-0.69l1.77,-0.63h0.09L10.89,16zM15.17,14.24c0,0.32 -0.03,0.6 -0.1,0.82s-0.17,0.42 -0.29,0.57 -0.28,0.26 -0.45,0.33 -0.37,0.1 -0.59,0.1 -0.41,-0.03 -0.59,-0.1 -0.33,-0.18 -0.46,-0.33 -0.23,-0.34 -0.3,-0.57 -0.11,-0.5 -0.11,-0.82v-0.74c0,-0.32 0.03,-0.6 0.1,-0.82s0.17,-0.42 0.29,-0.57 0.28,-0.26 0.45,-0.33 0.37,-0.1 0.59,-0.1 0.41,0.03 0.59,0.1 0.33,0.18 0.46,0.33 0.23,0.34 0.3,0.57 0.11,0.5 0.11,0.82v0.74zM14.32,13.38c0,-0.19 -0.01,-0.35 -0.04,-0.48s-0.07,-0.23 -0.12,-0.31 -0.11,-0.14 -0.19,-0.17 -0.16,-0.05 -0.25,-0.05 -0.18,0.02 -0.25,0.05 -0.14,0.09 -0.19,0.17 -0.09,0.18 -0.12,0.31 -0.04,0.29 -0.04,0.48v0.97c0,0.19 0.01,0.35 0.04,0.48s0.07,0.24 0.12,0.32 0.11,0.14 0.19,0.17 0.16,0.05 0.25,0.05 0.18,-0.02 0.25,-0.05 0.14,-0.09 0.19,-0.17 0.09,-0.19 0.11,-0.32 0.04,-0.29 0.04,-0.48v-0.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/replay_30.xml b/compose/material/material/icons/generator/raw-icons/rounded/replay_30.xml
index 98940aa..f25cfaf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/replay_30.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/replay_30.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4V2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L8.35,4.65c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C11.46,8.46 12,8.24 12,7.79V6c3.89,0 7.06,3.2 7,7.1c-0.05,3.71 -3.18,6.84 -6.9,6.9c-3.62,0.05 -6.62,-2.65 -7.05,-6.14C4.99,13.36 4.57,13 4.07,13c-0.6,0 -1.07,0.53 -1,1.12c0.56,4.52 4.48,8 9.19,7.87c4.7,-0.13 8.61,-4.05 8.74,-8.74C21.14,8.17 17.06,4 12,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,16c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1H15.5zM14,11.5h1v3h-1V11.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.5,15v-4c0,-0.55 -0.45,-1 -1,-1H8.25c-0.41,0 -0.75,0.34 -0.75,0.75v0c0,0.41 0.34,0.75 0.75,0.75H10v1H9c-0.28,0 -0.5,0.22 -0.5,0.5v0c0,0.28 0.22,0.5 0.5,0.5h1v1H8.25c-0.41,0 -0.75,0.34 -0.75,0.75v0C7.5,15.66 7.84,16 8.25,16h2.25C11.05,16 11.5,15.55 11.5,15z"/>
+ android:pathData="M12,5L12,2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-3.8,3.79c-0.2,0.2 -0.2,0.51 0,0.71l3.79,3.79c0.32,0.31 0.86,0.09 0.86,-0.36L12,7c3.73,0 6.68,3.42 5.86,7.29 -0.47,2.27 -2.31,4.1 -4.57,4.57 -3.57,0.75 -6.75,-1.7 -7.23,-5.01 -0.07,-0.48 -0.49,-0.85 -0.98,-0.85 -0.6,0 -1.08,0.53 -1,1.13 0.62,4.39 4.8,7.64 9.53,6.72 3.12,-0.61 5.63,-3.12 6.24,-6.24C20.84,9.48 16.94,5 12,5zM9.56,13.49h0.45c0.21,0 0.37,-0.05 0.48,-0.16s0.16,-0.25 0.16,-0.43c0,-0.08 -0.01,-0.15 -0.04,-0.22s-0.06,-0.12 -0.11,-0.17 -0.11,-0.09 -0.18,-0.11 -0.16,-0.04 -0.25,-0.04c-0.08,0 -0.15,0.01 -0.22,0.03s-0.13,0.05 -0.18,0.1 -0.09,0.09 -0.12,0.15 -0.05,0.13 -0.05,0.2h-0.85c0,-0.18 0.04,-0.34 0.11,-0.48s0.17,-0.27 0.3,-0.37 0.27,-0.18 0.44,-0.23 0.35,-0.08 0.54,-0.08c0.21,0 0.41,0.03 0.59,0.08s0.33,0.13 0.46,0.23 0.23,0.23 0.3,0.38 0.11,0.33 0.11,0.53c0,0.09 -0.01,0.18 -0.04,0.27s-0.07,0.17 -0.13,0.25 -0.12,0.15 -0.2,0.22 -0.17,0.12 -0.28,0.17c0.24,0.09 0.42,0.21 0.54,0.39s0.18,0.38 0.18,0.61c0,0.2 -0.04,0.38 -0.12,0.53s-0.18,0.29 -0.32,0.39 -0.29,0.19 -0.48,0.24 -0.38,0.08 -0.6,0.08c-0.18,0 -0.36,-0.02 -0.53,-0.07s-0.33,-0.12 -0.46,-0.23 -0.25,-0.23 -0.33,-0.38 -0.12,-0.34 -0.12,-0.55h0.85c0,0.08 0.02,0.15 0.05,0.22s0.07,0.12 0.13,0.17 0.12,0.09 0.2,0.11 0.16,0.04 0.25,0.04c0.1,0 0.19,-0.01 0.27,-0.04s0.15,-0.07 0.2,-0.12 0.1,-0.11 0.13,-0.18 0.04,-0.15 0.04,-0.24c0,-0.11 -0.02,-0.21 -0.05,-0.29s-0.08,-0.15 -0.14,-0.2 -0.13,-0.09 -0.22,-0.11 -0.18,-0.04 -0.29,-0.04h-0.47v-0.65zM15.3,14.24c0,0.32 -0.03,0.6 -0.1,0.82s-0.17,0.42 -0.29,0.57 -0.28,0.26 -0.45,0.33 -0.37,0.1 -0.59,0.1 -0.41,-0.03 -0.59,-0.1 -0.33,-0.18 -0.46,-0.33 -0.23,-0.34 -0.3,-0.57 -0.11,-0.5 -0.11,-0.82v-0.74c0,-0.32 0.03,-0.6 0.1,-0.82s0.17,-0.42 0.29,-0.57 0.28,-0.26 0.45,-0.33 0.37,-0.1 0.59,-0.1 0.41,0.03 0.59,0.1 0.33,0.18 0.46,0.33 0.23,0.34 0.3,0.57 0.11,0.5 0.11,0.82v0.74zM14.45,13.38c0,-0.19 -0.01,-0.35 -0.04,-0.48s-0.07,-0.23 -0.12,-0.31 -0.11,-0.14 -0.19,-0.17 -0.16,-0.05 -0.25,-0.05 -0.18,0.02 -0.25,0.05 -0.14,0.09 -0.19,0.17 -0.09,0.18 -0.12,0.31 -0.04,0.29 -0.04,0.48v0.97c0,0.19 0.01,0.35 0.04,0.48s0.07,0.24 0.12,0.32 0.11,0.14 0.19,0.17 0.16,0.05 0.25,0.05 0.18,-0.02 0.25,-0.05 0.14,-0.09 0.19,-0.17 0.09,-0.19 0.11,-0.32c0.03,-0.13 0.04,-0.29 0.04,-0.48v-0.97z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/replay_5.xml b/compose/material/material/icons/generator/raw-icons/rounded/replay_5.xml
index 6159858..6c5f16f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/replay_5.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/replay_5.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4V2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L8.35,4.65c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C11.46,8.46 12,8.24 12,7.79V6c3.89,0 7.06,3.2 7,7.1c-0.05,3.71 -3.18,6.84 -6.9,6.9c-3.62,0.05 -6.62,-2.65 -7.05,-6.14C4.99,13.37 4.57,13 4.07,13c-0.6,0 -1.07,0.53 -1,1.12c0.56,4.52 4.48,8 9.19,7.87c4.7,-0.13 8.61,-4.05 8.74,-8.74C21.14,8.17 17.06,4 12,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10.25,14.5c-0.41,0 -0.75,0.34 -0.75,0.75S9.84,16 10.25,16H13c0.55,0 1,-0.45 1,-1v-1.5c0,-0.55 -0.45,-1 -1,-1h-2v-1h2.25c0.41,0 0.75,-0.34 0.75,-0.75S13.66,10 13.25,10H10.5c-0.55,0 -1,0.45 -1,1v1.5c0,0.55 0.45,1 1,1h2v1H10.25z"/>
+ android:pathData="M12,5L12,2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-3.8,3.79c-0.2,0.2 -0.2,0.51 0,0.71l3.79,3.79c0.32,0.31 0.86,0.09 0.86,-0.36L12,7c3.73,0 6.68,3.42 5.86,7.29 -0.47,2.26 -2.14,3.99 -4.39,4.53 -3.64,0.88 -6.93,-1.6 -7.42,-4.96 -0.06,-0.49 -0.48,-0.86 -0.97,-0.86 -0.6,0 -1.08,0.53 -1,1.13 0.63,4.47 4.94,7.75 9.77,6.67 3.09,-0.69 5.39,-3.08 5.99,-6.19C20.84,9.48 16.94,5 12,5zM10.69,13.9l0.25,-2.17h2.39v0.71h-1.7l-0.11,0.92c0.03,-0.02 0.07,-0.03 0.11,-0.05s0.09,-0.04 0.15,-0.05 0.12,-0.03 0.18,-0.04 0.13,-0.02 0.2,-0.02c0.21,0 0.39,0.03 0.55,0.1s0.3,0.16 0.41,0.28 0.2,0.27 0.25,0.45 0.09,0.38 0.09,0.6c0,0.19 -0.03,0.37 -0.09,0.54s-0.15,0.32 -0.27,0.45 -0.27,0.24 -0.45,0.31 -0.39,0.12 -0.64,0.12c-0.18,0 -0.36,-0.03 -0.53,-0.08s-0.32,-0.14 -0.46,-0.24 -0.24,-0.24 -0.32,-0.39 -0.13,-0.33 -0.13,-0.53h0.84c0.02,0.18 0.08,0.32 0.19,0.41s0.25,0.15 0.42,0.15c0.11,0 0.2,-0.02 0.27,-0.06s0.14,-0.1 0.18,-0.17 0.08,-0.15 0.11,-0.25 0.03,-0.2 0.03,-0.31 -0.01,-0.21 -0.04,-0.31 -0.07,-0.17 -0.13,-0.24 -0.13,-0.12 -0.21,-0.15 -0.19,-0.05 -0.3,-0.05c-0.08,0 -0.15,0.01 -0.2,0.02s-0.11,0.03 -0.15,0.05 -0.08,0.05 -0.12,0.07 -0.07,0.06 -0.1,0.09l-0.67,-0.16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/reply.xml b/compose/material/material/icons/generator/raw-icons/rounded/reply.xml
index 6c59180..af74973 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/reply.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/reply.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,10H9V7.41c0,-0.89 -1.08,-1.34 -1.71,-0.71l-3.59,3.59c-0.39,0.39 -0.39,1.02 0,1.41l3.59,3.59C7.92,15.92 9,15.48 9,14.59V12h7c1.65,0 3,1.35 3,3v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-3C21,12.24 18.76,10 16,10z"/>
+ android:pathData="M10,9V7.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L3.7,11.29c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.63,0.63 1.71,0.19 1.71,-0.7V14.9c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/reply_all.xml b/compose/material/material/icons/generator/raw-icons/rounded/reply_all.xml
index e9e02bd..748aec9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/reply_all.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/reply_all.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,10h-5V7.41c0,-0.89 -1.08,-1.34 -1.71,-0.71l-3.59,3.59c-0.39,0.39 -0.39,1.02 0,1.41l3.59,3.59c0.63,0.63 1.71,0.18 1.71,-0.71V12h5c1.65,0 3,1.35 3,3v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-3C23,12.24 20.76,10 18,10zM8,7.4L8,7.4c0,-0.89 -1.08,-1.34 -1.71,-0.71l-3.59,3.59c-0.39,0.39 -0.39,1.02 0,1.41l3.59,3.59C6.92,15.91 8,15.46 8,14.57v0c0,-0.27 -0.11,-0.52 -0.29,-0.71l-2.88,-2.88l2.88,-2.88C7.89,7.92 8,7.67 8,7.4z"/>
+ android:pathData="M7,7.56c0,-0.94 -1.14,-1.42 -1.81,-0.75L0.71,11.29c-0.39,0.39 -0.39,1.02 0,1.41l4.48,4.48c0.67,0.68 1.81,0.2 1.81,-0.74 0,-0.28 -0.11,-0.55 -0.31,-0.75L3,12l3.69,-3.69c0.2,-0.2 0.31,-0.47 0.31,-0.75zM13,9V7.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L6.7,11.29c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.63,0.63 1.71,0.18 1.71,-0.71V14.9c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/report.xml b/compose/material/material/icons/generator/raw-icons/rounded/report.xml
index a5e1d31..6313627 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/report.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/report.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.9,3H9.1C8.57,3 8.06,3.21 7.68,3.59l-4.1,4.1C3.21,8.06 3,8.57 3,9.1v5.8c0,0.53 0.21,1.04 0.59,1.41l4.1,4.1C8.06,20.79 8.57,21 9.1,21h5.8c0.53,0 1.04,-0.21 1.41,-0.59l4.1,-4.1C20.79,15.94 21,15.43 21,14.9V9.1c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.1,-4.1C15.94,3.21 15.43,3 14.9,3zM12,13L12,13c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v4C13,12.55 12.55,13 12,13zM13,16c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1S13,15.45 13,16z"/>
+ android:pathData="M15.32,3L8.68,3c-0.26,0 -0.52,0.11 -0.7,0.29L3.29,7.98c-0.18,0.18 -0.29,0.44 -0.29,0.7v6.63c0,0.27 0.11,0.52 0.29,0.71l4.68,4.68c0.19,0.19 0.45,0.3 0.71,0.3h6.63c0.27,0 0.52,-0.11 0.71,-0.29l4.68,-4.68c0.19,-0.19 0.29,-0.44 0.29,-0.71L20.99,8.68c0,-0.27 -0.11,-0.52 -0.29,-0.71l-4.68,-4.68c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3s0.58,-1.3 1.3,-1.3 1.3,0.58 1.3,1.3 -0.58,1.3 -1.3,1.3zM12,13c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/report_gmailerrorred.xml b/compose/material/material/icons/generator/raw-icons/rounded/report_gmailerrorred.xml
index 0a7a23a..09e2f83 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/report_gmailerrorred.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/report_gmailerrorred.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.9,3H9.1C8.57,3 8.06,3.21 7.68,3.59l-4.1,4.1C3.21,8.06 3,8.57 3,9.1v5.8c0,0.53 0.21,1.04 0.59,1.41l4.1,4.1C8.06,20.79 8.57,21 9.1,21h5.8c0.53,0 1.04,-0.21 1.41,-0.59l4.1,-4.1C20.79,15.94 21,15.43 21,14.9V9.1c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.1,-4.1C15.94,3.21 15.43,3 14.9,3zM19,14.9L14.9,19H9.1L5,14.9V9.1L9.1,5h5.8L19,9.1V14.9z"/>
+ android:pathData="M20.71,7.98L16.03,3.3c-0.19,-0.19 -0.45,-0.3 -0.71,-0.3H8.68c-0.26,0 -0.52,0.11 -0.7,0.29L3.29,7.98c-0.18,0.18 -0.29,0.44 -0.29,0.7v6.63c0,0.27 0.11,0.52 0.29,0.71l4.68,4.68c0.19,0.19 0.45,0.3 0.71,0.3h6.63c0.27,0 0.52,-0.11 0.71,-0.29l4.68,-4.68c0.19,-0.19 0.29,-0.44 0.29,-0.71V8.68c0.01,-0.26 -0.1,-0.52 -0.28,-0.7zM19,14.9L14.9,19H9.1L5,14.9V9.1L9.1,5h5.8L19,9.1v5.8z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7L12,7c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V8C11,7.45 11.45,7 12,7z"/>
+ android:pathData="M12,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,17L12,17c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,16.55 12.55,17 12,17z"/>
+ android:pathData="M12,7c-0.55,0 -1,0.45 -1,1v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/report_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/report_off.xml
index 1286d42..0784e76 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/report_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/report_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2.17l6.78,6.78l0.64,-0.64C20.79,15.94 21,15.43 21,14.9V9.1c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.1,-4.1C15.94,3.21 15.43,3 14.9,3H9.1C8.57,3 8.06,3.21 7.68,3.59L7.05,4.22L11,8.17V8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.19,21.19L2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22l2.83,2.83L3.59,7.68C3.21,8.06 3,8.57 3,9.1v5.8c0,0.53 0.21,1.04 0.59,1.41l4.1,4.1C8.06,20.79 8.57,21 9.1,21h5.8c0.53,0 1.04,-0.21 1.41,-0.59l0.64,-0.63l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0C21.58,22.22 21.58,21.58 21.19,21.19zM13,16c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1s0.45,-1 1,-1c0.08,0 0.14,0.03 0.21,0.04l0.74,0.74C12.97,15.86 13,15.92 13,16z"/>
+ android:pathData="M12,7c0.55,0 1,0.45 1,1v1.33l7.2,7.2 0.51,-0.51c0.19,-0.19 0.29,-0.44 0.29,-0.71V8.68c0,-0.27 -0.11,-0.52 -0.29,-0.71l-4.68,-4.68c-0.19,-0.18 -0.45,-0.29 -0.71,-0.29H8.68c-0.26,0 -0.52,0.11 -0.7,0.29l-0.51,0.51 3.69,3.69c0.17,-0.29 0.48,-0.49 0.84,-0.49zM2.41,1.58L1,2.99l3.64,3.64 -1.35,1.35c-0.18,0.18 -0.29,0.44 -0.29,0.7v6.63c0,0.27 0.11,0.52 0.29,0.71l4.68,4.68c0.19,0.19 0.45,0.3 0.71,0.3h6.63c0.27,0 0.52,-0.11 0.71,-0.29l1.35,-1.35L21.01,23l1.41,-1.41L2.41,1.58zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3s1.3,0.58 1.3,1.3c0,0.72 -0.58,1.3 -1.3,1.3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/report_problem.xml b/compose/material/material/icons/generator/raw-icons/rounded/report_problem.xml
index 29a1243..1f939aa 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/report_problem.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/report_problem.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2.73,21h18.53c0.77,0 1.25,-0.83 0.87,-1.5l-9.27,-16c-0.39,-0.67 -1.35,-0.67 -1.73,0l-9.27,16C1.48,20.17 1.96,21 2.73,21zM12,15c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3C13,14.55 12.55,15 12,15zM13,17c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1s0.45,-1 1,-1S13,16.45 13,17z"/>
+ android:pathData="M2.73,21h18.53c0.77,0 1.25,-0.83 0.87,-1.5l-9.27,-16c-0.39,-0.67 -1.35,-0.67 -1.73,0l-9.27,16c-0.38,0.67 0.1,1.5 0.87,1.5zM13,18h-2v-2h2v2zM12,14c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/restaurant.xml b/compose/material/material/icons/generator/raw-icons/rounded/restaurant.xml
index a6c8452..3af52d0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/restaurant.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/restaurant.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,7v5c0,1.1 0.9,2 2,2h1v7c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-7V2C16.24,2 14,4.24 14,7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,9H9V3c0,-0.55 -0.45,-1 -1,-1h0C7.45,2 7,2.45 7,3v6H6V3c0,-0.55 -0.45,-1 -1,-1h0C4.45,2 4,2.45 4,3v6c0,1.86 1.28,3.41 3,3.86V21c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-8.14c1.72,-0.45 3,-2 3,-3.86V3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1V9z"/>
+ android:pathData="M16,6v6c0,1.1 0.9,2 2,2h1v7c0,0.55 0.45,1 1,1s1,-0.45 1,-1L21,3.13c0,-0.65 -0.61,-1.13 -1.24,-0.98C17.6,2.68 16,4.51 16,6zM11,9L9,9L9,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6L5,9L5,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6c0,2.21 1.79,4 4,4v8c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-8c2.21,0 4,-1.79 4,-4L13,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/restaurant_menu.xml b/compose/material/material/icons/generator/raw-icons/rounded/restaurant_menu.xml
index 96e0a63..a056d74 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/restaurant_menu.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/restaurant_menu.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.41,12l1.26,-1.26c1.4,0.6 3.32,0.14 4.75,-1.3c1.75,-1.75 2.09,-4.27 0.74,-5.62c-1.34,-1.34 -3.85,-1.01 -5.62,0.74c-1.43,1.43 -1.9,3.36 -1.29,4.76l-9.55,9.55c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,13.41l6.88,6.88c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7.34,12.42l3.21,-3.21l-5.4,-5.4C4.67,3.34 3.87,3.45 3.55,4.04C2.61,5.76 2.87,7.96 4.33,9.41L7.34,12.42z"/>
+ android:pathData="M8.1,13.34l2.83,-2.83 -6.19,-6.18c-0.48,-0.48 -1.31,-0.35 -1.61,0.27 -0.71,1.49 -0.45,3.32 0.78,4.56l4.19,4.18zM14.88,11.53c1.53,0.71 3.68,0.21 5.27,-1.38 1.91,-1.91 2.28,-4.65 0.81,-6.12 -1.46,-1.46 -4.2,-1.1 -6.12,0.81 -1.59,1.59 -2.09,3.74 -1.38,5.27L4.4,19.17c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,14.41l6.18,6.18c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,13l1.47,-1.47z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/restore.xml b/compose/material/material/icons/generator/raw-icons/rounded/restore.xml
index 0896387..b3abbac 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/restore.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/restore.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8v4c0,0.27 0.11,0.52 0.29,0.71l2.79,2.79c0.39,0.39 1.02,0.39 1.41,0v0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.5,-2.5V8c0,-0.55 -0.45,-1 -1,-1h0C12.45,7 12,7.45 12,8zM13.26,3C8.17,2.86 4,6.94 4,12H2.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.8,-2.79C8.46,12.54 8.24,12 7.79,12H6c0,-3.89 3.2,-7.06 7.1,-7c3.71,0.05 6.84,3.18 6.9,6.9c0.06,3.91 -3.1,7.1 -7,7.1c-1.59,0 -3.05,-0.53 -4.23,-1.43c-0.4,-0.3 -0.96,-0.27 -1.31,0.09l0,0c-0.43,0.43 -0.39,1.14 0.09,1.5C9.06,20.31 10.95,21 13,21c5.06,0 9.14,-4.17 9,-9.25C21.87,7.05 17.95,3.13 13.26,3z"/>
+ android:pathData="M13.25,3c-5.09,-0.14 -9.26,3.94 -9.26,9L2.2,12c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.8c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.8c0.32,-0.31 0.09,-0.85 -0.35,-0.85h-1.8c0,-3.9 3.18,-7.05 7.1,-7 3.72,0.05 6.85,3.18 6.9,6.9 0.05,3.91 -3.1,7.1 -7,7.1 -1.61,0 -3.1,-0.55 -4.28,-1.48 -0.4,-0.31 -0.96,-0.28 -1.32,0.08 -0.42,0.43 -0.39,1.13 0.08,1.5 1.52,1.19 3.44,1.9 5.52,1.9 5.05,0 9.14,-4.17 9,-9.26 -0.13,-4.69 -4.05,-8.61 -8.74,-8.74zM12.74,8c-0.41,0 -0.75,0.34 -0.75,0.75v3.68c0,0.35 0.19,0.68 0.49,0.86l3.12,1.85c0.36,0.21 0.82,0.09 1.03,-0.26 0.21,-0.36 0.09,-0.82 -0.26,-1.03l-2.88,-1.71v-3.4c0,-0.4 -0.33,-0.74 -0.75,-0.74z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/restore_from_trash.xml b/compose/material/material/icons/generator/raw-icons/rounded/restore_from_trash.xml
index 372d8b1..52f2520 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/restore_from_trash.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/restore_from_trash.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6V19zM11.65,10.35c0.2,-0.2 0.51,-0.2 0.71,0l2.79,2.8C15.46,13.46 15.24,14 14.8,14H13v3c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-3H9.21c-0.45,0 -0.67,-0.54 -0.35,-0.85L11.65,10.35zM15.5,4l-0.71,-0.71C14.61,3.11 14.35,3 14.09,3H9.91C9.65,3 9.39,3.11 9.21,3.29L8.5,4H6C5.45,4 5,4.45 5,5s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H15.5z"/>
+ android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,9c0,-1.1 -0.9,-2 -2,-2L8,7c-1.1,0 -2,0.9 -2,2v10zM11.65,10.35c0.2,-0.2 0.51,-0.2 0.71,0L16,14h-2v4h-4v-4L8,14l3.65,-3.65zM15.5,4l-0.71,-0.71c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29L9.91,3c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4L6,4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/restore_page.xml b/compose/material/material/icons/generator/raw-icons/rounded/restore_page.xml
index d458d5a..8a74fe0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/restore_page.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/restore_page.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.41,7.41l-4.83,-4.83C14.21,2.21 13.7,2 13.17,2H6C4.9,2 4.01,2.9 4.01,4L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8.83C20,8.3 19.79,7.79 19.41,7.41zM12,18c-1.65,0 -3.19,-0.81 -4.12,-2.17c-0.23,-0.34 -0.15,-0.81 0.19,-1.04c0.34,-0.24 0.81,-0.15 1.04,0.19c0.65,0.95 1.73,1.52 2.88,1.52c1.93,0 3.5,-1.57 3.5,-3.5S13.93,9.5 12,9.5c-1.33,0 -2.52,0.74 -3.11,1.89L10.5,13H7c-0.28,0 -0.5,-0.22 -0.5,-0.5V9l1.3,1.3C8.71,8.89 10.26,8 12,8c2.76,0 5,2.24 5,5S14.76,18 12,18z"/>
+ android:pathData="M19.41,7.41l-4.83,-4.83c-0.37,-0.37 -0.88,-0.58 -1.41,-0.58H6c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8.83c0,-0.53 -0.21,-1.04 -0.59,-1.42zM12,18c-1.65,0 -3.19,-0.81 -4.12,-2.17 -0.23,-0.34 -0.15,-0.81 0.19,-1.04 0.34,-0.24 0.81,-0.15 1.04,0.19 0.65,0.95 1.73,1.52 2.88,1.52 1.93,0 3.5,-1.57 3.5,-3.5S13.93,9.5 12,9.5c-1.33,0 -2.52,0.74 -3.11,1.89L10.5,13H7c-0.28,0 -0.5,-0.22 -0.5,-0.5V9l1.3,1.3C8.71,8.89 10.26,8 12,8c2.76,0 5,2.24 5,5s-2.24,5 -5,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/ring_volume.xml b/compose/material/material/icons/generator/raw-icons/rounded/ring_volume.xml
index e61fca6..12101df 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/ring_volume.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/ring_volume.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.02,2h-0.04C11.44,2 11,2.44 11,2.98v3.04C11,6.56 11.44,7 11.98,7h0.04C12.56,7 13,6.56 13,6.02V2.98C13,2.44 12.56,2 12.02,2zM20.45,5.55L20.45,5.55c-0.39,-0.39 -1.01,-0.39 -1.39,-0.01l-2.17,2.17c-0.38,0.38 -0.38,1 0,1.39l0.02,0.02c0.38,0.38 1.01,0.38 1.39,0c0.62,-0.63 1.53,-1.55 2.16,-2.17C20.83,6.55 20.83,5.93 20.45,5.55zM7.1,9.11l0.02,-0.02c0.38,-0.38 0.38,-1 0,-1.38L4.95,5.53c-0.38,-0.38 -1,-0.38 -1.39,0L3.55,5.55c-0.38,0.38 -0.39,1 0,1.39c0.63,0.62 1.54,1.54 2.16,2.17C6.09,9.5 6.71,9.5 7.1,9.11zM22.91,16.71C18.58,12.1 13.09,12 12,12s-6.58,0.1 -10.91,4.71c-0.38,0.4 -0.38,1.02 0.01,1.41l2.29,2.27c0.35,0.35 0.91,0.39 1.3,0.09L7.6,18.3C7.85,18.11 8,17.81 8,17.5v-2.87C9.26,14.23 10.6,14 12,14s2.74,0.23 4,0.63v2.87c0,0.31 0.15,0.61 0.4,0.8l2.91,2.18c0.4,0.3 0.95,0.26 1.3,-0.09l2.29,-2.27C23.29,17.73 23.29,17.11 22.91,16.71z"/>
+ android:pathData="M11.98,7h0.03c0.55,0 0.99,-0.44 0.99,-0.98L13,2.98c0,-0.54 -0.44,-0.98 -0.98,-0.98h-0.03c-0.55,0 -0.99,0.44 -0.99,0.98v3.03c0,0.55 0.44,0.99 0.98,0.99zM16.9,9.11c0.39,0.39 1.01,0.39 1.4,0 0.62,-0.63 1.52,-1.54 2.15,-2.17 0.39,-0.38 0.39,-1.01 0,-1.39 -0.38,-0.38 -1.01,-0.38 -1.39,0L16.89,7.7c-0.39,0.38 -0.39,1.01 0,1.39l0.01,0.02zM5.71,9.1c0.38,0.39 1.01,0.39 1.4,0 0.38,-0.38 0.38,-1.01 0,-1.39L4.96,5.54c-0.38,-0.39 -1.01,-0.39 -1.39,0l-0.02,0.01c-0.39,0.39 -0.39,1.01 0,1.39 0.63,0.62 1.54,1.53 2.16,2.16zM23.29,16.23c-6.41,-5.66 -16.07,-5.66 -22.48,0 -0.85,0.75 -0.85,2.08 -0.05,2.88l1.22,1.22c0.72,0.72 1.86,0.78 2.66,0.15l2,-1.59c0.48,-0.38 0.76,-0.96 0.76,-1.57v-2.6c3.02,-0.98 6.29,-0.99 9.32,0v2.61c0,0.61 0.28,1.19 0.76,1.57l1.99,1.58c0.8,0.63 1.94,0.57 2.66,-0.15l1.22,-1.22c0.79,-0.8 0.79,-2.13 -0.06,-2.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/room_service.xml b/compose/material/material/icons/generator/raw-icons/rounded/room_service.xml
index 1a050ee..8f1d63e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/room_service.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/room_service.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,18L22,18c0,0.55 -0.45,1 -1,1H3c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h18C21.55,17 22,17.45 22,18zM21,16H3v-1c0,-4.28 2.99,-7.86 7,-8.77V6c0,-1.1 0.9,-2 2,-2s2,0.9 2,2v0.23c4.01,0.91 7,4.49 7,8.77V16z"/>
+ android:pathData="M3,17h18c0.55,0 1,0.45 1,1s-0.45,1 -1,1L3,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM13.84,7.79c0.1,-0.24 0.16,-0.51 0.16,-0.79 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2c0,0.28 0.06,0.55 0.16,0.79C6.25,8.6 3.27,11.93 3,16h18c-0.27,-4.07 -3.25,-7.4 -7.16,-8.21z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rotate_90_degrees_ccw.xml b/compose/material/material/icons/generator/raw-icons/rounded/rotate_90_degrees_ccw.xml
index 8762cb1..6cc62e1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rotate_90_degrees_ccw.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rotate_90_degrees_ccw.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.34,7.79C18.52,5.26 15.76,4.01 13,4.01V2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L9.35,4.65c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C12.46,8.46 13,8.24 13,7.79V6.03c2.2,0 4.4,1 5.81,3.07c1.6,2.36 1.63,5.36 0.05,7.73c-1.99,2.99 -5.62,3.86 -8.58,2.62c-0.38,-0.16 -0.81,-0.1 -1.1,0.19l-0.05,0.05c-0.47,0.47 -0.34,1.29 0.27,1.56c3.63,1.58 8.09,0.66 10.74,-2.79C22.54,15.37 22.62,10.96 20.34,7.79z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1.71,12.29c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L7.71,7.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L1.71,12.29z"/>
+ android:pathData="M5.93,7.83l-3.65,3.66c-0.78,0.78 -0.78,2.05 0,2.83l3.66,3.66c0.78,0.78 2.05,0.78 2.83,0l3.66,-3.65c0.78,-0.78 0.78,-2.05 0,-2.83L8.76,7.82c-0.79,-0.78 -2.05,-0.78 -2.83,0.01zM4.4,12.19l2.25,-2.25c0.39,-0.39 1.02,-0.39 1.42,0l2.24,2.24c0.39,0.39 0.39,1.02 0,1.41l-2.25,2.25c-0.39,0.39 -1.02,0.39 -1.42,0L4.4,13.61c-0.39,-0.39 -0.39,-1.03 0,-1.42zM19.36,6.64C17.61,4.88 15.3,4 13,4v-0.83c0,-0.89 -1.08,-1.34 -1.71,-0.71L9.47,4.29c-0.39,0.39 -0.39,1.02 0,1.41l1.83,1.83c0.62,0.63 1.7,0.19 1.7,-0.7L13,6c2.02,0 4.03,0.86 5.45,2.61 2.05,2.52 2.05,6.27 0,8.79C17.03,19.14 15.02,20 13,20c-0.78,0 -1.55,-0.13 -2.29,-0.39 -0.36,-0.12 -0.75,-0.01 -1.02,0.26 -0.5,0.5 -0.34,1.39 0.34,1.62 0.96,0.34 1.96,0.51 2.97,0.51 2.3,0 4.61,-0.88 6.36,-2.64 3.52,-3.51 3.52,-9.21 0,-12.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rotate_left.xml b/compose/material/material/icons/generator/raw-icons/rounded/rotate_left.xml
index ecd2242..47016ec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rotate_left.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rotate_left.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.83,8.3L5.83,8.3C5.36,7.83 4.59,7.91 4.26,8.46C3.83,9.19 3.5,9.98 3.28,10.82c-0.16,0.63 0.33,1.23 0.98,1.23h0.01c0.45,0 0.85,-0.3 0.96,-0.73c0.17,-0.64 0.42,-1.26 0.76,-1.82C6.21,9.11 6.15,8.62 5.83,8.3zM7.42,20.8c0.72,0.43 1.51,0.76 2.35,0.98C10.39,21.94 11,21.44 11,20.8v-0.01c0,-0.45 -0.3,-0.85 -0.73,-0.96c-0.65,-0.17 -1.26,-0.42 -1.82,-0.76c-0.39,-0.23 -0.88,-0.16 -1.2,0.16l-0.01,0.01C6.79,19.69 6.86,20.47 7.42,20.8zM4.27,14.06L4.27,14.06c-0.65,0 -1.14,0.61 -0.98,1.23c0.21,0.84 0.55,1.63 0.98,2.35c0.33,0.55 1.1,0.63 1.56,0.18l0.01,-0.01c0.32,-0.32 0.39,-0.81 0.16,-1.2c-0.33,-0.56 -0.59,-1.17 -0.76,-1.82C5.11,14.36 4.72,14.06 4.27,14.06zM19.33,7.78C17.51,5.25 14.76,4.01 12,4.01V2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L8.35,4.65c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C11.46,8.46 12,8.24 12,7.79V6.03c2.19,0 4.39,0.99 5.8,3.05c1.63,2.38 1.59,5.63 -0.09,7.98c-1.03,1.44 -2.45,2.33 -3.98,2.72C13.3,19.87 13,20.28 13,20.72v0c0,0.64 0.6,1.14 1.23,0.98c1.93,-0.48 3.72,-1.61 5.05,-3.41C21.55,15.21 21.58,10.89 19.33,7.78z"/>
+ android:pathData="M6.56,7.98C6.1,7.52 5.31,7.6 5,8.17c-0.28,0.51 -0.5,1.03 -0.67,1.58 -0.19,0.63 0.31,1.25 0.96,1.25h0.01c0.43,0 0.82,-0.28 0.94,-0.7 0.12,-0.4 0.28,-0.79 0.48,-1.17 0.22,-0.37 0.15,-0.84 -0.16,-1.15zM5.31,13h-0.02c-0.65,0 -1.15,0.62 -0.96,1.25 0.16,0.54 0.38,1.07 0.66,1.58 0.31,0.57 1.11,0.66 1.57,0.2 0.3,-0.31 0.38,-0.77 0.17,-1.15 -0.2,-0.37 -0.36,-0.76 -0.48,-1.16 -0.12,-0.44 -0.51,-0.72 -0.94,-0.72zM8.16,19.02c0.51,0.28 1.04,0.5 1.59,0.66 0.62,0.18 1.24,-0.32 1.24,-0.96v-0.03c0,-0.43 -0.28,-0.82 -0.7,-0.94 -0.4,-0.12 -0.78,-0.28 -1.15,-0.48 -0.38,-0.21 -0.86,-0.14 -1.16,0.17l-0.03,0.03c-0.45,0.45 -0.36,1.24 0.21,1.55zM13,4.07v-0.66c0,-0.89 -1.08,-1.34 -1.71,-0.71L9.17,4.83c-0.4,0.4 -0.4,1.04 0,1.43l2.13,2.08c0.63,0.62 1.7,0.17 1.7,-0.72L13,6.09c2.84,0.48 5,2.94 5,5.91 0,2.73 -1.82,5.02 -4.32,5.75 -0.41,0.12 -0.68,0.51 -0.68,0.94v0.02c0,0.65 0.61,1.14 1.23,0.96C17.57,18.71 20,15.64 20,12c0,-4.08 -3.05,-7.44 -7,-7.93z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rotate_right.xml b/compose/material/material/icons/generator/raw-icons/rounded/rotate_right.xml
index 3c87d67..00ac5be8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rotate_right.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rotate_right.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.02,9.5c0.33,0.56 0.59,1.18 0.76,1.82c0.11,0.43 0.51,0.73 0.96,0.73h0.01c0.65,0 1.14,-0.61 0.98,-1.23c-0.21,-0.84 -0.54,-1.63 -0.98,-2.35c-0.33,-0.55 -1.11,-0.63 -1.56,-0.18L18.17,8.3C17.85,8.62 17.79,9.11 18.02,9.5zM16.76,19.24L16.76,19.24c-0.32,-0.32 -0.82,-0.39 -1.21,-0.16c-0.56,0.33 -1.17,0.59 -1.82,0.76C13.3,19.95 13,20.34 13,20.79v0.01c0,0.65 0.61,1.14 1.23,0.98c0.84,-0.21 1.63,-0.55 2.35,-0.98C17.14,20.47 17.22,19.69 16.76,19.24zM18.77,14.79c-0.17,0.65 -0.42,1.26 -0.76,1.82c-0.23,0.39 -0.16,0.88 0.16,1.2l0.01,0.01c0.46,0.46 1.23,0.38 1.56,-0.18c0.43,-0.72 0.76,-1.51 0.98,-2.35c0.16,-0.63 -0.33,-1.23 -0.98,-1.23h-0.01C19.28,14.06 18.89,14.36 18.77,14.79zM4.73,18.3c1.32,1.79 3.12,2.92 5.05,3.41C10.4,21.87 11,21.37 11,20.73v0c0,-0.45 -0.3,-0.85 -0.73,-0.96c-1.53,-0.38 -2.95,-1.27 -3.98,-2.72c-1.68,-2.35 -1.72,-5.6 -0.09,-7.98c1.41,-2.06 3.6,-3.05 5.8,-3.05v1.77c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79C12.54,1.54 12,1.76 12,2.21v1.81c-2.76,0 -5.51,1.24 -7.33,3.76C2.42,10.89 2.45,15.21 4.73,18.3z"/>
+ android:pathData="M14.83,4.83L12.7,2.7c-0.62,-0.62 -1.7,-0.18 -1.7,0.71v0.66C7.06,4.56 4,7.92 4,12c0,3.64 2.43,6.71 5.77,7.68 0.62,0.18 1.23,-0.32 1.23,-0.96v-0.03c0,-0.43 -0.27,-0.82 -0.68,-0.94C7.82,17.03 6,14.73 6,12c0,-2.97 2.16,-5.43 5,-5.91v1.53c0,0.89 1.07,1.33 1.7,0.71l2.13,-2.08c0.4,-0.38 0.4,-1.02 0,-1.42zM19.67,9.76c-0.16,-0.55 -0.38,-1.08 -0.66,-1.59 -0.31,-0.57 -1.1,-0.66 -1.56,-0.2l-0.01,0.01c-0.31,0.31 -0.38,0.78 -0.17,1.16 0.2,0.37 0.36,0.76 0.48,1.16 0.12,0.42 0.51,0.7 0.94,0.7h0.02c0.65,0 1.15,-0.62 0.96,-1.24zM13,18.68v0.02c0,0.65 0.62,1.14 1.24,0.96 0.55,-0.16 1.08,-0.38 1.59,-0.66 0.57,-0.31 0.66,-1.1 0.2,-1.56l-0.02,-0.02c-0.31,-0.31 -0.78,-0.38 -1.16,-0.17 -0.37,0.21 -0.76,0.37 -1.16,0.49 -0.41,0.12 -0.69,0.51 -0.69,0.94zM17.44,16.03c0.46,0.46 1.25,0.37 1.56,-0.2 0.28,-0.51 0.5,-1.04 0.67,-1.59 0.18,-0.62 -0.31,-1.24 -0.96,-1.24h-0.02c-0.44,0 -0.82,0.28 -0.94,0.7 -0.12,0.4 -0.28,0.79 -0.48,1.17 -0.21,0.38 -0.13,0.86 0.17,1.16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rounded_corner.xml b/compose/material/material/icons/generator/raw-icons/rounded/rounded_corner.xml
index a29f14a..afb1b77 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rounded_corner.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rounded_corner.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,19h2v2h-2V19zM19,17h2v-2h-2V17zM3,13h2v-2H3V13zM3,17h2v-2H3V17zM3,9h2V7H3V9zM3,5h2V3H3V5zM7,5h2V3H7V5zM15,21h2v-2h-2V21zM11,21h2v-2h-2V21zM15,21h2v-2h-2V21zM7,21h2v-2H7V21zM3,21h2v-2H3V21zM21,8c0,-2.76 -2.24,-5 -5,-5h-5v2h5c1.65,0 3,1.35 3,3v5h2V8z"/>
+ android:pathData="M19,19h2v2h-2v-2zM19,17h2v-2h-2v2zM3,13h2v-2L3,11v2zM3,17h2v-2L3,15v2zM3,9h2L5,7L3,7v2zM3,5h2L5,3L3,3v2zM7,5h2L9,3L7,3v2zM15,21h2v-2h-2v2zM11,21h2v-2h-2v2zM15,21h2v-2h-2v2zM7,21h2v-2L7,19v2zM3,21h2v-2L3,19v2zM21,8c0,-2.76 -2.24,-5 -5,-5h-5v2h5c1.65,0 3,1.35 3,3v5h2L21,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/router.xml b/compose/material/material/icons/generator/raw-icons/rounded/router.xml
index fa24ecc..75e482b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/router.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/router.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,13h-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4C21,13.9 20.1,13 19,13zM7,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S7.55,18 7,18zM10.5,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S11.05,18 10.5,18zM14,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S14.55,18 14,18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.12,5.12c0.35,0.35 0.89,0.38 1.28,0.09C13.4,4.45 14.65,4 16,4s2.6,0.45 3.6,1.2c0.39,0.3 0.93,0.26 1.28,-0.09L20.9,5.1c0.42,-0.42 0.38,-1.12 -0.09,-1.48C19.48,2.6 17.81,2 16,2s-3.48,0.6 -4.82,1.62c-0.47,0.36 -0.51,1.06 -0.09,1.48L11.12,5.12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,5.5c-0.79,0 -1.53,0.2 -2.17,0.56c-0.57,0.32 -0.67,1.1 -0.21,1.56l0.02,0.02c0.32,0.32 0.81,0.35 1.21,0.14C15.19,7.6 15.59,7.5 16,7.5s0.81,0.1 1.15,0.28c0.4,0.21 0.89,0.18 1.21,-0.14l0.02,-0.02c0.46,-0.46 0.36,-1.24 -0.21,-1.56C17.53,5.7 16.79,5.5 16,5.5z"/>
+ android:pathData="M11.45,5.55c0.19,0.19 0.5,0.21 0.72,0.04C13.3,4.69 14.65,4.2 16,4.2s2.7,0.49 3.84,1.39c0.21,0.17 0.52,0.15 0.72,-0.04l0.04,-0.05c0.22,-0.22 0.21,-0.59 -0.03,-0.8C19.24,3.57 17.62,3 16,3s-3.24,0.57 -4.57,1.7c-0.24,0.21 -0.26,0.57 -0.03,0.8l0.05,0.05zM13.15,6.31c-0.25,0.2 -0.26,0.58 -0.04,0.8l0.04,0.04c0.2,0.2 0.5,0.2 0.72,0.04 0.63,-0.48 1.38,-0.69 2.13,-0.69s1.5,0.21 2.13,0.68c0.22,0.17 0.53,0.16 0.72,-0.04l0.04,-0.04c0.23,-0.23 0.21,-0.6 -0.04,-0.8 -0.83,-0.64 -1.84,-1 -2.85,-1s-2.02,0.36 -2.85,1.01zM19,13h-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3L5,13c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2zM8,18L6,18v-2h2v2zM11.5,18h-2v-2h2v2zM15,18h-2v-2h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rowing.xml b/compose/material/material/icons/generator/raw-icons/rounded/rowing.xml
index ba0de7e..7fa2cd9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rowing.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rowing.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.75,18.25c-0.41,0.41 -0.41,1.09 0,1.5s1.09,0.41 1.5,0L9,17h2l-2.5,-2.5L4.75,18.25zM15,5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S13.9,5 15,5zM20.29,20.3l-2,-2.01C18.11,18.11 17.85,18 17.58,18H16.5l-6.29,-6.29c0.79,-0.33 1.66,-0.87 2.29,-1.39v2.27l3.58,3.58c0.57,-0.55 0.92,-1.32 0.92,-2.16V8.26C17,7.02 15.98,6 14.74,6h-0.02c-0.34,0 -0.67,0.09 -0.96,0.23c-0.26,0.12 -0.5,0.29 -0.69,0.5l-1.4,1.55C10.61,9.45 8.66,10.35 7,10.32c-0.6,0 -1.08,0.48 -1.08,1.08S6.4,12.48 7,12.48c0.31,0 0.61,-0.03 0.9,-0.07l7.11,7.09v1.08c0,0.26 0.1,0.52 0.29,0.7l1.99,2.01c0.39,0.39 1.02,0.39 1.42,0l1.58,-1.58C20.68,21.33 20.68,20.69 20.29,20.3z"/>
+ android:pathData="M4.75,18.25c-0.41,0.41 -0.41,1.09 0,1.5 0.41,0.41 1.09,0.41 1.5,0L9,17h2l-2.5,-2.5 -3.75,3.75zM15,5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM20.29,20.3l-2,-2.01c-0.18,-0.18 -0.44,-0.29 -0.71,-0.29L16.5,18l-6.29,-6.29c0.79,-0.33 1.66,-0.87 2.29,-1.39v2.27l3.58,3.58c0.57,-0.55 0.92,-1.32 0.92,-2.16L17,8.26C17,7.02 15.98,6 14.74,6h-0.02c-0.34,0 -0.67,0.09 -0.96,0.23 -0.26,0.12 -0.5,0.29 -0.69,0.5l-1.4,1.55C10.61,9.45 8.66,10.35 7,10.32c-0.6,0 -1.08,0.48 -1.08,1.08 0,0.6 0.48,1.08 1.08,1.08 0.31,0 0.61,-0.03 0.9,-0.07l7.11,7.09v1.08c0,0.26 0.1,0.52 0.29,0.7l1.99,2.01c0.39,0.39 1.02,0.39 1.42,0l1.58,-1.58c0.39,-0.38 0.39,-1.02 0,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rss_feed.xml b/compose/material/material/icons/generator/raw-icons/rounded/rss_feed.xml
index 61dc797..32e43d8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rss_feed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rss_feed.xml
@@ -6,11 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,19m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M6.18,17.82m-2.18,0a2.18,2.18 0,1 1,4.36 0a2.18,2.18 0,1 1,-4.36 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M4.35,7.06c6.64,0.64 11.95,5.94 12.58,12.58c0.07,0.77 0.72,1.35 1.49,1.35h0c0.88,0 1.59,-0.76 1.5,-1.63c-0.77,-8.09 -7.2,-14.52 -15.29,-15.29C3.76,3.99 3,4.7 3,5.58v0C3,6.35 3.58,6.99 4.35,7.06z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,11.62c0,0.75 0.56,1.36 1.3,1.48c3.37,0.55 6.04,3.22 6.6,6.59c0.12,0.74 0.73,1.3 1.48,1.3h0c0.93,0 1.63,-0.84 1.48,-1.75c-0.75,-4.67 -4.44,-8.36 -9.11,-9.11C3.84,9.99 3,10.69 3,11.62L3,11.62z"/>
+ android:pathData="M5.59,10.23c-0.84,-0.14 -1.59,0.55 -1.59,1.4 0,0.71 0.53,1.28 1.23,1.4 2.92,0.51 5.22,2.82 5.74,5.74 0.12,0.7 0.69,1.23 1.4,1.23 0.85,0 1.54,-0.75 1.41,-1.59 -0.68,-4.2 -3.99,-7.51 -8.19,-8.18zM5.56,4.52C4.73,4.43 4,5.1 4,5.93c0,0.73 0.55,1.33 1.27,1.4 6.01,0.6 10.79,5.38 11.39,11.39 0.07,0.73 0.67,1.28 1.4,1.28 0.84,0 1.5,-0.73 1.42,-1.56 -0.73,-7.34 -6.57,-13.19 -13.92,-13.92z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/rv_hookup.xml b/compose/material/material/icons/generator/raw-icons/rounded/rv_hookup.xml
index 08046fa..481cd08 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/rv_hookup.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/rv_hookup.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.9,16.21V17h-3V7c0,-1.1 -0.9,-2 -2,-2h-12c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h5v3h-6v6c0,1.65 1.35,3 3,3h1.18c0.42,1.16 1.52,2 2.82,2s2.4,-0.84 2.82,-2h8.19l0,0.78c0,0.45 0.54,0.67 0.85,0.36l1.79,-1.79c0.2,-0.2 0.2,-0.51 0,-0.71l-1.79,-1.79C20.44,15.54 19.9,15.76 19.9,16.21zM9.9,7h5v3h-5V7zM8.9,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S9.45,19 8.9,19z"/>
+ android:pathData="M21,17h-1v-6c0,-1.1 -0.9,-2 -2,-2L7,9v-0.74c0,-0.46 -0.56,-0.7 -0.89,-0.37L4.37,9.63c-0.2,0.2 -0.2,0.53 0,0.74l1.74,1.74c0.33,0.33 0.89,0.1 0.89,-0.37L7,11h4v3L5,14c-0.55,0 -1,0.45 -1,1v2c0,1.1 0.9,2 2,2h2c0,1.66 1.34,3 3,3s3,-1.34 3,-3h7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM11,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,14h-4v-3h3c0.55,0 1,0.45 1,1v2zM10,6h7v0.74c0,0.46 0.56,0.7 0.89,0.37l1.74,-1.74c0.2,-0.2 0.2,-0.53 0,-0.74l-1.74,-1.74c-0.33,-0.33 -0.89,-0.1 -0.89,0.37L17,4h-7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/satellite.xml b/compose/material/material/icons/generator/raw-icons/rounded/satellite.xml
index 9518cc5..8d4c48d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/satellite.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/satellite.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM6,6.5C6,6.22 6.22,6 6.5,6h1.51C8.32,6 8.57,6.29 8.5,6.6C8.28,7.54 7.54,8.28 6.6,8.51C6.29,8.58 6,8.33 6,8.01V6.5zM6,11.07c0,-0.42 0.3,-0.77 0.71,-0.84c1.8,-0.3 3.22,-1.73 3.52,-3.52C10.3,6.3 10.65,6 11.07,6c0.52,0 0.94,0.47 0.85,0.99c-0.42,2.52 -2.41,4.52 -4.93,4.93C6.47,12 6,11.59 6,11.07zM17,17H7c-0.41,0 -0.65,-0.47 -0.4,-0.8l2,-2.67c0.2,-0.27 0.6,-0.27 0.8,0L11.25,16l2.6,-3.47c0.2,-0.27 0.6,-0.27 0.8,0l2.75,3.67C17.65,16.53 17.41,17 17,17z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM5,5h3c0,1.66 -1.34,3 -3,3L5,5zM5,10.91c0,-0.49 0.36,-0.9 0.85,-0.98 2.08,-0.36 3.72,-2 4.08,-4.08 0.08,-0.49 0.49,-0.85 0.98,-0.85 0.61,0 1.09,0.53 1,1.13 -0.48,2.96 -2.81,5.3 -5.77,5.78 -0.6,0.1 -1.14,-0.39 -1.14,-1zM5.63,17.19l2.49,-3.2c0.2,-0.25 0.58,-0.26 0.78,-0.01l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8L6.02,18.01c-0.41,-0.01 -0.65,-0.49 -0.39,-0.82z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/save.xml b/compose/material/material/icons/generator/raw-icons/rounded/save.xml
index 5ee7bda..e05287f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/save.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/save.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.17,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V7.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-2.83,-2.83C17.21,3.21 16.7,3 16.17,3zM12,18c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S13.66,18 12,18zM14,10H7c-0.55,0 -1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1h7c0.55,0 1,0.45 1,1v2C15,9.55 14.55,10 14,10z"/>
+ android:pathData="M17.59,3.59c-0.38,-0.38 -0.89,-0.59 -1.42,-0.59L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-2.82,-2.83zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM13,9L7,9c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2h6c1.1,0 2,0.9 2,2s-0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/save_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/save_alt.xml
index 876e1d0..b4e4746 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/save_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/save_alt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.59,9H15V4c0,-0.55 -0.45,-1 -1,-1h-4C9.45,3 9,3.45 9,4v5H7.41c-0.89,0 -1.34,1.08 -0.71,1.71l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59C17.92,10.08 17.48,9 16.59,9zM5,19c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6C5.45,18 5,18.45 5,19z"/>
+ android:pathData="M19,13v5c0,0.55 -0.45,1 -1,1L6,19c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM13,12.67l1.88,-1.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-3.59,3.59c-0.39,0.39 -1.02,0.39 -1.41,0L7.7,12.2c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L11,12.67L11,4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v8.67z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/scanner.xml b/compose/material/material/icons/generator/raw-icons/rounded/scanner.xml
index 285fbb6..44e257c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/scanner.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/scanner.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.8,10.7L5.15,5.35c-0.52,-0.19 -1.1,0.08 -1.3,0.6l0,0c-0.19,0.53 0.08,1.11 0.6,1.3L17.6,12H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-5.5C21,11.7 20.5,10.9 19.8,10.7zM7,17L7,17c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C8,16.55 7.55,17 7,17zM17,17h-6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v0C18,16.55 17.55,17 17,17z"/>
+ android:pathData="M19.8,10.7L5.15,5.35c-0.52,-0.19 -1.1,0.08 -1.3,0.6 -0.19,0.53 0.08,1.11 0.6,1.3L17.6,12L5,12c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-5.5c0,-0.8 -0.5,-1.6 -1.2,-1.8zM7,17L5,17v-2h2v2zM18,17h-8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/scatter_plot.xml b/compose/material/material/icons/generator/raw-icons/rounded/scatter_plot.xml
index d1d94dd..c192675 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/scatter_plot.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/scatter_plot.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,14m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
+ android:pathData="M7,14m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,6m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
+ android:pathData="M11,6m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M17,17m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
+ android:pathData="M16.6,17.6m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/schedule.xml b/compose/material/material/icons/generator/raw-icons/rounded/schedule.xml
index b82761b..07b7ee3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/schedule.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/schedule.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM16,16c-0.39,0.39 -1.02,0.39 -1.41,0l-3.29,-3.29C11.11,12.52 11,12.27 11,12V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3.59l3,3C16.39,14.98 16.39,15.61 16,16z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM11.78,7h-0.06c-0.4,0 -0.72,0.32 -0.72,0.72v4.72c0,0.35 0.18,0.68 0.49,0.86l4.15,2.49c0.34,0.2 0.78,0.1 0.98,-0.24 0.21,-0.34 0.1,-0.79 -0.25,-0.99l-3.87,-2.3L12.5,7.72c0,-0.4 -0.32,-0.72 -0.72,-0.72z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/school.xml b/compose/material/material/icons/generator/raw-icons/rounded/school.xml
index bd5a74b..2d88878 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/school.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/school.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,13.18v2.81c0,0.73 0.4,1.41 1.04,1.76l5,2.73c0.6,0.33 1.32,0.33 1.92,0l5,-2.73C18.6,17.4 19,16.72 19,15.99v-2.81l-6.04,3.3c-0.6,0.33 -1.32,0.33 -1.92,0L5,13.18zM11.04,3.52l-8.43,4.6c-0.69,0.38 -0.69,1.38 0,1.76l8.43,4.6c0.6,0.33 1.32,0.33 1.92,0L21,10.09V16c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V9.59c0,-0.37 -0.2,-0.7 -0.52,-0.88l-9.52,-5.19C12.36,3.2 11.64,3.2 11.04,3.52z"/>
+ android:pathData="M5,13.18v2.81c0,0.73 0.4,1.41 1.04,1.76l5,2.73c0.6,0.33 1.32,0.33 1.92,0l5,-2.73c0.64,-0.35 1.04,-1.03 1.04,-1.76v-2.81l-6.04,3.3c-0.6,0.33 -1.32,0.33 -1.92,0L5,13.18zM11.04,3.52l-8.43,4.6c-0.69,0.38 -0.69,1.38 0,1.76l8.43,4.6c0.6,0.33 1.32,0.33 1.92,0L21,10.09L21,16c0,0.55 0.45,1 1,1s1,-0.45 1,-1L23,9.59c0,-0.37 -0.2,-0.7 -0.52,-0.88l-9.52,-5.19c-0.6,-0.32 -1.32,-0.32 -1.92,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/score.xml b/compose/material/material/icons/generator/raw-icons/rounded/score.xml
index e8e663d..89e02d3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/score.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/score.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM12,6.75C12,6.34 12.34,6 12.75,6s0.75,0.34 0.75,0.75V9l1.79,-2.69C15.42,6.12 15.64,6 15.88,6c0.56,0 0.9,0.63 0.59,1.1L15.2,9l1.27,1.9c0.31,0.47 -0.02,1.1 -0.59,1.1c-0.24,0 -0.46,-0.12 -0.59,-0.31L13.5,9v2.25c0,0.41 -0.34,0.75 -0.75,0.75S12,11.66 12,11.25V6.75zM7,9.25c0,-0.55 0.45,-1 1,-1h1.5V7.5H7.75C7.34,7.5 7,7.16 7,6.75S7.34,6 7.75,6H10c0.55,0 1,0.45 1,1v1.75c0,0.55 -0.45,1 -1,1H8.5v0.75h1.75c0.41,0 0.75,0.34 0.75,0.75S10.66,12 10.25,12H8c-0.55,0 -1,-0.45 -1,-1V9.25zM18.74,13.26l-5.03,5.03c-0.39,0.39 -1.02,0.39 -1.41,0L9,15l-2.49,2.49C5.95,18.05 5,17.65 5,16.87c0,-0.23 0.09,-0.46 0.26,-0.62l3.03,-3.03c0.39,-0.39 1.02,-0.39 1.41,0L13,16.5l4.49,-4.49c0.56,-0.56 1.51,-0.16 1.51,0.62C19,12.87 18.91,13.09 18.74,13.26z"/>
+ android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,5.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75L13.5,8l1.79,-2.69c0.13,-0.19 0.35,-0.31 0.59,-0.31 0.56,0 0.9,0.63 0.59,1.1L15.2,8l1.27,1.9c0.31,0.47 -0.02,1.1 -0.59,1.1 -0.24,0 -0.46,-0.12 -0.59,-0.31L13.5,8v2.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75v-4.5zM7,8.25c0,-0.55 0.45,-1 1,-1h1.5L9.5,6.5L7.75,6.5c-0.41,0 -0.75,-0.34 -0.75,-0.75S7.34,5 7.75,5L10,5c0.55,0 1,0.45 1,1v1.75c0,0.55 -0.45,1 -1,1L8.5,8.75v0.75h1.75c0.41,0 0.75,0.34 0.75,0.75s-0.34,0.75 -0.75,0.75L8,11c-0.55,0 -1,-0.45 -1,-1L7,8.25zM18.74,13.26l-5.03,5.03c-0.39,0.39 -1.02,0.39 -1.41,0L9,15l-2.49,2.49c-0.56,0.56 -1.51,0.16 -1.51,-0.62 0,-0.23 0.09,-0.46 0.26,-0.62l3.03,-3.03c0.39,-0.39 1.02,-0.39 1.41,0L13,16.5l4.49,-4.49c0.56,-0.56 1.51,-0.16 1.51,0.62 0,0.24 -0.09,0.46 -0.26,0.63z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/screen_rotation.xml b/compose/material/material/icons/generator/raw-icons/rounded/screen_rotation.xml
index 8a630a6..0fccc2d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/screen_rotation.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/screen_rotation.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.65,4.58C11.26,4.2 10.75,4 10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59s1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82L11.65,4.58zM13.77,18L6,10.24L10.23,6L18,13.76L13.77,18zM13.04,0.05C12.7,0.02 12.35,0 12,0c-0.6,0 -1.2,0.05 -1.77,0.14C9.82,0.2 9.66,0.7 9.95,0.99l3.2,3.16C13.46,4.47 14,4.25 14,3.8V2.2c4.28,0.87 7.57,4.48 7.96,8.92c0.04,0.5 0.48,0.88 0.99,0.88h0c0.6,0 1.05,-0.52 1,-1.12C23.42,5.12 18.81,0.55 13.04,0.05zM10,21.8c-4.28,-0.87 -7.57,-4.48 -7.96,-8.92C1.99,12.38 1.56,12 1.05,12h0c-0.6,0 -1.05,0.52 -1,1.12c0.53,5.76 5.14,10.34 10.91,10.83C11.3,23.98 11.65,24 12,24c0.59,0 1.16,-0.05 1.72,-0.13c0.41,-0.06 0.59,-0.56 0.29,-0.85l-3.16,-3.16C10.54,19.54 10,19.76 10,20.21V21.8z"/>
+ android:pathData="M10.23,1.75c-0.59,-0.59 -1.54,-0.59 -2.12,0L1.75,8.11c-0.59,0.59 -0.59,1.54 0,2.12l12.02,12.02c0.59,0.59 1.54,0.59 2.12,0l6.36,-6.36c0.59,-0.59 0.59,-1.54 0,-2.12L10.23,1.75zM14.12,20.48L3.52,9.88c-0.39,-0.39 -0.39,-1.02 0,-1.41l4.95,-4.95c0.39,-0.39 1.02,-0.39 1.41,0l10.61,10.61c0.39,0.39 0.39,1.02 0,1.41l-4.95,4.95c-0.39,0.38 -1.03,0.38 -1.42,-0.01zM17.61,1.4C16.04,0.57 14.06,-0.03 11.81,0.02c-0.18,0 -0.26,0.22 -0.14,0.35l3.48,3.48 1.33,-1.33c3.09,1.46 5.34,4.37 5.89,7.86 0.06,0.41 0.44,0.69 0.86,0.62 0.41,-0.06 0.69,-0.45 0.62,-0.86 -0.6,-3.8 -2.96,-7 -6.24,-8.74zM8.85,20.16l-1.33,1.33c-3.09,-1.46 -5.34,-4.37 -5.89,-7.86 -0.06,-0.41 -0.44,-0.69 -0.86,-0.62 -0.41,0.06 -0.69,0.45 -0.62,0.86 0.6,3.81 2.96,7.01 6.24,8.75 1.57,0.83 3.55,1.43 5.8,1.38 0.18,0 0.26,-0.22 0.14,-0.35l-3.48,-3.49z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/screen_share.xml b/compose/material/material/icons/generator/raw-icons/rounded/screen_share.xml
index ba40121..fbb60d5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/screen_share.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/screen_share.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v11c0,1.1 0.9,2 2,2h16c1.1,0 1.99,-0.9 1.99,-2L22,5C22,3.9 21.1,3 20,3zM15.65,10.35l-1.79,1.79C13.54,12.46 13,12.24 13,11.79V11h-2c-0.55,0 -1,0.45 -1,1v1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-1c0,-1.65 1.35,-3 3,-3h2V8.21c0,-0.45 0.54,-0.67 0.85,-0.35l1.79,1.79C15.84,9.84 15.84,10.16 15.65,10.35z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1,20L1,20c0,0.55 0.45,1 1,1h20c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H2C1.45,19 1,19.45 1,20z"/>
+ android:pathData="M20,18c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.89,2 2,2L1,18c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h22c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3zM13,14.47v-2.19c-2.78,0 -4.61,0.85 -6,2.72 0.56,-2.67 2.11,-5.33 6,-5.87L13,7l3.61,3.36c0.21,0.2 0.21,0.53 0,0.73L13,14.47z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sd_card.xml b/compose/material/material/icons/generator/raw-icons/rounded/sd_card.xml
index d82d51a..38e9552 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sd_card.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sd_card.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2h-7.17C10.3,2 9.79,2.21 9.41,2.59L4.59,7.41C4.21,7.79 4,8.3 4,8.83V20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM10,11L10,11c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2C11,10.55 10.55,11 10,11zM13,11L13,11c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2C14,10.55 13.55,11 13,11zM16,11L16,11c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2C17,10.55 16.55,11 16,11z"/>
+ android:pathData="M18,2h-7.17c-0.53,0 -1.04,0.21 -1.42,0.59L4.6,7.42c-0.37,0.37 -0.6,0.88 -0.6,1.4L4,20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM11,8c-0.55,0 -1,-0.45 -1,-1L10,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM14,8c-0.55,0 -1,-0.45 -1,-1L13,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM17,8c-0.55,0 -1,-0.45 -1,-1L16,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sd_card_alert.xml b/compose/material/material/icons/generator/raw-icons/rounded/sd_card_alert.xml
index f71953f..7228ccb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sd_card_alert.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sd_card_alert.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2h-7.17C10.3,2 9.79,2.21 9.41,2.59L4.6,7.42C4.23,7.79 4.02,8.3 4.02,8.82L4,20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM12,17L12,17c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,16.55 12.55,17 12,17zM12,13L12,13c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v3C13,12.55 12.55,13 12,13z"/>
+ android:pathData="M18,2h-7.17c-0.53,0 -1.04,0.21 -1.42,0.59L4.6,7.42c-0.37,0.37 -0.58,0.88 -0.58,1.4L4,20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM13,17h-2v-2h2v2zM12,13c-0.55,0 -1,-0.45 -1,-1L11,9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sd_storage.xml b/compose/material/material/icons/generator/raw-icons/rounded/sd_storage.xml
index d82d51a..38e9552 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sd_storage.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sd_storage.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2h-7.17C10.3,2 9.79,2.21 9.41,2.59L4.59,7.41C4.21,7.79 4,8.3 4,8.83V20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM10,11L10,11c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2C11,10.55 10.55,11 10,11zM13,11L13,11c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2C14,10.55 13.55,11 13,11zM16,11L16,11c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2C17,10.55 16.55,11 16,11z"/>
+ android:pathData="M18,2h-7.17c-0.53,0 -1.04,0.21 -1.42,0.59L4.6,7.42c-0.37,0.37 -0.6,0.88 -0.6,1.4L4,20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM11,8c-0.55,0 -1,-0.45 -1,-1L10,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM14,8c-0.55,0 -1,-0.45 -1,-1L13,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM17,8c-0.55,0 -1,-0.45 -1,-1L16,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/search.xml b/compose/material/material/icons/generator/raw-icons/rounded/search.xml
index 848e09c..c1818d5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/search.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/search.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.29,18.88l-5.56,-5.56c1.13,-1.55 1.63,-3.58 0.98,-5.74c-0.68,-2.23 -2.57,-3.98 -4.85,-4.44C6.21,2.2 2.2,6.22 3.14,10.86c0.46,2.29 2.21,4.18 4.44,4.85c2.16,0.65 4.19,0.15 5.74,-0.98l5.56,5.56c0.39,0.39 1.02,0.39 1.41,0l0,0C20.68,19.9 20.68,19.27 20.29,18.88zM5,9.5C5,7.01 7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14S5,11.99 5,9.5z"/>
+ android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.79,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.25,4.25c0.41,0.41 1.08,0.41 1.49,0 0.41,-0.41 0.41,-1.08 0,-1.49L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/search_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/search_off.xml
index 00c4723..34e35b0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/search_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/search_off.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,12c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S9.76,12 7,12zM9.12,18.41c0.2,0.2 0.2,0.51 0,0.71c-0.2,0.2 -0.51,0.2 -0.71,0L7,17.71l-1.41,1.41c-0.2,0.2 -0.51,0.2 -0.71,0c-0.2,-0.2 -0.2,-0.51 0,-0.71L6.29,17l-1.41,-1.41c-0.2,-0.2 -0.2,-0.51 0,-0.71c0.2,-0.2 0.51,-0.2 0.71,0L7,16.29l1.41,-1.41c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71L7.71,17L9.12,18.41z"/>
+ android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34c-0.47,-2.78 -2.79,-4.99 -5.58,-5.34C6.54,2.58 3.3,5.38 3.03,9h2.02c0.24,-2.12 1.92,-3.8 4.06,-3.98C11.65,4.8 14,6.95 14,9.5c0,2.49 -2.01,4.5 -4.5,4.5c-0.17,0 -0.33,-0.03 -0.5,-0.05l0,2.02c0,0 0,0 0.01,0.01c1.8,0.13 3.47,-0.47 4.72,-1.55L14,14.71v0.79l4.25,4.25c0.41,0.41 1.08,0.41 1.49,0l0,0c0.41,-0.41 0.41,-1.08 0,-1.49L15.5,14z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15.73,13.31c1.13,-1.54 1.63,-3.57 0.99,-5.72c-0.68,-2.27 -2.63,-4.04 -4.96,-4.47C7.61,2.34 4,5.5 4,9.5c0,0.39 0.04,0.76 0.1,1.13c0.61,-0.28 1.26,-0.47 1.95,-0.56C6.03,9.88 6,9.7 6,9.5c0,-2.79 2.52,-4.97 5.41,-4.41c1.5,0.29 2.78,1.38 3.3,2.82c0.8,2.2 -0.16,4.35 -1.82,5.41l6.98,6.98c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L15.73,13.31z"/>
+ android:pathData="M6.12,11.17L4,13.29l-2.12,-2.12c-0.2,-0.2 -0.51,-0.2 -0.71,0l0,0c-0.2,0.2 -0.2,0.51 0,0.71L3.29,14l-2.12,2.12c-0.2,0.2 -0.2,0.51 0,0.71l0,0c0.2,0.2 0.51,0.2 0.71,0L4,14.71l2.12,2.12c0.2,0.2 0.51,0.2 0.71,0l0,0c0.2,-0.2 0.2,-0.51 0,-0.71L4.71,14l2.12,-2.12c0.2,-0.2 0.2,-0.51 0,-0.71l0,0C6.63,10.98 6.32,10.98 6.12,11.17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/security.xml b/compose/material/material/icons/generator/raw-icons/rounded/security.xml
index 90abe84..43954d1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/security.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/security.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.3,2.26l-6,2.25C4.52,4.81 4,5.55 4,6.39v4.7C4,11.4 4.01,11.7 4.04,12c0.36,4.49 3.37,8.55 7.4,9.84c0.37,0.12 0.77,0.12 1.13,0c4.03,-1.29 7.03,-5.35 7.4,-9.84c0.02,-0.3 0.04,-0.6 0.04,-0.91v-4.7c0,-0.83 -0.52,-1.58 -1.3,-1.87l-6,-2.25C12.25,2.09 11.75,2.09 11.3,2.26zM12,19.92V12H6.05C6.02,11.7 6,11.4 6,11.09v-4.7l6,-2.25V12h5.95C17.6,15.64 15.19,18.88 12,19.92z"/>
+ android:pathData="M11.19,1.36l-7,3.11C3.47,4.79 3,5.51 3,6.3V11c0,5.55 3.84,10.74 9,12 5.16,-1.26 9,-6.45 9,-12V6.3c0,-0.79 -0.47,-1.51 -1.19,-1.83l-7,-3.11c-0.51,-0.23 -1.11,-0.23 -1.62,0zM12,11.99h7c-0.53,4.12 -3.28,7.79 -7,8.94V12H5V6.3l7,-3.11v8.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/select_all.xml b/compose/material/material/icons/generator/raw-icons/rounded/select_all.xml
index 1b8f111..4e8aecd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/select_all.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/select_all.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,5h2V3C3.9,3 3,3.9 3,5zM3,13h2v-2H3V13zM7,21h2v-2H7V21zM3,9h2V7H3V9zM13,3h-2v2h2V3zM19,3v2h2C21,3.9 20.1,3 19,3zM5,21v-2H3C3,20.1 3.9,21 5,21zM3,17h2v-2H3V17zM9,3H7v2h2V3zM11,21h2v-2h-2V21zM19,13h2v-2h-2V13zM19,21c1.1,0 2,-0.9 2,-2h-2V21zM19,9h2V7h-2V9zM19,17h2v-2h-2V17zM15,21h2v-2h-2V21zM15,5h2V3h-2V5zM8,17h8c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1H8C7.45,7 7,7.45 7,8v8C7,16.55 7.45,17 8,17zM9,9h6v6H9V9z"/>
+ android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM8,17h8c0.55,0 1,-0.45 1,-1L17,8c0,-0.55 -0.45,-1 -1,-1L8,7c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1zM9,9h6v6L9,15L9,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/self_improvement.xml b/compose/material/material/icons/generator/raw-icons/rounded/self_improvement.xml
index 0cc257e..ecb94f8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/self_improvement.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/self_improvement.xml
@@ -9,5 +9,5 @@
android:pathData="M12,6m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M21,14.94L21,14.94c0,-0.5 -0.36,-0.93 -0.85,-0.98c-1.88,-0.21 -3.49,-1.13 -4.75,-2.63l-1.34,-1.6C13.68,9.26 13.12,9 12.53,9h-1.05c-0.59,0 -1.15,0.26 -1.53,0.72l-1.34,1.6c-1.25,1.5 -2.87,2.42 -4.75,2.63C3.36,14.01 3,14.44 3,14.94l0,0c0,0.6 0.53,1.07 1.13,1c2.3,-0.27 4.32,-1.39 5.87,-3.19V15l-3.76,1.5c-0.65,0.26 -1.16,0.83 -1.23,1.53C4.91,19.1 5.74,20 6.79,20H9v-0.5c0,-1.38 1.12,-2.5 2.5,-2.5h3c0.28,0 0.5,0.22 0.5,0.5S14.78,18 14.5,18h-3c-0.83,0 -1.5,0.67 -1.5,1.5V20h7.1c0.85,0 1.65,-0.54 1.85,-1.37c0.21,-0.89 -0.27,-1.76 -1.08,-2.08L14,15v-2.25c1.56,1.8 3.57,2.91 5.87,3.19C20.47,16 21,15.54 21,14.94z"/>
+ android:pathData="M21,14.94L21,14.94c0,-0.5 -0.36,-0.93 -0.85,-0.98c-1.88,-0.21 -3.49,-1.13 -4.75,-2.63l-1.34,-1.6C13.68,9.26 13.12,9 12.53,9h-1.05c-0.59,0 -1.15,0.26 -1.53,0.72l-1.34,1.6c-1.25,1.5 -2.87,2.42 -4.75,2.63C3.36,14.01 3,14.44 3,14.94v0c0,0.6 0.53,1.07 1.13,1c2.3,-0.27 4.32,-1.39 5.87,-3.19V15l-3.76,1.5c-0.65,0.26 -1.16,0.83 -1.23,1.53C4.91,19.1 5.74,20 6.79,20H9v-0.5c0,-1.38 1.12,-2.5 2.5,-2.5h3c0.28,0 0.5,0.22 0.5,0.5S14.78,18 14.5,18h-3c-0.83,0 -1.5,0.67 -1.5,1.5V20l7.1,0c0.85,0 1.65,-0.54 1.85,-1.37c0.21,-0.89 -0.27,-1.76 -1.08,-2.08L14,15v-2.25c1.56,1.8 3.57,2.91 5.87,3.19C20.47,16 21,15.54 21,14.94z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/send.xml b/compose/material/material/icons/generator/raw-icons/rounded/send.xml
index 20c8446..ae931b5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/send.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/send.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,5.51v3.71c0,0.46 0.31,0.86 0.76,0.97L11,12l-7.24,1.81C3.31,13.92 3,14.32 3,14.78v3.71c0,0.72 0.73,1.2 1.39,0.92l15.42,-6.49c0.82,-0.34 0.82,-1.5 0,-1.84L4.39,4.58C3.73,4.31 3,4.79 3,5.51z"/>
+ android:pathData="M3.4,20.4l17.45,-7.48c0.81,-0.35 0.81,-1.49 0,-1.84L3.4,3.6c-0.66,-0.29 -1.39,0.2 -1.39,0.91L2,9.12c0,0.5 0.37,0.93 0.87,0.99L17,12 2.87,13.88c-0.5,0.07 -0.87,0.5 -0.87,1l0.01,4.61c0,0.71 0.73,1.2 1.39,0.91z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_dissatisfied.xml b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_dissatisfied.xml
index 65c41e2..e1d439d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_dissatisfied.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_dissatisfied.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM15.5,8C16.33,8 17,8.67 17,9.5S16.33,11 15.5,11S14,10.33 14,9.5S14.67,8 15.5,8zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM15.86,17c-0.23,0 -0.46,-0.1 -0.6,-0.29C14.53,15.68 13.35,15 12,15c-1.35,0 -2.54,0.68 -3.26,1.7C8.6,16.9 8.38,17 8.14,17h0c-0.62,0 -0.97,-0.7 -0.61,-1.2c1,-1.39 2.63,-2.3 4.47,-2.3c1.84,0 3.47,0.91 4.47,2.3C16.83,16.3 16.47,17 15.86,17L15.86,17z"/>
+ android:pathData="M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12,14c-1.9,0 -3.63,0.97 -4.65,2.58 -0.22,0.35 -0.11,0.81 0.24,1.03 0.35,0.22 0.81,0.11 1.03,-0.24 0.74,-1.18 2,-1.88 3.38,-1.88s2.64,0.7 3.38,1.88c0.14,0.23 0.39,0.35 0.64,0.35 0.14,0 0.27,-0.04 0.4,-0.11 0.35,-0.22 0.46,-0.68 0.24,-1.03C15.63,14.96 13.9,14 12,14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_neutral.xml b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_neutral.xml
index 3475f3f..70735fa 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_neutral.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_neutral.xml
@@ -6,5 +6,14 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM7,9.5C7,8.67 7.67,8 8.5,8S10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5zM14.25,15.5h-4.5C9.34,15.5 9,15.16 9,14.75C9,14.34 9.34,14 9.75,14h4.5c0.41,0 0.75,0.34 0.75,0.75C15,15.16 14.66,15.5 14.25,15.5zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
+ android:pathData="M9.75,15.5h4.5c0.41,0 0.75,-0.34 0.75,-0.75s-0.34,-0.75 -0.75,-0.75h-4.5c-0.41,0 -0.75,0.34 -0.75,0.75s0.34,0.75 0.75,0.75z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied.xml b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied.xml
index d46eae1..4c8205f7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM16.65,14.92C15.63,16.53 13.9,17.5 12,17.5s-3.63,-0.96 -4.65,-2.59c-0.22,-0.35 -0.11,-0.81 0.24,-1.03c0.35,-0.22 0.81,-0.11 1.03,0.24C9.36,15.3 10.62,16 12,16s2.64,-0.7 3.38,-1.87c0.21,-0.35 0.68,-0.46 1.03,-0.24C16.76,14.11 16.87,14.57 16.65,14.92zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
+ android:pathData="M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM16.41,13.89c-0.35,-0.22 -0.82,-0.11 -1.03,0.24 -0.74,1.17 -2,1.87 -3.38,1.87s-2.64,-0.7 -3.38,-1.88c-0.22,-0.35 -0.68,-0.46 -1.03,-0.24 -0.35,0.22 -0.46,0.68 -0.24,1.03C8.37,16.54 10.1,17.5 12,17.5s3.63,-0.97 4.65,-2.58c0.22,-0.35 0.11,-0.81 -0.24,-1.03z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied_alt.xml
index d46eae1..4c8205f7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_satisfied_alt.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM16.65,14.92C15.63,16.53 13.9,17.5 12,17.5s-3.63,-0.96 -4.65,-2.59c-0.22,-0.35 -0.11,-0.81 0.24,-1.03c0.35,-0.22 0.81,-0.11 1.03,0.24C9.36,15.3 10.62,16 12,16s2.64,-0.7 3.38,-1.87c0.21,-0.35 0.68,-0.46 1.03,-0.24C16.76,14.11 16.87,14.57 16.65,14.92zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
+ android:pathData="M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM16.41,13.89c-0.35,-0.22 -0.82,-0.11 -1.03,0.24 -0.74,1.17 -2,1.87 -3.38,1.87s-2.64,-0.7 -3.38,-1.88c-0.22,-0.35 -0.68,-0.46 -1.03,-0.24 -0.35,0.22 -0.46,0.68 -0.24,1.03C8.37,16.54 10.1,17.5 12,17.5s3.63,-0.97 4.65,-2.58c0.22,-0.35 0.11,-0.81 -0.24,-1.03z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_dissatisfied.xml b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_dissatisfied.xml
index 6432049..4db5de0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_dissatisfied.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_dissatisfied.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.47 2,12s4.47,10 9.99,10S22,17.53 22,12S17.52,2 11.99,2zM7.29,9.35C7,9.06 7,8.58 7.29,8.29C7.58,8 8.06,8 8.35,8.29l0.53,0.53l0.53,-0.53C9.7,8 10.18,8 10.47,8.29c0.29,0.29 0.29,0.77 0,1.06L9.94,9.88l0.53,0.53c0.29,0.29 0.29,0.77 0,1.06c-0.29,0.29 -0.77,0.29 -1.06,0l-0.53,-0.53l-0.53,0.53c-0.29,0.29 -0.77,0.29 -1.06,0C7,11.18 7,10.7 7.29,10.41l0.53,-0.53L7.29,9.35zM16.31,17H7.69c-0.38,0 -0.63,-0.42 -0.44,-0.75C8.2,14.61 9.97,13.5 12,13.5s3.8,1.11 4.75,2.75C16.94,16.58 16.69,17 16.31,17zM16.71,10.41c0.29,0.29 0.29,0.77 0,1.06c-0.29,0.29 -0.77,0.29 -1.06,0l-0.53,-0.53l-0.53,0.53c-0.29,0.29 -0.77,0.29 -1.06,0c-0.29,-0.29 -0.29,-0.77 0,-1.06l0.53,-0.53l-0.53,-0.53c-0.29,-0.29 -0.29,-0.77 0,-1.06C13.82,8 14.3,8 14.59,8.29l0.53,0.53l0.53,-0.53c0.29,-0.29 0.77,-0.29 1.06,0c0.29,0.29 0.29,0.77 0,1.06l-0.53,0.53L16.71,10.41z"/>
+ android:pathData="M12,13.5c-2.03,0 -3.8,1.11 -4.75,2.75 -0.19,0.33 0.06,0.75 0.44,0.75h8.62c0.38,0 0.63,-0.42 0.44,-0.75 -0.95,-1.64 -2.72,-2.75 -4.75,-2.75zM8.35,11.47l0.53,-0.53 0.53,0.53c0.29,0.29 0.77,0.29 1.06,0 0.29,-0.29 0.29,-0.77 0,-1.06l-0.53,-0.53 0.53,-0.53c0.29,-0.29 0.29,-0.77 0,-1.06 -0.29,-0.29 -0.77,-0.29 -1.06,0l-0.53,0.53 -0.53,-0.53c-0.29,-0.29 -0.77,-0.29 -1.06,0 -0.29,0.29 -0.29,0.77 0,1.06l0.53,0.53 -0.53,0.53c-0.29,0.29 -0.29,0.77 0,1.06 0.29,0.29 0.77,0.29 1.06,0zM11.99,2C6.47,2 2,6.47 2,12s4.47,10 9.99,10S22,17.53 22,12 17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.65,8.29l-0.53,0.53 -0.53,-0.53c-0.29,-0.29 -0.77,-0.29 -1.06,0 -0.29,0.29 -0.29,0.77 0,1.06l0.53,0.53 -0.53,0.53c-0.29,0.29 -0.29,0.77 0,1.06 0.29,0.29 0.77,0.29 1.06,0l0.53,-0.53 0.53,0.53c0.29,0.29 0.77,0.29 1.06,0 0.29,-0.29 0.29,-0.77 0,-1.06l-0.53,-0.53 0.53,-0.53c0.29,-0.29 0.29,-0.77 0,-1.06 -0.29,-0.29 -0.77,-0.29 -1.06,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_satisfied.xml b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_satisfied.xml
index dcb1c20..fda446f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_satisfied.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sentiment_very_satisfied.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.47 2,12s4.47,10 9.99,10S22,17.53 22,12S17.52,2 11.99,2zM7.29,9.41l0.89,-0.88c0.39,-0.39 1.02,-0.39 1.41,0l0.88,0.88c0.29,0.29 0.29,0.77 0,1.06c-0.29,0.29 -0.77,0.29 -1.06,0L8.88,9.94l-0.53,0.53c-0.29,0.29 -0.77,0.29 -1.06,0C7,10.18 7,9.7 7.29,9.41zM16.75,14.75C15.8,16.39 14.03,17.5 12,17.5s-3.8,-1.11 -4.75,-2.75C7.06,14.42 7.31,14 7.69,14h8.62C16.7,14 16.94,14.42 16.75,14.75zM16.71,10.47c-0.29,0.29 -0.77,0.29 -1.06,0l-0.53,-0.53l-0.53,0.53c-0.29,0.29 -0.77,0.29 -1.06,0c-0.29,-0.29 -0.29,-0.77 0.01,-1.06l0.88,-0.88c0.39,-0.39 1.02,-0.39 1.41,0l0.88,0.88C17,9.7 17,10.18 16.71,10.47z"/>
+ android:pathData="M8.88,9.94l0.53,0.53c0.29,0.29 0.77,0.29 1.06,0 0.29,-0.29 0.29,-0.77 0,-1.06l-0.88,-0.88c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.89,0.88c-0.29,0.29 -0.29,0.77 0,1.06 0.29,0.29 0.77,0.29 1.06,0l0.53,-0.53zM12,17.5c2.03,0 3.8,-1.11 4.75,-2.75 0.19,-0.33 -0.05,-0.75 -0.44,-0.75L7.69,14c-0.38,0 -0.63,0.42 -0.44,0.75 0.95,1.64 2.72,2.75 4.75,2.75zM13.53,10.47c0.29,0.29 0.77,0.29 1.06,0l0.53,-0.53 0.53,0.53c0.29,0.29 0.77,0.29 1.06,0 0.29,-0.29 0.29,-0.77 0,-1.06l-0.88,-0.88c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.88,0.88c-0.3,0.29 -0.3,0.77 -0.01,1.06zM11.99,2C6.47,2 2,6.47 2,12s4.47,10 9.99,10S22,17.53 22,12 17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/settings_system_daydream.xml b/compose/material/material/icons/generator/raw-icons/rounded/settings_system_daydream.xml
index 24e80ab..4435521 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/settings_system_daydream.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/settings_system_daydream.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM15.5,16H9c-1.66,0 -3,-1.34 -3,-3c0,-1.55 1.17,-2.82 2.68,-2.98h0.16C9.4,8.83 10.6,8 12,8c1.76,0 3.21,1.31 3.45,3h0.05c1.38,0 2.5,1.12 2.5,2.5S16.88,16 15.5,16z"/>
+ android:pathData="M9,16h6.5c1.38,0 2.5,-1.12 2.5,-2.5S16.88,11 15.5,11h-0.05c-0.24,-1.69 -1.69,-3 -3.45,-3 -1.4,0 -2.6,0.83 -3.16,2.02h-0.16C7.17,10.18 6,11.45 6,13c0,1.66 1.34,3 3,3zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM20,19.01L4,19.01c-0.55,0 -1,-0.45 -1,-1L3,5.99c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v12.02c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/share.xml b/compose/material/material/icons/generator/raw-icons/rounded/share.xml
index de50903..17f4f4a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/share.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/share.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,16c-0.79,0 -1.5,0.31 -2.03,0.81L8.91,12.7C8.96,12.47 9,12.24 9,12s-0.04,-0.47 -0.09,-0.7l7.05,-4.11C16.49,7.69 17.21,8 18,8c1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3s-3,1.34 -3,3c0,0.24 0.04,0.48 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.05,4.12C15.04,18.53 15,18.76 15,19c0,1.66 1.34,3 3,3s3,-1.34 3,-3S19.66,16 18,16z"/>
+ android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92s2.92,-1.31 2.92,-2.92 -1.31,-2.92 -2.92,-2.92z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/shop.xml b/compose/material/material/icons/generator/raw-icons/rounded/shop.xml
index 838b2a3..3ab2e20 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/shop.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/shop.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,6V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H2v13c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6H16zM10,4h4v2h-4V4zM9.5,16.17v-5.34c0,-0.79 0.88,-1.27 1.54,-0.84l4.15,2.67c0.61,0.39 0.61,1.29 0,1.68l-4.15,2.67C10.38,17.44 9.5,16.96 9.5,16.17z"/>
+ android:pathData="M16,6L16,4c0,-1.1 -0.9,-2 -2,-2h-4c-1.1,0 -2,0.9 -2,2v2L4,6c-1.1,0 -2,0.9 -2,2v11c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2h-4zM10,4h4v2h-4L10,4zM9,17.07L9,9.83c0,-0.38 0.4,-0.62 0.74,-0.44l6.03,3.21c0.33,0.18 0.36,0.65 0.04,0.86l-6.03,4.02c-0.33,0.22 -0.78,-0.01 -0.78,-0.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/shopping_basket.xml b/compose/material/material/icons/generator/raw-icons/rounded/shopping_basket.xml
index d050196..8ee01fd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/shopping_basket.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/shopping_basket.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.21,9l-4.39,-6.56c-0.4,-0.59 -1.27,-0.59 -1.66,0L6.77,9H2c-0.66,0 -1.14,0.63 -0.96,1.27l2.76,10C3.92,20.7 4.31,21 4.76,21h14.5c0.45,0 0.85,-0.3 0.96,-0.74l2.74,-10C23.14,9.63 22.66,9 22,9H17.21zM11.99,4.79L14.8,9H9.18L11.99,4.79zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,17 12,17z"/>
+ android:pathData="M22,9h-4.79l-4.39,-6.57c-0.4,-0.59 -1.27,-0.59 -1.66,0L6.77,9H2c-0.55,0 -1,0.45 -1,1 0,0.09 0.01,0.18 0.04,0.27l2.54,9.27c0.23,0.84 1,1.46 1.92,1.46h13c0.92,0 1.69,-0.62 1.93,-1.46l2.54,-9.27L23,10c0,-0.55 -0.45,-1 -1,-1zM11.99,4.79L14.8,9H9.18l2.81,-4.21zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/shopping_cart.xml b/compose/material/material/icons/generator/raw-icons/rounded/shopping_cart.xml
index cbf0397..8e442dd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/shopping_cart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/shopping_cart.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.55,13c1.22,0 1.74,-1.01 1.75,-1.03l3.55,-6.44c0.23,-0.45 0.18,-0.84 -0.01,-1.11C20.66,4.16 20.33,4 20,4C19.99,4 5.21,4 5.21,4L4.54,2.57C4.38,2.22 4.02,2 3.64,2H2C1.45,2 1,2.45 1,3v0c0,0.55 0.45,1 1,1h1l3.6,7.59l-1.35,2.44C4.52,15.37 5.48,17 7,17h11c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H7l1.1,-2H15.55z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7,20m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,20m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2zM1,3c0,0.55 0.45,1 1,1h1l3.6,7.59 -1.35,2.44C4.52,15.37 5.48,17 7,17h11c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L7,15l1.1,-2h7.45c0.75,0 1.41,-0.41 1.75,-1.03l3.58,-6.49c0.37,-0.66 -0.11,-1.48 -0.87,-1.48L5.21,4l-0.67,-1.43c-0.16,-0.35 -0.52,-0.57 -0.9,-0.57L2,2c-0.55,0 -1,0.45 -1,1zM17,18c-1.1,0 -1.99,0.9 -1.99,2s0.89,2 1.99,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/short_text.xml b/compose/material/material/icons/generator/raw-icons/rounded/short_text.xml
index 465879b..d2cdbb5 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/short_text.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/short_text.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,9h14c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1l0,0C4,9.45 4.45,9 5,9zM5,13h8c0.55,0 1,0.45 1,1l0,0c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1l0,0C4,13.45 4.45,13 5,13z"/>
+ android:pathData="M5,9h14c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM5,13h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,15c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/show_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/show_chart.xml
index e634c10..4dfa21d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/show_chart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/show_chart.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.2,17.78l5.3,-5.3l3.25,3.25c0.41,0.41 1.07,0.39 1.45,-0.04l7.17,-8.07c0.35,-0.39 0.33,-0.99 -0.04,-1.37l0,0c-0.4,-0.4 -1.07,-0.39 -1.45,0.04l-6.39,7.18l-3.29,-3.29c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.09,6.1c-0.39,0.39 -0.39,1.02 0,1.41l0.09,0.09C3.18,18.17 3.82,18.17 4.2,17.78z"/>
+ android:pathData="M4.2,17.78l5.3,-5.3 3.25,3.25c0.41,0.41 1.07,0.39 1.45,-0.04l7.17,-8.07c0.35,-0.39 0.33,-0.99 -0.04,-1.37 -0.4,-0.4 -1.07,-0.39 -1.45,0.04l-6.39,7.18 -3.29,-3.29c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.09,6.1c-0.39,0.39 -0.39,1.02 0,1.41l0.09,0.09c0.39,0.39 1.03,0.39 1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/shuffle.xml b/compose/material/material/icons/generator/raw-icons/rounded/shuffle.xml
index dcda847..0d35020 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/shuffle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/shuffle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.18,9.17L5.71,4.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l4.46,4.46L10.18,9.17zM14.94,4.85l1.19,1.19L4.29,17.88c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L17.55,7.46l1.19,1.19c0.31,0.31 0.85,0.09 0.85,-0.36V4.5c0,-0.28 -0.22,-0.5 -0.5,-0.5H15.3C14.85,4 14.63,4.54 14.94,4.85zM14.42,13.41l-1.41,1.41l3.13,3.13l-1.2,1.2C14.63,19.46 14.85,20 15.3,20h3.79c0.28,0 0.5,-0.22 0.5,-0.5v-3.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.19,1.19L14.42,13.41z"/>
+ android:pathData="M10.59,9.17L6.12,4.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.46,4.46 1.42,-1.4zM15.35,4.85l1.19,1.19L4.7,17.88c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L17.96,7.46l1.19,1.19c0.31,0.31 0.85,0.09 0.85,-0.36L20,4.5c0,-0.28 -0.22,-0.5 -0.5,-0.5h-3.79c-0.45,0 -0.67,0.54 -0.36,0.85zM14.83,13.41l-1.41,1.41 3.13,3.13 -1.2,1.2c-0.31,0.31 -0.09,0.85 0.36,0.85h3.79c0.28,0 0.5,-0.22 0.5,-0.5v-3.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.19,1.19 -3.13,-3.14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/shutter_speed.xml b/compose/material/material/icons/generator/raw-icons/rounded/shutter_speed.xml
index bb24f26..43242bb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/shutter_speed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/shutter_speed.xml
@@ -6,26 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,1h-4C9.45,1 9,1.45 9,2v0c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v0C15,1.45 14.55,1 14,1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.03,7.39l0.75,-0.75c0.38,-0.38 0.39,-1.01 0,-1.4c0,0 -0.01,-0.01 -0.01,-0.01c-0.39,-0.39 -1.01,-0.38 -1.4,0l-0.75,0.75C16.07,4.74 14.12,4 12,4c-4.8,0 -8.88,3.96 -9,8.76C2.87,17.84 6.94,22 12,22c4.98,0 9,-4.03 9,-9C21,10.88 20.26,8.93 19.03,7.39zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7s7,3.13 7,7S15.87,20 12,20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.67,15.74c0.61,1.19 1.61,2.15 2.83,2.71c0.23,0.11 0.51,0.01 0.63,-0.21l1.43,-2.48c0.19,-0.33 -0.05,-0.75 -0.43,-0.75H7.11C6.74,15 6.49,15.4 6.67,15.74z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.7,18.99c1.48,0.08 2.79,-0.4 3.77,-1.1c0.2,-0.15 0.25,-0.43 0.13,-0.65l-1.44,-2.49c-0.19,-0.33 -0.67,-0.33 -0.87,0l-2.01,3.48C11.1,18.56 11.33,18.97 11.7,18.99z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.3,7.01c-1.48,-0.08 -2.79,0.4 -3.77,1.1c-0.2,0.15 -0.25,0.43 -0.13,0.65l1.44,2.49c0.19,0.33 0.67,0.33 0.87,0l2.01,-3.48C12.9,7.44 12.67,7.03 12.3,7.01z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.97,9.73c-0.66,1.02 -1.08,2.33 -0.94,3.83C6.06,13.81 6.28,14 6.53,14H9.4c0.38,0 0.63,-0.42 0.43,-0.75L7.82,9.76C7.64,9.44 7.17,9.42 6.97,9.73z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.03,16.27c0.66,-1.02 1.08,-2.33 0.94,-3.83c-0.02,-0.25 -0.25,-0.44 -0.5,-0.44H14.6c-0.38,0 -0.63,0.42 -0.43,0.75l2.01,3.49C16.36,16.56 16.83,16.58 17.03,16.27z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.87,7.77l-1.43,2.48C12.24,10.58 12.48,11 12.87,11h4.02c0.38,0 0.62,-0.4 0.45,-0.74c-0.61,-1.19 -1.61,-2.15 -2.83,-2.71C14.27,7.45 13.99,7.55 13.87,7.77z"/>
+ android:pathData="M10,3h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM19.03,7.39l0.75,-0.75c0.38,-0.38 0.39,-1.01 0,-1.4l-0.01,-0.01c-0.39,-0.39 -1.01,-0.38 -1.4,0l-0.75,0.75C16.07,4.74 14.12,4 12,4c-4.8,0 -8.88,3.96 -9,8.76C2.87,17.84 6.94,22 12,22c4.98,0 9,-4.03 9,-9 0,-2.12 -0.74,-4.07 -1.97,-5.61zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7zM10.81,15h-3.7c-0.38,0 -0.62,0.4 -0.45,0.74 0.56,1.12 1.44,2.01 2.57,2.57 0.23,0.11 0.52,0.02 0.65,-0.21l1.37,-2.35c0.19,-0.33 -0.05,-0.75 -0.44,-0.75zM14.73,7.65c-0.23,-0.12 -0.52,-0.02 -0.65,0.2l-1.38,2.39c-0.2,0.34 0.04,0.76 0.43,0.76h3.76c0.38,0 0.62,-0.4 0.45,-0.73 -0.58,-1.13 -1.49,-2.04 -2.61,-2.62zM13.88,14.7c-0.19,-0.34 -0.68,-0.35 -0.87,-0.01l-2.04,3.52c-0.18,0.32 0.02,0.72 0.39,0.75 1.34,0.14 2.69,-0.18 3.83,-0.89 0.22,-0.14 0.28,-0.43 0.16,-0.66l-1.47,-2.71zM10.31,13.23L7.93,9.57c-0.2,-0.3 -0.64,-0.3 -0.84,0 -0.81,1.16 -1.17,2.57 -1.05,3.98 0.02,0.26 0.24,0.45 0.5,0.45h3.35c0.39,0 0.63,-0.44 0.42,-0.77zM13.97,12.74l2.02,3.74c0.18,0.33 0.64,0.35 0.86,0.05 0.86,-1.18 1.24,-2.62 1.12,-4.08 -0.02,-0.26 -0.25,-0.45 -0.5,-0.45h-3.05c-0.39,0 -0.63,0.4 -0.45,0.74zM10.17,11.17c0.2,0.31 0.66,0.3 0.85,-0.02l1.94,-3.35c0.19,-0.32 -0.03,-0.72 -0.4,-0.76 -1.36,-0.12 -2.73,0.21 -3.88,0.97 -0.22,0.15 -0.27,0.46 -0.13,0.68l1.62,2.48z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_4_bar.xml b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_4_bar.xml
index 67bef2b..b22cb46 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_4_bar.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_4_bar.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.41,22H21c0.55,0 1,-0.45 1,-1V4.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L3.7,20.3C3.08,20.93 3.52,22 4.41,22z"/>
+ android:pathData="M4.41,22H20c1.1,0 2,-0.9 2,-2V4.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L3.71,20.29c-0.63,0.63 -0.19,1.71 0.7,1.71z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_alt.xml
index 33e150a..fcb1c5d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_alt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.5,4L18.5,4C19.33,4 20,4.67 20,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5l0,0c-0.83,0 -1.5,-0.67 -1.5,-1.5v-13C17,4.67 17.67,4 18.5,4zM6.5,14L6.5,14C7.33,14 8,14.67 8,15.5v3C8,19.33 7.33,20 6.5,20l0,0C5.67,20 5,19.33 5,18.5v-3C5,14.67 5.67,14 6.5,14zM12.5,9L12.5,9c0.83,0 1.5,0.67 1.5,1.5v8c0,0.83 -0.67,1.5 -1.5,1.5l0,0c-0.83,0 -1.5,-0.67 -1.5,-1.5v-8C11,9.67 11.67,9 12.5,9z"/>
+ android:pathData="M18.5,4c0.83,0 1.5,0.67 1.5,1.5v13c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5v-13c0,-0.83 0.67,-1.5 1.5,-1.5zM6.5,14c0.83,0 1.5,0.67 1.5,1.5v3c0,0.83 -0.67,1.5 -1.5,1.5S5,19.33 5,18.5v-3c0,-0.83 0.67,-1.5 1.5,-1.5zM12.5,9c0.83,0 1.5,0.67 1.5,1.5v8c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5v-8c0,-0.83 0.67,-1.5 1.5,-1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_no_sim.xml b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_no_sim.xml
index e0272d8..2a09a3d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_no_sim.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_no_sim.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M1.39,2.81L1.39,2.81C1,3.2 1,3.83 1.39,4.22l3.19,3.19L4,8v12c0,1.1 0.9,2 2,2h12.01c0.34,0 0.65,-0.09 0.92,-0.24l0.85,0.85c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81C2.42,2.42 1.78,2.42 1.39,2.81z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,17.17L19.99,4c0,-1.1 -0.89,-2 -1.99,-2h-8L7.41,4.59L20,17.17z"/>
+ android:pathData="M19,5c0,-1.1 -0.9,-2 -2,-2h-6.17c-0.53,0 -1.04,0.21 -1.42,0.59L7.95,5.06 19,16.11V5zM3.09,4.44c-0.39,0.39 -0.39,1.02 0,1.41L5,7.78V19c0,1.11 0.9,2 2,2h11.23l0.91,0.91c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.5,4.44c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_null.xml b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_null.xml
index 8f98e74..d6e7bed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_null.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_null.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6.83V20H6.83L20,6.83M20.29,3.71L3.71,20.29C3.08,20.92 3.52,22 4.41,22H21c0.55,0 1,-0.45 1,-1V4.41C22,3.52 20.92,3.08 20.29,3.71z"/>
+ android:pathData="M20,6.83V19c0,0.55 -0.45,1 -1,1H6.83L20,6.83m0.29,-3.12L3.71,20.29c-0.63,0.63 -0.19,1.71 0.7,1.71H20c1.1,0 2,-0.9 2,-2V4.41c0,-0.89 -1.08,-1.33 -1.71,-0.7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_off.xml
index 1eaac81..c77a3ed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/signal_cellular_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.29,3.71l-6.88,6.88L22,19.17V4.41C22,3.52 20.92,3.08 20.29,3.71z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.1,4.51L3.1,4.51c-0.39,0.39 -0.39,1.02 0,1.41l7.49,7.49l-6.88,6.88C3.08,20.92 3.52,22 4.41,22h14.76l0.9,0.9c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L4.51,4.51C4.12,4.12 3.49,4.12 3.1,4.51z"/>
+ android:pathData="M21,3.41c0,-0.89 -1.08,-1.34 -1.71,-0.71l-6.6,6.6L21,17.61L21,3.41zM21.44,20.88L5.62,5.06c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l5.66,5.66 -7.16,7.16c-0.63,0.63 -0.19,1.71 0.7,1.71h15.32l1.29,1.29c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.39 0.4,-1.02 0.01,-1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_4_bar.xml b/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_4_bar.xml
index 36c6256..99571e2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_4_bar.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_4_bar.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4C7.7,4 3.78,5.6 0.79,8.24C0.35,8.63 0.32,9.3 0.73,9.71l10.56,10.58c0.39,0.39 1.02,0.39 1.42,0L23.27,9.71c0.41,-0.41 0.38,-1.08 -0.06,-1.47C20.22,5.6 16.3,4 12,4z"/>
+ android:pathData="M23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l10.08,12.56c0.8,1 2.32,1 3.12,0L23.64,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_off.xml
index 1c8db0b..2001792 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/signal_wifi_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M23.21,8.24C20.22,5.6 16.3,4 12,4c-1.58,0 -3.1,0.22 -4.55,0.62l10.46,10.46l5.36,-5.37C23.68,9.3 23.65,8.63 23.21,8.24zM2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22l2.09,2.09c-0.96,0.56 -1.86,1.2 -2.69,1.93C0.35,8.63 0.32,9.3 0.73,9.71l10.56,10.58c0.39,0.39 1.02,0.39 1.42,0l2.38,-2.38l4.7,4.69c0.39,0.39 1.02,0.39 1.41,0s0.39,-1.02 0,-1.41L2.81,2.81z"/>
+ android:pathData="M23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4 -1.32,0 -2.55,0.14 -3.69,0.38L18.43,13.5 23.64,7zM4.12,2.01c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l1.35,1.35C1.91,5.76 0.59,6.82 0.36,7l10.08,12.56c0.8,1 2.32,1 3.12,0l2.35,-2.93 2.61,2.61c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.12,2.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sim_card.xml b/compose/material/material/icons/generator/raw-icons/rounded/sim_card.xml
index 4e75218..9be0267 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sim_card.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sim_card.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.99,4c0,-1.1 -0.89,-2 -1.99,-2h-7.17C10.3,2 9.79,2.21 9.41,2.59L4.59,7.41C4.21,7.79 4,8.3 4,8.83V20c0,1.1 0.9,2 2,2h12.01c1.1,0 1.99,-0.9 1.99,-2L19.99,4zM8,19L8,19c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1l0,0C9,18.55 8.55,19 8,19zM16,19L16,19c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1l0,0C17,18.55 16.55,19 16,19zM8,15L8,15c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v2C9,14.55 8.55,15 8,15zM12,19L12,19c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v2C13,18.55 12.55,19 12,19zM12,13L12,13c-0.55,0 -1,-0.45 -1,-1l0,0c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1l0,0C13,12.55 12.55,13 12,13zM16,15L16,15c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1l0,0c0.55,0 1,0.45 1,1v2C17,14.55 16.55,15 16,15z"/>
+ android:pathData="M19.99,4c0,-1.1 -0.89,-2 -1.99,-2h-7.17c-0.53,0 -1.04,0.21 -1.42,0.59L4.59,7.41C4.21,7.79 4,8.3 4,8.83L4,20c0,1.1 0.9,2 2,2h12.01c1.1,0 1.99,-0.9 1.99,-2l-0.01,-16zM8,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM16,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM8,15c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM12,19c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM12,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM16,15c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/single_bed.xml b/compose/material/material/icons/generator/raw-icons/rounded/single_bed.xml
index a0a8868..b4fddd2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/single_bed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/single_bed.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,10V7c0,-1.1 -0.9,-2 -2,-2H8C6.9,5 6,5.9 6,7v3c-1.1,0 -2,0.9 -2,2v5h1.33l0.51,1.53C5.94,18.81 6.2,19 6.5,19l0,0c0.3,0 0.56,-0.19 0.66,-0.47L7.67,17h8.67l0.51,1.53C16.94,18.81 17.2,19 17.5,19l0,0c0.3,0 0.56,-0.19 0.66,-0.47L18.67,17H20v-5C20,10.9 19.1,10 18,10zM11,10H8V7h3V10zM16,10h-3V7h3V10z"/>
+ android:pathData="M18,10V7c0,-1.1 -0.9,-2 -2,-2H8C6.9,5 6,5.9 6,7v3c-1.1,0 -2,0.9 -2,2v5h1.33l0.51,1.53C5.94,18.81 6.2,19 6.5,19h0c0.3,0 0.56,-0.19 0.66,-0.47L7.67,17h8.67l0.51,1.53C16.94,18.81 17.2,19 17.5,19l0,0c0.3,0 0.56,-0.19 0.66,-0.47L18.67,17H20v-5C20,10.9 19.1,10 18,10zM11,10H8V8c0,-0.55 0.45,-1 1,-1h2V10zM16,10h-3V7h2c0.55,0 1,0.45 1,1V10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/skip_next.xml b/compose/material/material/icons/generator/raw-icons/rounded/skip_next.xml
index de220c4..7c4d464 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/skip_next.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/skip_next.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,7v10c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1h0C16.45,6 16,6.45 16,7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.55,16.96l6.2,-4.13c0.59,-0.4 0.59,-1.27 0,-1.66l-6.2,-4.13C5.89,6.59 5,7.07 5,7.87v8.26C5,16.93 5.89,17.41 6.55,16.96z"/>
+ android:pathData="M7.58,16.89l5.77,-4.07c0.56,-0.4 0.56,-1.24 0,-1.63L7.58,7.11C6.91,6.65 6,7.12 6,7.93v8.14c0,0.81 0.91,1.28 1.58,0.82zM16,7v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/skip_previous.xml b/compose/material/material/icons/generator/raw-icons/rounded/skip_previous.xml
index 22a7766..37bee91 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/skip_previous.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/skip_previous.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,17V7c0,-0.55 -0.45,-1 -1,-1h0C5.45,6 5,6.45 5,7v10c0,0.55 0.45,1 1,1h0C6.55,18 7,17.55 7,17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.45,7.04l-6.2,4.13c-0.59,0.4 -0.59,1.27 0,1.66l6.2,4.13c0.66,0.44 1.55,-0.03 1.55,-0.83V7.87C18,7.07 17.11,6.59 16.45,7.04z"/>
+ android:pathData="M7,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L6,7c0,-0.55 0.45,-1 1,-1zM10.66,12.82l5.77,4.07c0.66,0.47 1.58,-0.01 1.58,-0.82L18.01,7.93c0,-0.81 -0.91,-1.28 -1.58,-0.82l-5.77,4.07c-0.57,0.4 -0.57,1.24 0,1.64z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/slideshow.xml b/compose/material/material/icons/generator/raw-icons/rounded/slideshow.xml
index b2982f8..52b796a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/slideshow.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/slideshow.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM15.19,12.84l-4.15,2.67c-0.67,0.43 -1.54,-0.05 -1.54,-0.84V9.33c0,-0.79 0.88,-1.27 1.54,-0.84l4.15,2.67C15.8,11.55 15.8,12.45 15.19,12.84z"/>
+ android:pathData="M10,9.04v5.92c0,0.42 0.48,0.65 0.81,0.39l3.7,-2.96c0.25,-0.2 0.25,-0.58 0,-0.78l-3.7,-2.96c-0.33,-0.26 -0.81,-0.03 -0.81,0.39zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,6c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/slow_motion_video.xml b/compose/material/material/icons/generator/raw-icons/rounded/slow_motion_video.xml
index b7c029d..c1c015b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/slow_motion_video.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/slow_motion_video.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.98,3.23L10.98,3.23c0,-0.64 -0.59,-1.13 -1.21,-0.98c-1.12,0.26 -2.17,0.7 -3.12,1.3c-0.54,0.34 -0.61,1.1 -0.16,1.55l0,0C6.81,5.42 7.31,5.5 7.7,5.25C8.47,4.76 9.32,4.4 10.23,4.2C10.68,4.1 10.98,3.69 10.98,3.23z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5.07,6.51L5.07,6.51C4.62,6.06 3.86,6.13 3.52,6.67c-0.6,0.94 -1.04,1.99 -1.3,3.12C2.08,10.41 2.57,11 3.21,11h0c0.45,0 0.87,-0.3 0.97,-0.74c0.2,-0.91 0.57,-1.77 1.05,-2.53C5.47,7.34 5.39,6.83 5.07,6.51z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.21,13L3.21,13c-0.64,0 -1.13,0.59 -0.98,1.21c0.26,1.12 0.7,2.17 1.3,3.11c0.34,0.54 1.1,0.61 1.55,0.16l0,0c0.32,-0.32 0.4,-0.83 0.15,-1.21c-0.49,-0.76 -0.85,-1.61 -1.05,-2.53C4.07,13.3 3.66,13 3.21,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.02,3.24L13.02,3.24c0,0.46 0.31,0.87 0.75,0.97c3.55,0.82 6.2,4.01 6.2,7.79s-2.65,6.97 -6.2,7.79c-0.44,0.1 -0.75,0.51 -0.75,0.96v0c0,0.64 0.6,1.13 1.22,0.98c4.43,-1.03 7.73,-5.01 7.73,-9.74s-3.3,-8.71 -7.73,-9.74C13.62,2.11 13.02,2.6 13.02,3.24z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.64,20.45c0.94,0.6 2,1.04 3.12,1.3c0.62,0.14 1.21,-0.35 1.21,-0.98v0c0,-0.45 -0.3,-0.87 -0.74,-0.97c-0.91,-0.2 -1.77,-0.57 -2.53,-1.05c-0.39,-0.25 -0.89,-0.17 -1.21,0.16l0,0C6.04,19.36 6.11,20.11 6.64,20.45z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.04,15.51l4.15,-2.67c0.61,-0.39 0.61,-1.29 0,-1.68l-4.15,-2.67C10.38,8.06 9.5,8.54 9.5,9.33v5.34C9.5,15.46 10.38,15.94 11.04,15.51z"/>
+ android:pathData="M10,8.5v7c0,0.41 0.47,0.65 0.8,0.4l4.67,-3.5c0.27,-0.2 0.27,-0.6 0,-0.8L10.8,8.1c-0.33,-0.25 -0.8,-0.01 -0.8,0.4zM11,3.23c0,-0.64 -0.59,-1.13 -1.21,-0.99 -1.12,0.26 -2.18,0.7 -3.12,1.3 -0.53,0.34 -0.61,1.1 -0.16,1.55 0.32,0.32 0.83,0.4 1.21,0.16 0.77,-0.49 1.62,-0.85 2.54,-1.05 0.44,-0.1 0.74,-0.51 0.74,-0.97zM5.1,6.51c-0.46,-0.45 -1.21,-0.38 -1.55,0.16 -0.6,0.94 -1.04,2 -1.3,3.12 -0.14,0.62 0.34,1.21 0.98,1.21 0.45,0 0.87,-0.3 0.96,-0.74 0.2,-0.91 0.57,-1.77 1.05,-2.53 0.26,-0.39 0.18,-0.9 -0.14,-1.22zM3.23,13c-0.64,0 -1.13,0.59 -0.99,1.21 0.26,1.12 0.7,2.17 1.3,3.12 0.34,0.54 1.1,0.61 1.55,0.16 0.32,-0.32 0.4,-0.83 0.15,-1.21 -0.49,-0.76 -0.85,-1.61 -1.05,-2.53 -0.09,-0.45 -0.5,-0.75 -0.96,-0.75zM6.67,20.45c0.95,0.6 2,1.04 3.12,1.3 0.62,0.14 1.21,-0.35 1.21,-0.98 0,-0.45 -0.3,-0.87 -0.74,-0.96 -0.91,-0.2 -1.77,-0.57 -2.53,-1.05 -0.39,-0.24 -0.89,-0.17 -1.21,0.16 -0.46,0.44 -0.39,1.19 0.15,1.53zM22,12c0,4.73 -3.3,8.71 -7.73,9.74 -0.62,0.15 -1.22,-0.34 -1.22,-0.98 0,-0.46 0.31,-0.86 0.75,-0.97 3.55,-0.82 6.2,-4 6.2,-7.79s-2.65,-6.97 -6.2,-7.79c-0.44,-0.1 -0.75,-0.51 -0.75,-0.97 0,-0.64 0.6,-1.13 1.22,-0.98C18.7,3.29 22,7.27 22,12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/smartphone.xml b/compose/material/material/icons/generator/raw-icons/rounded/smartphone.xml
index d76f897..bd22f2e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/smartphone.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/smartphone.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1 17,1zM17,18H7V6h10V18z"/>
+ android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19H7V5h10v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/smoke_free.xml b/compose/material/material/icons/generator/raw-icons/rounded/smoke_free.xml
index 96fa979..d463c1b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/smoke_free.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/smoke_free.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,15.17L18.83,16h0.67v-3H18V15.17zM14.6,8.65l1.43,0c1.05,0 1.97,0.74 1.97,2.05v0.55c0,0.41 0.34,0.75 0.75,0.75l0,0c0.41,0 0.75,-0.34 0.75,-0.75v-0.89c0,-1.81 -1.6,-3.16 -3.47,-3.16h-1.31c-0.95,0 -1.81,-0.64 -2.02,-1.57c-0.23,-1.04 0.38,-1.88 1.27,-2.12c0.32,-0.08 0.53,-0.38 0.53,-0.71v0c0,-0.51 -0.5,-0.86 -0.99,-0.71c-1.42,0.43 -2.43,1.78 -2.36,3.35C11.23,7.26 12.8,8.65 14.6,8.65zM20.5,16H22v-3h-1.5V16zM18.85,4.73c0.4,-0.4 0.71,-0.86 0.87,-1.43c0.13,-0.48 -0.23,-0.95 -0.73,-0.95h0c-0.33,0 -0.63,0.21 -0.71,0.52c-0.17,0.6 -0.62,1.06 -1.2,1.24c-0.34,0.11 -0.58,0.42 -0.58,0.78v0.06c0,0.41 0.3,0.74 0.7,0.81c1.9,0.34 3.3,2.01 3.3,4.01v1.48c0,0.41 0.34,0.75 0.75,0.75l0,0c0.41,0 0.75,-0.34 0.75,-0.75V9.76C22,7.54 20.72,5.62 18.85,4.73zM2.1,4.93L10.17,13H3.5C2.67,13 2,13.67 2,14.5S2.67,16 3.5,16h9.67l5.9,5.9c0.39,0.39 1.02,0.39 1.41,0v0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1.71,3.9 1.71,4.54 2.1,4.93zM17,14.17V13h-1.17L17,14.17z"/>
+ android:pathData="M20.5,13L22,13v3h-1.5zM18,13h1.5v3L18,16zM17,14.5c0,-0.83 -0.67,-1.5 -1.5,-1.5h-0.84l2.18,2.18c0.1,-0.21 0.16,-0.44 0.16,-0.68zM18.96,2.35L19,2.35h-0.04zM18.85,4.73c0.38,-0.38 0.67,-0.84 0.84,-1.35 0.16,-0.5 -0.19,-1.01 -0.71,-1.02 -0.34,0.01 -0.61,0.25 -0.72,0.58 -0.18,0.55 -0.62,0.99 -1.17,1.17 -0.34,0.11 -0.59,0.39 -0.59,0.74L16.5,5c0,0.37 0.27,0.69 0.64,0.75 1.93,0.31 3.36,2 3.36,4.02v1.48c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75L22,9.76c0,-2.22 -1.28,-4.14 -3.15,-5.03zM14.61,8.65h1.42c1.05,0 1.97,0.74 1.97,2.05v0.55c0,0.41 0.33,0.75 0.75,0.75h0.01c0.41,0 0.75,-0.33 0.75,-0.75v-0.89c0,-1.81 -1.6,-3.16 -3.47,-3.16h-1.3c-1.02,0 -1.94,-0.73 -2.07,-1.75 -0.12,-0.95 0.46,-1.7 1.3,-1.93 0.32,-0.09 0.54,-0.38 0.54,-0.72 0,-0.49 -0.46,-0.86 -0.93,-0.72 -1.42,0.41 -2.45,1.73 -2.42,3.28 0.02,1.85 1.61,3.29 3.45,3.29zM4.12,5.29c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L9,13L3.5,13c-0.83,0 -1.5,0.67 -1.5,1.5S2.67,16 3.5,16L12,16l6.29,6.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.12,5.29z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/smoking_rooms.xml b/compose/material/material/icons/generator/raw-icons/rounded/smoking_rooms.xml
index 45d6b58..83a2e2c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/smoking_rooms.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/smoking_rooms.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,16H3.5C2.67,16 2,16.67 2,17.5S2.67,19 3.5,19H17V16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.85,7.73c0.62,-0.61 1,-1.45 1,-2.38c0,-1.51 -1,-2.79 -2.38,-3.21C16.99,2 16.5,2.36 16.5,2.86c0,0.33 0.21,0.62 0.52,0.71c0.77,0.23 1.33,0.94 1.33,1.78c0,0.82 -0.53,1.51 -1.27,1.76C16.75,7.22 16.5,7.5 16.5,7.85V8c0,0.37 0.27,0.69 0.64,0.75c1.93,0.31 3.36,2 3.36,4.02v1.48c0,0.41 0.34,0.75 0.75,0.75S22,14.66 22,14.25v-1.49C22,10.54 20.72,8.62 18.85,7.73z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16.03,10.2h-1.3c-1.02,0 -1.94,-0.73 -2.07,-1.75c-0.12,-0.95 0.46,-1.7 1.3,-1.93c0.32,-0.09 0.54,-0.38 0.54,-0.72c0,-0.49 -0.46,-0.86 -0.93,-0.72c-1.42,0.41 -2.45,1.73 -2.42,3.28c0.03,1.84 1.62,3.29 3.46,3.29h1.42c1.05,0 1.97,0.74 1.97,2.05v0.55c0,0.41 0.33,0.75 0.75,0.75h0.01c0.41,0 0.75,-0.33 0.75,-0.75v-0.89C19.5,11.55 17.9,10.2 16.03,10.2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,16h1.5v3h-1.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20.5,16h1.5v3h-1.5z"/>
+ android:pathData="M15.5,16h-12c-0.83,0 -1.5,0.67 -1.5,1.5S2.67,19 3.5,19h12c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5zM18.85,7.73c0.62,-0.61 1,-1.45 1,-2.38 0,-1.51 -1,-2.79 -2.38,-3.21 -0.48,-0.14 -0.97,0.22 -0.97,0.72 0,0.33 0.21,0.62 0.52,0.71 0.77,0.23 1.33,0.94 1.33,1.78 0,0.82 -0.53,1.51 -1.27,1.76 -0.33,0.11 -0.58,0.39 -0.58,0.74L16.5,8c0,0.37 0.27,0.69 0.64,0.75 1.93,0.31 3.36,2 3.36,4.02v1.48c0,0.41 0.34,0.75 0.75,0.75s0.75,-0.34 0.75,-0.75v-1.49c0,-2.22 -1.28,-4.14 -3.15,-5.03zM16.03,10.2h-1.3c-1.02,0 -1.94,-0.73 -2.07,-1.75 -0.12,-0.95 0.46,-1.7 1.3,-1.93 0.32,-0.09 0.54,-0.38 0.54,-0.72 0,-0.49 -0.46,-0.86 -0.93,-0.72 -1.42,0.41 -2.45,1.73 -2.42,3.28 0.03,1.84 1.62,3.29 3.46,3.29h1.42c1.05,0 1.97,0.74 1.97,2.05v0.55c0,0.41 0.33,0.75 0.75,0.75h0.01c0.41,0 0.75,-0.33 0.75,-0.75v-0.89c-0.01,-1.81 -1.61,-3.16 -3.48,-3.16zM18,16h1.5v3L18,19zM20.5,16L22,16v3h-1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sms.xml b/compose/material/material/icons/generator/raw-icons/rounded/sms.xml
index 5cebe5f..9479c61 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sms.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sms.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2.01,2.9 2.01,4L2,19.58c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM8,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S8.55,11 8,11zM12,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,11 12,11zM16,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S16.55,11 16,11z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM9,11L7,11L7,9h2v2zM13,11h-2L11,9h2v2zM17,11h-2L15,9h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sms_failed.xml b/compose/material/material/icons/generator/raw-icons/rounded/sms_failed.xml
index ac286e6..24d52ef 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sms_failed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sms_failed.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2,2.9 2,4v15.59c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM12,11c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4C13,10.55 12.55,11 12,11zM12,15L12,15c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C13,14.55 12.55,15 12,15z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM13,14h-2v-2h2v2zM12,10c-0.55,0 -1,-0.45 -1,-1L11,7c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/snooze.xml b/compose/material/material/icons/generator/raw-icons/rounded/snooze.xml
index 32851c7..c77cdc2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/snooze.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/snooze.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c4.97,0 9,-4.03 9,-9S16.97,4 12,4zM13.75,14.5c0.41,0 0.75,0.34 0.75,0.75S14.16,16 13.75,16h-3.32c-0.52,0 -0.93,-0.42 -0.93,-0.93c0,-0.23 0.08,-0.45 0.23,-0.62l2.6,-2.95h-2.09c-0.41,0 -0.75,-0.34 -0.75,-0.75S9.84,10 10.25,10h3.29c0.53,0 0.96,0.43 0.96,0.96c0,0.23 -0.09,0.46 -0.24,0.63l-2.57,2.91H13.75z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.29,4.46c0.39,-0.39 0.39,-1.02 0,-1.41c-0.39,-0.39 -1.02,-0.39 -1.41,0L2.05,5.88c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0L6.29,4.46z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.95,5.88l-2.83,-2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0v0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0v0C22.34,6.9 22.34,6.27 21.95,5.88z"/>
+ android:pathData="M10,11h2.63l-3.72,4.35C8.36,16 8.82,17 9.67,17L14,17c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2.63l3.72,-4.35c0.55,-0.65 0.09,-1.65 -0.76,-1.65L10,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM21.3,6.42c-0.35,0.42 -0.98,0.48 -1.41,0.13l-3.07,-2.56c-0.42,-0.36 -0.48,-0.99 -0.12,-1.41 0.35,-0.42 0.98,-0.48 1.41,-0.13l3.07,2.56c0.42,0.36 0.48,0.99 0.12,1.41zM2.7,6.42c0.35,0.43 0.98,0.48 1.4,0.13l3.07,-2.56c0.43,-0.36 0.49,-0.99 0.13,-1.41 -0.35,-0.43 -0.98,-0.48 -1.4,-0.13L2.82,5.01c-0.42,0.36 -0.48,0.99 -0.12,1.41zM12,6c3.86,0 7,3.14 7,7s-3.14,7 -7,7 -7,-3.14 -7,-7 3.14,-7 7,-7m0,-2c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sort.xml b/compose/material/material/icons/generator/raw-icons/rounded/sort.xml
index 72e118a..28d006e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sort.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sort.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h4c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,17.55 3.45,18 4,18zM3,7L3,7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4C3.45,6 3,6.45 3,7zM4,13h10c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1l0,0C3,12.55 3.45,13 4,13z"/>
+ android:pathData="M4,18h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,16c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,7c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,6c-0.55,0 -1,0.45 -1,1zM4,13h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sort_by_alpha.xml b/compose/material/material/icons/generator/raw-icons/rounded/sort_by_alpha.xml
index b6e6019..5dd7bd1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sort_by_alpha.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sort_by_alpha.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.17,15.7L8.29,8.02C8.06,7.4 7.48,7 6.83,7h0C6.17,7 5.59,7.41 5.36,8.02L2.49,15.7C2.25,16.33 2.72,17 3.39,17h0c0.41,0 0.77,-0.26 0.91,-0.65l0.61,-1.74h3.83l0.6,1.74C9.49,16.74 9.86,17 10.27,17h0C10.94,17 11.41,16.33 11.17,15.7zM5.52,12.88l1.25,-3.71h0.11l1.24,3.71H5.52zM15.93,15.21l4.7,-5.93c0.2,-0.25 0.31,-0.56 0.31,-0.88v0c0,-0.78 -0.63,-1.41 -1.41,-1.41H14.8c-0.49,0 -0.89,0.4 -0.89,0.89v0c0,0.49 0.4,0.89 0.89,0.89h3.95l-4.76,5.92c-0.2,0.25 -0.31,0.56 -0.31,0.88v0c0,0.78 0.63,1.41 1.41,1.41h5.02C20.6,17 21,16.6 21,16.11v0c0,-0.49 -0.4,-0.89 -0.89,-0.89H15.93zM11.65,2.35L9.85,4.15C9.54,4.46 9.76,5 10.21,5h3.59c0.45,0 0.67,-0.54 0.35,-0.85l-1.79,-1.79C12.16,2.16 11.84,2.16 11.65,2.35zM12.35,21.65l1.79,-1.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85h-3.59c-0.45,0 -0.67,0.54 -0.35,0.85l1.79,1.79C11.84,21.84 12.16,21.84 12.35,21.65z"/>
+ android:pathData="M12.93,2.65c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.01,2.01h4.72l-2,-2.01zM12.23,21.35c0.2,0.2 0.51,0.2 0.71,0l1.98,-1.98h-4.66l1.97,1.98zM10.98,17.73c0.6,0 1.01,-0.6 0.79,-1.16L8.04,7.03c-0.18,-0.46 -0.63,-0.76 -1.12,-0.76 -0.49,0 -0.94,0.3 -1.12,0.76l-3.74,9.53c-0.22,0.56 0.19,1.16 0.79,1.16 0.35,0 0.67,-0.22 0.8,-0.55l0.71,-1.9h5.11l0.71,1.9c0.13,0.34 0.45,0.56 0.8,0.56zM4.97,13.64l1.94,-5.18 1.94,5.18L4.97,13.64zM21.05,16.14h-5.33l5.72,-8.29c0.46,-0.66 -0.02,-1.57 -0.82,-1.57h-6.48c-0.44,0 -0.79,0.36 -0.79,0.8v0.01c0,0.44 0.36,0.8 0.79,0.8h5.09l-5.73,8.28c-0.46,0.66 0.02,1.57 0.82,1.57h6.72c0.44,0 0.79,-0.36 0.79,-0.79 0.02,-0.45 -0.34,-0.81 -0.78,-0.81z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/soup_kitchen.xml b/compose/material/material/icons/generator/raw-icons/rounded/soup_kitchen.xml
new file mode 100644
index 0000000..340f483
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/soup_kitchen.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.15,13.5c-0.46,0 -0.8,-0.42 -0.71,-0.87C5.48,12.45 5.5,12.24 5.5,12c0,-1 -1,-2.85 -1,-3.62c0,-0.29 0.03,-0.59 0.17,-0.93C4.78,7.18 5.04,7 5.34,7c0.45,0 0.8,0.42 0.71,0.86C6.01,8.04 6,8.21 6,8.38C6,9.15 7,11 7,12c0,0.42 -0.08,0.76 -0.17,1.01C6.73,13.31 6.46,13.5 6.15,13.5zM12.65,13.5c0.31,0 0.58,-0.19 0.68,-0.49c0.09,-0.25 0.17,-0.59 0.17,-1.01c0,-1 -1,-2.85 -1,-3.62c0,-0.17 0.01,-0.34 0.04,-0.51C12.63,7.42 12.29,7 11.84,7c-0.29,0 -0.56,0.18 -0.67,0.45C11.03,7.79 11,8.08 11,8.38C11,9.15 12,11 12,12c0,0.24 -0.02,0.45 -0.06,0.63C11.85,13.08 12.19,13.5 12.65,13.5zM9.4,13.5c0.31,0 0.58,-0.19 0.68,-0.49c0.09,-0.25 0.17,-0.59 0.17,-1.01c0,-1 -1,-2.85 -1,-3.62c0,-0.17 0.01,-0.34 0.04,-0.51C9.38,7.42 9.04,7 8.59,7C8.29,7 8.03,7.18 7.92,7.45C7.78,7.79 7.75,8.08 7.75,8.38c0,0.77 1,2.63 1,3.62c0,0.24 -0.02,0.45 -0.06,0.63C8.6,13.08 8.94,13.5 9.4,13.5zM20.46,6.37c0.57,0.07 1.08,-0.34 1.12,-0.91C21.59,5.28 21.6,5.12 21.6,5c0,-1.65 -1.35,-3 -3,-3c-1.54,0 -2.81,1.16 -2.98,2.65L14.53,15H3.99c-0.6,0 -1.07,0.54 -0.98,1.14C3.54,19.46 6.39,22 9.75,22c3.48,0 6.34,-2.73 6.71,-6.23l1.15,-10.87C17.66,4.39 18.08,4 18.6,4c0.55,0 1,0.45 1,1c0,0.07 -0.01,0.18 -0.01,0.31C19.55,5.84 19.93,6.3 20.46,6.37L20.46,6.37z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/south_america.xml b/compose/material/material/icons/generator/raw-icons/rounded/south_america.xml
new file mode 100644
index 0000000..ca13a97
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/south_america.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM4,12c0,-1.95 0.7,-3.74 1.87,-5.13L9,10v1c0,1.1 0.9,2 2,2v5.59c0,0.27 0.11,0.52 0.29,0.71L12,20C7.58,20 4,16.42 4,12zM13,19.94V18l3.75,-5.62c0.16,-0.25 0.25,-0.54 0.25,-0.83V10.5c0,-0.55 -0.45,-1 -1,-1h-1.5l-1.4,-1.75C12.72,7.28 12.15,7 11.54,7H8V5.07C9.18,4.39 10.54,4 12,4c4.41,0 8,3.59 8,8C20,16.07 16.94,19.44 13,19.94z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/spa.xml b/compose/material/material/icons/generator/raw-icons/rounded/spa.xml
index 957bc3c..db7c51d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/spa.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/spa.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.85,10.08c-2.1,0.27 -5.46,1.3 -7.66,4.31c1,1.79 1.66,4.03 1.77,6.82c3.09,-1.16 6.61,-3.9 7,-10.06C22,10.53 21.47,10 20.85,10.08z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.01,12.63c1.09,-1.33 2.39,-2.32 3.74,-3.03c-0.57,-2.88 -2.02,-5.26 -2.94,-6.56c-0.4,-0.56 -1.22,-0.56 -1.62,0C10.27,4.34 8.82,6.73 8.25,9.6C9.6,10.32 10.91,11.3 12.01,12.63z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.04,11.15c0.52,8.23 6.63,10.37 9.82,10.77c0.62,0.08 1.15,-0.45 1.11,-1.08c-0.52,-8.23 -6.64,-10.36 -9.82,-10.76C2.52,10 2,10.53 2.04,11.15z"/>
+ android:pathData="M15.49,9.63c-0.16,-2.42 -1.03,-4.79 -2.64,-6.76 -0.41,-0.5 -1.16,-0.5 -1.57,0 -1.65,1.98 -2.57,4.35 -2.77,6.76 1.28,0.68 2.46,1.56 3.49,2.63 1.03,-1.06 2.21,-1.94 3.49,-2.63zM8.99,12.28c-0.14,-0.1 -0.3,-0.19 -0.45,-0.29 0.15,0.11 0.31,0.19 0.45,0.29zM15.41,12.03c-0.13,0.09 -0.27,0.16 -0.4,0.26 0.13,-0.1 0.27,-0.17 0.4,-0.26zM12,15.45c-1.95,-2.97 -5.14,-5.03 -8.83,-5.39 -0.64,-0.06 -1.17,0.47 -1.11,1.11 0.45,4.8 3.65,8.78 7.98,10.33 0.63,0.23 1.29,0.4 1.97,0.51 0.68,-0.12 1.33,-0.29 1.97,-0.51 4.33,-1.55 7.53,-5.52 7.98,-10.33 0.06,-0.64 -0.48,-1.17 -1.11,-1.11 -3.71,0.36 -6.9,2.42 -8.85,5.39z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/space_bar.xml b/compose/material/material/icons/generator/raw-icons/rounded/space_bar.xml
index 49dc161..95320d7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/space_bar.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/space_bar.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,10v3H6v-3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1l0,0C18.45,9 18,9.45 18,10z"/>
+ android:pathData="M18,10v3H6v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/space_dashboard.xml b/compose/material/material/icons/generator/raw-icons/rounded/space_dashboard.xml
new file mode 100644
index 0000000..3201869
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/space_dashboard.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,21H5c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h4c1.1,0 2,0.9 2,2v14C11,20.1 10.1,21 9,21zM15,21h4c1.1,0 2,-0.9 2,-2v-5c0,-1.1 -0.9,-2 -2,-2h-4c-1.1,0 -2,0.9 -2,2v5C13,20.1 13.9,21 15,21zM21,8V5c0,-1.1 -0.9,-2 -2,-2h-4c-1.1,0 -2,0.9 -2,2v3c0,1.1 0.9,2 2,2h4C20.1,10 21,9.1 21,8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/speaker.xml b/compose/material/material/icons/generator/raw-icons/rounded/speaker.xml
index c682611..c5604ee 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/speaker.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/speaker.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,2H7C5.9,2 5,2.9 5,4v16c0,1.1 0.9,1.99 2,1.99L17,22c1.1,0 2,-0.9 2,-2V4C19,2.9 18.1,2 17,2zM12,5c1.1,0 2,0.9 2,2s-0.9,2 -2,2c-1.11,0 -2,-0.9 -2,-2S10.89,5 12,5zM12,19c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4s4,1.79 4,4S14.21,19 12,19zM12,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,13 12,13z"/>
+ android:pathData="M17,2L7,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,1.99 2,1.99L17,22c1.1,0 2,-0.9 2,-2L19,4c0,-1.1 -0.9,-2 -2,-2zM12,4c1.1,0 2,0.9 2,2s-0.9,2 -2,2c-1.11,0 -2,-0.9 -2,-2s0.89,-2 2,-2zM12,20c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/speaker_group.xml b/compose/material/material/icons/generator/raw-icons/rounded/speaker_group.xml
index 7422d79..7159b97 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/speaker_group.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/speaker_group.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,5L5,5C4.45,5 4,5.45 4,6v15c0,1.1 0.9,2 2,2h9c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H6V6C6,5.45 5.55,5 5,5z"/>
+ android:pathData="M18.2,1L9.8,1C8.81,1 8,1.81 8,2.8v14.4c0,0.99 0.81,1.79 1.8,1.79l8.4,0.01c0.99,0 1.8,-0.81 1.8,-1.8L20,2.8c0,-0.99 -0.81,-1.8 -1.8,-1.8zM14,3c1.1,0 2,0.89 2,2s-0.9,2 -2,2 -2,-0.89 -2,-2 0.9,-2 2,-2zM14,16.5c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M14.5,12.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ android:pathData="M14,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19,1h-9C8.9,1 8,1.9 8,3v13.99c0,1.1 0.89,2 2,2L19,19c1.1,0 2,-0.9 2,-2V3C21,1.9 20.1,1 19,1zM14.5,4.5C15.33,4.5 16,5.17 16,6s-0.67,1.5 -1.5,1.5S13,6.83 13,6S13.67,4.5 14.5,4.5zM14.5,16c-1.93,0 -3.5,-1.57 -3.5,-3.5S12.57,9 14.5,9s3.5,1.57 3.5,3.5S16.43,16 14.5,16z"/>
+ android:pathData="M5,5c-0.55,0 -1,0.45 -1,1v15c0,1.1 0.89,2 2,2h9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H7c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes.xml b/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes.xml
index 85fee45..05db2a3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2.01,2.9 2.01,4L2,19.58c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM7,14L7,14c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C8,13.55 7.55,14 7,14zM7,11L7,11c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C8,10.55 7.55,11 7,11zM7,8L7,8C6.45,8 6,7.55 6,7v0c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v0C8,7.55 7.55,8 7,8zM14,14h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3c0.55,0 1,0.45 1,1S14.55,14 14,14zM17,11h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1S17.55,11 17,11zM17,8h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1S17.55,8 17,8z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM8,14L6,14v-2h2v2zM8,11L6,11L6,9h2v2zM8,8L6,8L6,6h2v2zM14,14h-3c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h3c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,11h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,8h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes_off.xml
index 2b3a955..ae6439e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/speaker_notes_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2.74,2.81c-0.38,-0.38 -0.99,-0.38 -1.37,0c-0.38,0.38 -0.38,0.99 0,1.37l0.64,0.64L2,19.56c0,0.89 1.08,1.34 1.71,0.71L6,17.98h9.17l4.61,4.61c0.39,0.39 1.02,0.39 1.41,0s0.39,-1.02 0,-1.41L2.74,2.81zM6.4,9.2l1.38,1.38c-0.18,0.23 -0.46,0.4 -0.78,0.4c-0.55,0 -1,-0.45 -1,-1C6,9.66 6.16,9.39 6.4,9.2zM7,13.98c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S7.55,13.98 7,13.98z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H4.83l5.22,5.22C10.03,7.14 10,7.08 10,7c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-6c-0.08,0 -0.14,-0.03 -0.22,-0.04L11.83,9H17c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-3.17l6.87,6.87C21.45,17.58 22,16.85 22,16V4C22,2.9 21.1,2 20,2z"/>
+ android:pathData="M1.91,2.36c-0.35,-0.35 -0.92,-0.35 -1.27,0s-0.35,0.92 0,1.27l1.38,1.38L2,22l4,-4h9l5.09,5.09c0.35,0.35 0.92,0.35 1.27,0s0.35,-0.92 0,-1.27L1.91,2.36zM7,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM7,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM20,2L4.08,2l7,7L17,9c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-3.92l6.99,6.99C21.14,17.95 22,17.08 22,16L22,4c0,-1.1 -0.9,-2 -2,-2zM17,8h-6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h6c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/speed.xml b/compose/material/material/icons/generator/raw-icons/rounded/speed.xml
index 9640e5e..0c1f5b0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/speed.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/speed.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.59,15.41c0.78,0.78 2.05,0.78 2.83,0c0.53,-0.53 2.91,-4.22 4.39,-6.53c0.29,-0.45 -0.24,-0.98 -0.69,-0.69c-2.31,1.48 -6,3.86 -6.53,4.39C9.8,13.37 9.8,14.63 10.59,15.41z"/>
+ android:pathData="M19.46,10a1,1 0,0 0,-0.07 1,7.55 7.55,0 0,1 0.52,1.81 8,8 0,0 1,-0.69 4.73,1 1,0 0,1 -0.89,0.53H5.68a1,1 0,0 1,-0.89 -0.54A8,8 0,0 1,13 6.06a7.69,7.69 0,0 1,2.11 0.56,1 1,0 0,0 1,-0.07 1,1 0,0 0,-0.17 -1.76A10,10 0,0 0,3.35 19a2,2 0,0 0,1.72 1h13.85a2,2 0,0 0,1.74 -1,10 10,0 0,0 0.55,-8.89 1,1 0,0 0,-1.75 -0.11z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M19.46,10.01c0,0.01 -0.01,0.02 -0.01,0.02c-0.18,0.28 -0.19,0.63 -0.07,0.93c0.38,0.91 0.61,1.9 0.62,2.93c0.02,1.45 -0.36,2.87 -1.09,4.1L5.09,18.02C4.38,16.8 4,15.41 4,14c0,-4.41 3.59,-8 8,-8c0.07,0 0.15,0 0.23,0c0.99,0.03 1.93,0.25 2.81,0.61c0.31,0.13 0.66,0.11 0.94,-0.07c0.01,0 0.01,-0.01 0.02,-0.01c0.67,-0.43 0.58,-1.43 -0.15,-1.75c-1.1,-0.47 -2.3,-0.75 -3.56,-0.79C12.19,4 12.09,4 12,4C6.48,4 2,8.48 2,14c0,1.84 0.5,3.56 1.37,5.03C3.73,19.64 4.39,20 5.09,20l13.82,0c0.7,0 1.36,-0.36 1.72,-0.97c0.89,-1.51 1.39,-3.27 1.37,-5.16c-0.02,-1.3 -0.3,-2.55 -0.79,-3.7C20.9,9.43 19.89,9.34 19.46,10.01z"/>
+ android:pathData="M10.59,12.59a2,2 0,0 0,2.83 2.83l5.66,-8.49z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/spellcheck.xml b/compose/material/material/icons/generator/raw-icons/rounded/spellcheck.xml
index f77ea11..a5f5e8f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/spellcheck.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/spellcheck.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.88,14.22l-4.95,4.95l-2.12,-2.12c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l2.83,2.83c0.39,0.39 1.02,0.39 1.41,0l5.66,-5.66c0.39,-0.39 0.39,-1.02 0,-1.41v0C19.9,13.83 19.27,13.83 18.88,14.22z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.58,16L13.58,16c0.73,0 1.24,-0.73 0.98,-1.41l-3.94,-10.5C10.37,3.43 9.74,3 9.05,3h0c-0.7,0 -1.32,0.43 -1.57,1.09l-3.94,10.5C3.27,15.27 3.78,16 4.51,16h0c0.44,0 0.84,-0.28 0.99,-0.7l0.93,-2.63h5.25l0.92,2.62C12.74,15.72 13.14,16 13.58,16zM7.1,10.79l1.89,-5.37H9.1l1.89,5.37H7.1z"/>
+ android:pathData="M13.12,16c0.69,0 1.15,-0.69 0.9,-1.32L9.77,3.87C9.56,3.34 9.06,3 8.5,3s-1.06,0.34 -1.27,0.87L2.98,14.68c-0.25,0.63 0.22,1.32 0.9,1.32 0.4,0 0.76,-0.25 0.91,-0.63L5.67,13h5.64l0.9,2.38c0.15,0.37 0.51,0.62 0.91,0.62zM6.43,11L8.5,5.48 10.57,11L6.43,11zM20.89,12.29l-7.39,7.39 -2.97,-2.97c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l3.68,3.68c0.39,0.39 1.02,0.39 1.41,0l8.08,-8.09c0.39,-0.39 0.39,-1.02 0,-1.41 -0.38,-0.39 -1.02,-0.39 -1.4,-0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/spoke.xml b/compose/material/material/icons/generator/raw-icons/rounded/spoke.xml
new file mode 100644
index 0000000..b271345
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/spoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,7c0,2.21 -1.79,4 -4,4S8,9.21 8,7s1.79,-4 4,-4S16,4.79 16,7zM7,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.21,13 7,13zM17,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S19.21,13 17,13z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports.xml
index a45e879..44374f1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,7H11C9.39,7 7.93,7.64 6.85,8.67C6.51,7.7 5.59,7 4.5,7C3.12,7 2,8.12 2,9.5S3.12,12 4.5,12c0.21,0 0.41,-0.03 0.6,-0.08C5.04,12.27 5,12.63 5,13c0,3.31 2.69,6 6,6s6,-2.69 6,-6c0,-0.7 0,-2 0,-2h4c0.55,0 1,-0.45 1,-1V8C22,7.45 21.55,7 21,7zM4.5,10.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S5.05,10.5 4.5,10.5zM11,16.5c-1.93,0 -3.5,-1.57 -3.5,-3.5S9.07,9.5 11,9.5s3.5,1.57 3.5,3.5S12.93,16.5 11,16.5z"/>
+ android:pathData="M21,6h-9.77C9.57,6 8.01,6.66 6.87,7.73C6.54,6.73 5.61,6 4.5,6C3.12,6 2,7.12 2,8.5C2,9.88 3.12,11 4.5,11c0.21,0 0.41,-0.03 0.61,-0.08c-0.05,0.25 -0.09,0.51 -0.1,0.78c-0.18,3.68 2.95,6.68 6.68,6.27c2.55,-0.28 4.68,-2.26 5.19,-4.77c0.15,-0.71 0.15,-1.4 0.06,-2.06c-0.09,-0.6 0.38,-1.13 0.99,-1.13l2.76,0C21.56,10 22,9.55 22,9V7C22,6.45 21.55,6 21,6zM4.5,9C4.22,9 4,8.78 4,8.5C4,8.22 4.22,8 4.5,8S5,8.22 5,8.5C5,8.78 4.78,9 4.5,9zM11,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S12.66,15 11,15z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,13m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M11,12m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_cricket.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_cricket.xml
index 9583d1a..5c402b9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_cricket.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_cricket.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.02,12.78L6.53,4.29c-0.39,-0.39 -1.02,-0.39 -1.41,0L2.29,7.12c-0.39,0.39 -0.39,1.02 0,1.41l8.49,8.49c0.39,0.39 1.02,0.39 1.41,0l2.83,-2.83C15.41,13.8 15.41,13.17 15.02,12.78z"/>
+ android:pathData="M15.05,12.81L6.56,4.32c-0.39,-0.39 -1.02,-0.39 -1.41,0L2.32,7.15c-0.39,0.39 -0.39,1.02 0,1.41l8.49,8.49c0.39,0.39 1.02,0.39 1.41,0l2.83,-2.83C15.44,13.83 15.44,13.2 15.05,12.81z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M14.34,17.76l3.54,3.54c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-3.54,-3.54L14.34,17.76z"/>
+ android:pathData="M14.34,17.76l3.53,3.53c0.39,0.39 1.03,0.39 1.42,0l0,0c0.39,-0.39 0.39,-1.03 0,-1.42l-3.53,-3.53L14.34,17.76z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M18.5,5.5m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_esports.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_esports.xml
index 80647e5..ee0e0f8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_esports.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_esports.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.97,15.94l-1.07,-7.5C20.62,6.46 18.93,5 16.93,5H7.06c-2,0 -3.69,1.46 -3.97,3.44l-1.07,7.49C1.81,17.48 2.95,18.99 4.52,19c0.68,0 1.33,-0.27 1.81,-0.75L8.6,16h6.8l2.25,2.25c0.84,0.84 2.2,1.04 3.27,0.28C21.74,17.95 22.11,16.92 21.97,15.94zM10.25,11.25h-1v1C9.25,12.66 8.91,13 8.5,13h0c-0.41,0 -0.75,-0.34 -0.75,-0.75v-1h-1C6.34,11.25 6,10.91 6,10.5v0c0,-0.41 0.34,-0.75 0.75,-0.75h1v-1C7.75,8.34 8.09,8 8.5,8h0c0.41,0 0.75,0.34 0.75,0.75v1h1c0.41,0 0.75,0.34 0.75,0.75v0C11,10.91 10.66,11.25 10.25,11.25zM15,10c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S15.55,10 15,10zM17,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S17.55,13 17,13z"/>
+ android:pathData="M21.58,16.09l-1.09,-7.66C20.21,6.46 18.52,5 16.53,5H7.47C5.48,5 3.79,6.46 3.51,8.43l-1.09,7.66C2.2,17.63 3.39,19 4.94,19h0c0.68,0 1.32,-0.27 1.8,-0.75L9,16h6l2.25,2.25c0.48,0.48 1.13,0.75 1.8,0.75h0C20.61,19 21.8,17.63 21.58,16.09zM11,11H9v2H8v-2H6v-1h2V8h1v2h2V11zM15,10c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C16,9.55 15.55,10 15,10zM17,13c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C18,12.55 17.55,13 17,13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_football.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_football.xml
index 91d3f69..66483c0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_football.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_football.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3.01,15.62c-0.08,2.42 0.32,4.34 0.67,4.69c0.35,0.35 2.28,0.76 4.7,0.67L3.01,15.62z"/>
+ android:pathData="M3.02,15.62c-0.08,2.42 0.32,4.34 0.67,4.69s2.28,0.76 4.69,0.67L3.02,15.62z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M13.08,3.27c-2.33,0.42 -4.8,1.34 -6.63,3.18s-2.76,4.29 -3.18,6.63l7.64,7.64c2.34,-0.41 4.8,-1.34 6.63,-3.18c1.83,-1.84 2.76,-4.29 3.18,-6.63L13.08,3.27zM9.2,14.8L9.2,14.8c-0.39,-0.39 -0.39,-1.01 0,-1.4l4.2,-4.2c0.39,-0.39 1.01,-0.39 1.4,0l0,0c0.39,0.39 0.39,1.01 0,1.4l-4.2,4.2C10.21,15.19 9.58,15.19 9.2,14.8z"/>
+ android:pathData="M13.08,3.28C10.75,3.7 8.29,4.62 6.46,6.46s-2.76,4.29 -3.18,6.62l7.63,7.63c2.34,-0.41 4.79,-1.34 6.62,-3.18s2.76,-4.29 3.18,-6.62L13.08,3.28zM14.8,10.6l-4.2,4.2c-0.39,0.39 -1.01,0.39 -1.4,0s-0.39,-1.01 0,-1.4l4.2,-4.2c0.39,-0.39 1.01,-0.39 1.4,0S15.19,10.21 14.8,10.6z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M20.99,8.38c0.08,-2.42 -0.32,-4.34 -0.67,-4.69c-0.35,-0.35 -2.28,-0.76 -4.7,-0.67L20.99,8.38z"/>
+ android:pathData="M20.98,8.38c0.08,-2.42 -0.32,-4.34 -0.67,-4.69s-2.28,-0.76 -4.69,-0.67L20.98,8.38z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_golf.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_golf.xml
index fd208e6..89e3cfa 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_golf.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_golf.xml
@@ -6,7 +6,7 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,16c3.87,0 7,-3.13 7,-7s-3.13,-7 -7,-7S5,5.13 5,9S8.13,16 12,16zM12,4c2.76,0 5,2.24 5,5s-2.24,5 -5,5s-5,-2.24 -5,-5S9.24,4 12,4z"/>
+ android:pathData="M12,16c3.87,0 7,-3.13 7,-7c0,-3.87 -3.13,-7 -7,-7C8.13,2 5,5.13 5,9C5,12.87 8.13,16 12,16zM12,4c2.76,0 5,2.24 5,5s-2.24,5 -5,5s-5,-2.24 -5,-5S9.24,4 12,4z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M10,8m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
@@ -18,5 +18,5 @@
android:pathData="M12,6m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M16,17H8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1c1.1,0 2,0.9 2,2v1h2v-1c0,-1.1 0.9,-2 2,-2h1c0.55,0 1,-0.45 1,-1S16.55,17 16,17z"/>
+ android:pathData="M16,17H8c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h1c1.1,0 2,0.9 2,2v1h2v-1c0,-1.1 0.9,-2 2,-2h1c0.55,0 1,-0.45 1,-1C17,17.45 16.55,17 16,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_handball.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_handball.xml
index 935099f..ff8729d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_handball.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_handball.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.27,6C13.72,6.95 14.05,8.18 15,8.73c0.95,0.55 2.18,0.22 2.73,-0.73S17.95,5.82 17,5.27C16.05,4.72 14.82,5.05 14.27,6z"/>
+ android:pathData="M14.27,6C13.72,6.95 14.05,8.18 15,8.73c0.95,0.55 2.18,0.22 2.73,-0.73c0.55,-0.95 0.22,-2.18 -0.73,-2.73C16.05,4.72 14.82,5.05 14.27,6z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15.84,10.41c0,0 -1.63,-0.94 -2.6,-1.5c-2.13,-1.24 -3.01,-3.83 -2.18,-6.07c0.17,-0.46 -0.01,-0.97 -0.43,-1.21c-0.53,-0.3 -1.22,-0.07 -1.43,0.5C8.25,4.64 8.85,7.48 10.66,9.4l-4.65,8.05c-0.28,0.48 -0.11,1.09 0.37,1.37s1.09,0.11 1.37,-0.37l1,-1.73l1.73,1l-2.5,4.33c-0.28,0.48 -0.11,1.09 0.37,1.37s1.09,0.11 1.37,-0.37l5.79,-10.02c0.98,1.34 1.26,3.12 0.66,4.72c-0.17,0.45 0.02,0.96 0.43,1.2c0.53,0.31 1.22,0.08 1.44,-0.5C19.01,15.83 18.45,12.61 15.84,10.41z"/>
+ android:pathData="M15.84,10.41c0,0 -1.63,-0.94 -2.6,-1.5c-2.13,-1.24 -3.01,-3.83 -2.18,-6.07c0.17,-0.46 -0.01,-0.97 -0.43,-1.21C10.1,1.33 9.41,1.56 9.2,2.13C8.25,4.64 8.85,7.48 10.66,9.4l-4.65,8.05c-0.28,0.48 -0.11,1.09 0.37,1.37c0.48,0.28 1.09,0.11 1.37,-0.37l1,-1.73l1.73,1l-2.5,4.33c-0.28,0.48 -0.11,1.09 0.37,1.37c0.48,0.28 1.09,0.11 1.37,-0.37l5.79,-10.02c0.98,1.34 1.26,3.12 0.66,4.72c-0.17,0.45 0.02,0.96 0.43,1.2c0.53,0.31 1.22,0.08 1.44,-0.5C19.01,15.83 18.45,12.61 15.84,10.41z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12.75,3.8c0.72,0.41 1.63,0.17 2.05,-0.55c0.41,-0.72 0.17,-1.63 -0.55,-2.05c-0.72,-0.41 -1.63,-0.17 -2.05,0.55C11.79,2.47 12.03,3.39 12.75,3.8z"/>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_hockey.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_hockey.xml
index 17edff6..520fe43 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_hockey.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_hockey.xml
@@ -6,14 +6,14 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,17v2c0,0.55 0.45,1 1,1h1v-4H3C2.45,16 2,16.45 2,17z"/>
+ android:pathData="M2,17v3l2,0v-4H3C2.45,16 2,16.45 2,17z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M9,16H5v4l4.69,-0.01c0.38,0 0.72,-0.21 0.89,-0.55l0.87,-1.9l-1.59,-3.48L9,16z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M21.71,16.29C21.53,16.11 21.28,16 21,16h-1v4h1c0.55,0 1,-0.45 1,-1v-2C22,16.72 21.89,16.47 21.71,16.29z"/>
+ android:pathData="M21.71,16.29C21.53,16.11 21.28,16 21,16h-1v4l2,0v-3C22,16.72 21.89,16.47 21.71,16.29z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M13.6,12.84l3.07,-6.69c0.46,-1 -0.27,-2.15 -1.38,-2.15h0c-0.6,0 -1.14,0.35 -1.39,0.9l-1.36,3.07l-0.49,1.1L12,9.21L10.1,4.9C9.86,4.35 9.31,4 8.71,4h0c-1.1,0 -1.84,1.14 -1.38,2.15l3.07,6.69l1.52,3.32L12,16.34l1.42,3.1c0.17,0.34 0.51,0.55 0.89,0.55L19,20v-4h-4L13.6,12.84z"/>
+ android:pathData="M13.6,12.84L17.65,4H14.3l-1.76,3.97l-0.49,1.1L12,9.21L9.7,4H6.35l4.05,8.84l1.52,3.32L12,16.34l1.42,3.1c0.17,0.34 0.51,0.55 0.89,0.55L19,20v-4h-4L13.6,12.84z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_kabaddi.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_kabaddi.xml
index 5dd70c8..f956961 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_kabaddi.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_kabaddi.xml
@@ -6,14 +6,14 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.5,2.5m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M16.5,2.38m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11.5,6.5m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M24,10.88v-3.7l-4.99,-2.11c-0.98,-0.41 -2.12,-0.07 -2.71,0.81l0,0l-1,1.6c-0.67,1.18 -1.91,2.06 -3.41,2.32l0.06,0.06c0.69,0.69 1.52,1.07 2.46,1.17c0.8,-0.42 1.52,-0.98 2.09,-1.64l0.6,3l-1.16,1.1L15,14.38v0.76v5.74c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-5l2.1,-2l1.62,7.19c0.11,0.47 0.53,0.81 1.02,0.81h0c0.66,0 1.15,-0.6 1.02,-1.24l-1.94,-9.76l-0.62,-3.1l1.8,0.7v2.4c0,0.55 0.45,1 1,1h0C23.55,11.88 24,11.43 24,10.88z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15,12.92c0,-0.5 -0.37,-0.92 -0.87,-0.99c-1.15,-0.17 -2.17,-0.65 -2.89,-1.37l-2,-1.98C9.08,8.42 8.62,8 7.83,8C7.32,8 6.81,8.2 6.42,8.59l-3.34,3.32C2.47,12.52 2.38,13.4 2.61,14l1.07,2.95l-2.93,2.93c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.03,0.39 1.42,0l3.53,-3.53v-2.22L7,16.75V21c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-5.12l-2.12,-2.12l2.36,-2.36l0.71,0.71c1.04,1.02 2.36,1.63 3.91,1.82C14.47,14.01 15,13.53 15,12.92L15,12.92z"/>
+ android:pathData="M10.29,8.09c0.22,0.15 0.47,0.24 0.72,0.29c0.13,0.02 0.25,0.04 0.38,0.04s0.26,-0.01 0.38,-0.04c0.13,-0.02 0.25,-0.06 0.37,-0.11c0.24,-0.1 0.47,-0.24 0.66,-0.44c0.49,-0.49 0.67,-1.17 0.55,-1.8C13.28,5.66 13.1,5.29 12.8,5c-0.19,-0.19 -0.42,-0.34 -0.66,-0.44c-0.12,-0.05 -0.24,-0.09 -0.37,-0.11s-0.25,-0.04 -0.38,-0.04c-0.12,0 -0.23,0.01 -0.35,0.03c-0.14,0.02 -0.28,0.06 -0.41,0.11C10.4,4.66 10.17,4.81 9.98,5C9.68,5.29 9.5,5.66 9.43,6.03c-0.12,0.63 0.06,1.31 0.55,1.8C10.07,7.93 10.18,8.01 10.29,8.09z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M24,11.01V7.97c0,-0.4 -0.24,-0.76 -0.61,-0.92l-4.44,-1.88c-0.97,-0.41 -2.1,-0.06 -2.66,0.84l-1,1.6c-0.67,1.18 -1.91,1.93 -3.41,2.19l0.04,0.04c0.01,0.01 0.02,0.01 0.02,0.02c0.65,0.65 1.64,1.03 2.75,1.11c0.68,-0.4 1.3,-0.88 1.8,-1.45L17.1,13L15,14.99V21c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-4.51l2.1,-2l1.62,6.74c0.11,0.45 0.51,0.77 0.97,0.77h0.09c0.63,0 1.1,-0.58 0.98,-1.19L20.2,7.91l1.8,0.7v2.4c0,0.55 0.45,1 1,1h0C23.55,12.01 24,11.56 24,11.01z"/>
+ android:pathData="M11.24,10.56l-2,-2c-0.1,-0.1 -0.2,-0.18 -0.31,-0.26C8.71,8.16 8.46,8.06 8.21,8.02C8.08,7.99 7.96,7.98 7.83,7.98c-0.51,0 -1.02,0.2 -1.41,0.59l-3.34,3.34c-0.41,0.41 -0.62,0.98 -0.58,1.54C2.5,13.63 2.54,13.82 2.61,14l1.07,2.95l-2.92,2.92c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l3.54,-3.54v-2.22L7,16.75v4.13c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v-5l-2.12,-2.12l2.36,-2.36l0.71,0.71l0,0c1.02,1 2.28,1.69 3.79,1.94c0.64,0.11 1.21,-0.45 1.16,-1.1v0c-0.03,-0.48 -0.4,-0.87 -0.87,-0.94C12.9,11.83 11.97,11.29 11.24,10.56z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_mma.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_mma.xml
index 7754544..9ddc0fd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_mma.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_mma.xml
@@ -9,5 +9,5 @@
android:pathData="M7,20c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-3H7V20z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M18,7c-0.55,0 -1,0.45 -1,1V5c0,-1.1 -0.9,-2 -2,-2H7C5.9,3 5,3.9 5,5v5.8c0,0.13 0.01,0.26 0.04,0.39l0.8,4c0.09,0.47 0.5,0.8 0.98,0.8h10.36c0.45,0 0.89,-0.36 0.98,-0.8l0.8,-4C18.99,11.06 19,10.93 19,10.8V8C19,7.45 18.55,7 18,7zM13,10H9c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1v1C14,9.55 13.55,10 13,10z"/>
+ android:pathData="M18,7c-0.55,0 -1,0.45 -1,1V5c0,-1.1 -0.9,-2 -2,-2H7C5.9,3 5,3.9 5,5v5.8c0,0.13 0.01,0.26 0.04,0.39l0.8,4c0.09,0.47 0.5,0.8 0.98,0.8h10.36c0.45,0 0.89,-0.36 0.98,-0.8l0.8,-4C18.99,11.06 19,10.93 19,10.8V8C19,7.45 18.55,7 18,7zM14,10H8c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v1C15,9.55 14.55,10 14,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_motorsports.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_motorsports.xml
index 30eca5a..99386ef 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_motorsports.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_motorsports.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.42,13c0.87,0 1.58,-0.71 1.58,-1.58c0,-0.65 -0.39,-1.22 -0.99,-1.47l-5.77,-2.3c-1.4,1.47 -2.42,3.3 -2.9,5.35H10.42z"/>
+ android:pathData="M12,11.39c0,-0.65 -0.39,-1.23 -0.98,-1.48L5.44,7.55c-1.48,1.68 -2.32,3.7 -2.8,5.45h7.75C11.28,13 12,12.28 12,11.39z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M21.92,10.84C21.36,6.85 17.75,4 13.73,4c-2.53,0 -4.87,0.81 -6.79,2.18l4.82,1.92C13.11,8.64 14,9.96 14,11.42C14,13.4 12.4,15 10.42,15H2.04C2.02,15.24 2,15.48 2,15.73V18c0,1.1 0.9,2 2,2h10C18.8,20 22.61,15.77 21.92,10.84z"/>
+ android:pathData="M21.96,11.22c-0.41,-4.41 -4.56,-7.49 -8.98,-7.2c-2.51,0.16 -4.44,0.94 -5.93,2.04l4.74,2.01c1.33,0.57 2.2,1.87 2.2,3.32c0,1.99 -1.62,3.61 -3.61,3.61H2.21C2,16.31 2,17.2 2,17.2V18c0,1.1 0.9,2 2,2h10C18.67,20 22.41,15.99 21.96,11.22z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_rugby.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_rugby.xml
index 9b795b6..c4608dc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_rugby.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_rugby.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.53,3.47c-0.56,-0.56 -2.16,-0.97 -4.18,-0.97c-3.1,0 -7.19,0.96 -10.03,3.81C1.61,11.03 2.05,19.1 3.47,20.53c0.56,0.56 2.16,0.97 4.18,0.97c3.1,0 7.19,-0.96 10.03,-3.81C22.39,12.97 21.95,4.9 20.53,3.47zM7.74,7.74c2.65,-2.65 6.38,-3.13 8.07,-3.2C13.75,5.48 11.33,7 9.17,9.17c-2.17,2.17 -3.69,4.6 -4.64,6.66C4.62,13.34 5.41,10.06 7.74,7.74zM16.26,16.26c-2.65,2.65 -6.38,3.13 -8.07,3.2c2.06,-0.94 4.48,-2.46 6.64,-4.63c2.17,-2.17 3.69,-4.6 4.64,-6.66C19.38,10.66 18.59,13.94 16.26,16.26z"/>
+ android:pathData="M20.49,3.51c-0.56,-0.56 -2.15,-0.97 -4.16,-0.97c-3.08,0 -7.15,0.96 -9.98,3.79C1.66,11.03 2.1,19.07 3.51,20.49c0.56,0.56 2.15,0.97 4.16,0.97c3.08,0 7.15,-0.96 9.98,-3.79C22.34,12.97 21.9,4.93 20.49,3.51zM7.76,7.76c2.64,-2.64 6.35,-3.12 8.03,-3.19c-2.05,0.94 -4.46,2.45 -6.61,4.61c-2.16,2.16 -3.67,4.58 -4.61,6.63C4.66,13.33 5.44,10.07 7.76,7.76zM16.24,16.24c-2.64,2.64 -6.35,3.12 -8.03,3.19c2.05,-0.94 4.46,-2.45 6.61,-4.61c2.16,-2.16 3.67,-4.58 4.62,-6.63C19.34,10.67 18.56,13.93 16.24,16.24z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_soccer.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_soccer.xml
index a6783e4..d01405e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_soccer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_soccer.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM13,5.3l1.35,-0.95c1.82,0.56 3.37,1.76 4.38,3.34l-0.39,1.34l-1.35,0.46L13,6.7V5.3zM9.65,4.35L11,5.3v1.4L7.01,9.49L5.66,9.03L5.27,7.69C6.28,6.12 7.83,4.92 9.65,4.35zM7.08,17.11l-1.14,0.1C4.73,15.81 4,13.99 4,12c0,-0.12 0.01,-0.23 0.02,-0.35l1,-0.73L6.4,11.4l1.46,4.34L7.08,17.11zM14.5,19.59C13.71,19.85 12.87,20 12,20s-1.71,-0.15 -2.5,-0.41L8.81,18.1L9.45,17h5.11l0.64,1.11L14.5,19.59zM14.27,15H9.73l-1.35,-4.02L12,8.44l3.63,2.54L14.27,15zM18.06,17.21l-1.14,-0.1l-0.79,-1.37l1.46,-4.34l1.39,-0.47l1,0.73C19.99,11.77 20,11.88 20,12C20,13.99 19.27,15.81 18.06,17.21z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM13,5.3l1.35,-0.95c1.82,0.56 3.37,1.76 4.38,3.34l-0.39,1.34l-1.35,0.46L13,6.7V5.3zM9.65,4.35L11,5.3v1.4L7.01,9.49L5.66,9.03L5.27,7.69C6.28,6.12 7.83,4.92 9.65,4.35zM7.08,17.11l-1.14,0.1C4.73,15.81 4,13.99 4,12c0,-0.12 0.01,-0.23 0.02,-0.35l1,-0.73L6.4,11.4l1.46,4.34L7.08,17.11zM14.5,19.59C13.71,19.85 12.87,20 12,20s-1.71,-0.15 -2.5,-0.41l-0.69,-1.49L9.45,17h5.11l0.64,1.11L14.5,19.59zM14.27,15H9.73l-1.35,-4.02L12,8.44l3.63,2.54L14.27,15zM18.06,17.21l-1.14,-0.1l-0.79,-1.37l1.46,-4.34l1.39,-0.47l1,0.73C19.99,11.77 20,11.88 20,12C20,13.99 19.27,15.81 18.06,17.21z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sports_tennis.xml b/compose/material/material/icons/generator/raw-icons/rounded/sports_tennis.xml
index f6aeb6f..3b1d39b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sports_tennis.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sports_tennis.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.52,2.49c-2.34,-2.34 -6.62,-1.87 -9.55,1.06c-1.6,1.6 -2.52,3.87 -2.54,5.46c-0.02,1.58 0.26,3.89 -1.35,5.5l-3.37,3.37c-0.39,0.39 -0.39,1.03 0,1.42h0c0.39,0.39 1.03,0.39 1.42,0l3.37,-3.37c1.61,-1.61 3.92,-1.33 5.5,-1.35s3.86,-0.94 5.46,-2.54C21.38,9.11 21.86,4.83 19.52,2.49zM10.32,11.67c-1.53,-1.53 -1.05,-4.61 1.06,-6.72c2.11,-2.11 5.18,-2.59 6.72,-1.06c1.53,1.53 1.05,4.61 -1.06,6.72C14.93,12.72 11.86,13.2 10.32,11.67z"/>
+ android:pathData="M19.52,2.49c-2.34,-2.34 -6.62,-1.87 -9.55,1.06c-1.6,1.6 -2.52,3.87 -2.54,5.46c-0.02,1.58 0.26,3.89 -1.35,5.5l-3.54,3.53c-0.39,0.39 -0.39,1.02 0,1.42l0,0c0.39,0.39 1.02,0.39 1.42,0l3.53,-3.54c1.61,-1.61 3.92,-1.33 5.5,-1.35s3.86,-0.94 5.46,-2.54C21.38,9.11 21.86,4.83 19.52,2.49zM10.32,11.68c-1.53,-1.53 -1.05,-4.61 1.06,-6.72s5.18,-2.59 6.72,-1.06c1.53,1.53 1.05,4.61 -1.06,6.72S11.86,13.21 10.32,11.68z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M20.83,16.17C20.05,15.39 19.02,15 18,15c-1.02,0 -2.05,0.39 -2.83,1.17c-1.56,1.56 -1.56,4.09 0,5.66C15.95,22.61 16.98,23 18,23c1.02,0 2.05,-0.39 2.83,-1.17C22.39,20.27 22.39,17.74 20.83,16.17z"/>
+ android:pathData="M18,17c0.53,0 1.04,0.21 1.41,0.59c0.78,0.78 0.78,2.05 0,2.83C19.04,20.79 18.53,21 18,21s-1.04,-0.21 -1.41,-0.59c-0.78,-0.78 -0.78,-2.05 0,-2.83C16.96,17.21 17.47,17 18,17M18,15c-1.02,0 -2.05,0.39 -2.83,1.17c-1.56,1.56 -1.56,4.09 0,5.66C15.95,22.61 16.98,23 18,23s2.05,-0.39 2.83,-1.17c1.56,-1.56 1.56,-4.09 0,-5.66C20.05,15.39 19.02,15 18,15L18,15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/square_foot.xml b/compose/material/material/icons/generator/raw-icons/rounded/square_foot.xml
index 039d25d..b116b38 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/square_foot.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/square_foot.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.68,19.14l-1.97,-1.97l-1.33,1.33l-0.71,-0.71L17,16.46l-2.59,-2.59l-1.33,1.33l-0.71,-0.71l1.33,-1.33l-2.59,-2.59l-1.33,1.33l-0.71,-0.71l1.33,-1.33L7.8,7.26L6.47,8.59L5.77,7.89L7.1,6.56L4.86,4.32C4.64,4.1 4.37,4 4.1,4C3.54,4 3,4.44 3,5.09v13.73C3,20.02 3.98,21 5.18,21h13.73C19.88,21 20.37,19.83 19.68,19.14zM6,18V9.7l8.3,8.3H6z"/>
+ android:pathData="M17.66,17.66l-0.71,0.71c-0.2,0.2 -0.51,0.2 -0.71,0l0,0c-0.2,-0.2 -0.2,-0.51 0,-0.71l0.71,-0.71l-1.94,-1.94l-0.71,0.71c-0.2,0.2 -0.51,0.2 -0.71,0l0,0c-0.2,-0.2 -0.2,-0.51 0,-0.71l0.71,-0.71l-1.94,-1.94l-0.71,0.71c-0.2,0.2 -0.51,0.2 -0.71,0l0,0c-0.2,-0.2 -0.2,-0.51 0,-0.71l0.71,-0.71L9.7,9.7l-0.71,0.71c-0.2,0.2 -0.51,0.2 -0.71,0l0,0c-0.2,-0.2 -0.2,-0.51 0,-0.71l0.71,-0.71L7.05,7.05L6.34,7.76c-0.2,0.2 -0.51,0.2 -0.71,0l0,0c-0.2,-0.2 -0.2,-0.51 0,-0.71l0.71,-0.71L4.85,4.85C4.54,4.54 4,4.76 4,5.21V18c0,1.1 0.9,2 2,2h12.79c0.45,0 0.67,-0.54 0.35,-0.85L17.66,17.66zM7,16v-4.76L12.76,17H8C7.45,17 7,16.55 7,16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/star.xml b/compose/material/material/icons/generator/raw-icons/rounded/star.xml
index 61a30e5..76a947b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/star.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/star.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.43,10l-1.47,-4.84c-0.29,-0.95 -1.63,-0.95 -1.91,0L9.57,10H5.12c-0.97,0 -1.37,1.25 -0.58,1.81l3.64,2.6l-1.43,4.61c-0.29,0.93 0.79,1.68 1.56,1.09L12,17.31l3.69,2.81c0.77,0.59 1.85,-0.16 1.56,-1.09l-1.43,-4.61l3.64,-2.6c0.79,-0.57 0.39,-1.81 -0.58,-1.81H14.43z"/>
+ android:pathData="M12,17.27l4.15,2.51c0.76,0.46 1.69,-0.22 1.49,-1.08l-1.1,-4.72l3.67,-3.18c0.67,-0.58 0.31,-1.68 -0.57,-1.75l-4.83,-0.41l-1.89,-4.46c-0.34,-0.81 -1.5,-0.81 -1.84,0L9.19,8.63L4.36,9.04c-0.88,0.07 -1.24,1.17 -0.57,1.75l3.67,3.18l-1.1,4.72c-0.2,0.86 0.73,1.54 1.49,1.08L12,17.27z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/star_border.xml b/compose/material/material/icons/generator/raw-icons/rounded/star_border.xml
index cb4f3f7..16a2efc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/star_border.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/star_border.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,8.89L12.94,12h2.82l-2.27,1.62l0.93,3.01L12,14.79l-2.42,1.84l0.93,-3.01L8.24,12h2.82L12,8.89M9.58,10H5.12c-0.97,0 -1.37,1.25 -0.58,1.81l3.64,2.6l-1.43,4.61c-0.29,0.93 0.79,1.68 1.56,1.09L12,17.31l3.69,2.81c0.77,0.59 1.85,-0.16 1.56,-1.09l-1.43,-4.61l3.64,-2.6c0.79,-0.57 0.39,-1.81 -0.58,-1.81h-4.46l-1.47,-4.84c-0.29,-0.95 -1.63,-0.95 -1.91,0L9.58,10z"/>
+ android:pathData="M19.65,9.04l-4.84,-0.42 -1.89,-4.45c-0.34,-0.81 -1.5,-0.81 -1.84,0L9.19,8.63l-4.83,0.41c-0.88,0.07 -1.24,1.17 -0.57,1.75l3.67,3.18 -1.1,4.72c-0.2,0.86 0.73,1.54 1.49,1.08l4.15,-2.5 4.15,2.51c0.76,0.46 1.69,-0.22 1.49,-1.08l-1.1,-4.73 3.67,-3.18c0.67,-0.58 0.32,-1.68 -0.56,-1.75zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/star_half.xml b/compose/material/material/icons/generator/raw-icons/rounded/star_half.xml
index 5b8a41a..219b90a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/star_half.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/star_half.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.88,10h-4.46l-1.47,-4.84c-0.29,-0.95 -1.63,-0.95 -1.91,0L9.58,10H5.12c-0.97,0 -1.37,1.25 -0.58,1.81l3.64,2.6l-1.43,4.61c-0.29,0.93 0.79,1.68 1.56,1.09L12,17.31l3.69,2.81c0.77,0.59 1.85,-0.16 1.56,-1.09l-1.43,-4.61l3.64,-2.6C20.25,11.25 19.85,10 18.88,10zM14.42,16.63L12,14.79v-5.9L12.94,12h2.82l-2.27,1.62L14.42,16.63z"/>
+ android:pathData="M19.65,9.04l-4.84,-0.42 -1.89,-4.45c-0.34,-0.81 -1.5,-0.81 -1.84,0L9.19,8.63l-4.83,0.41c-0.88,0.07 -1.24,1.17 -0.57,1.75l3.67,3.18 -1.1,4.72c-0.2,0.86 0.73,1.54 1.49,1.08l4.15,-2.5 4.15,2.51c0.76,0.46 1.69,-0.22 1.49,-1.08l-1.1,-4.73 3.67,-3.18c0.67,-0.58 0.32,-1.68 -0.56,-1.75zM12,15.4V6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/star_outline.xml b/compose/material/material/icons/generator/raw-icons/rounded/star_outline.xml
index 61a30e5..16a2efc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/star_outline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/star_outline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.43,10l-1.47,-4.84c-0.29,-0.95 -1.63,-0.95 -1.91,0L9.57,10H5.12c-0.97,0 -1.37,1.25 -0.58,1.81l3.64,2.6l-1.43,4.61c-0.29,0.93 0.79,1.68 1.56,1.09L12,17.31l3.69,2.81c0.77,0.59 1.85,-0.16 1.56,-1.09l-1.43,-4.61l3.64,-2.6c0.79,-0.57 0.39,-1.81 -0.58,-1.81H14.43z"/>
+ android:pathData="M19.65,9.04l-4.84,-0.42 -1.89,-4.45c-0.34,-0.81 -1.5,-0.81 -1.84,0L9.19,8.63l-4.83,0.41c-0.88,0.07 -1.24,1.17 -0.57,1.75l3.67,3.18 -1.1,4.72c-0.2,0.86 0.73,1.54 1.49,1.08l4.15,-2.5 4.15,2.51c0.76,0.46 1.69,-0.22 1.49,-1.08l-1.1,-4.73 3.67,-3.18c0.67,-0.58 0.32,-1.68 -0.56,-1.75zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stars.xml b/compose/material/material/icons/generator/raw-icons/rounded/stars.xml
index ac44c38..adea02a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stars.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stars.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM14.77,17.06L12,14.95l-2.77,2.11c-0.39,0.29 -0.92,-0.08 -0.78,-0.55l1.07,-3.44l-2.74,-1.96c-0.4,-0.28 -0.2,-0.91 0.29,-0.91h3.36l1.1,-3.62c0.14,-0.47 0.81,-0.47 0.96,0l1.1,3.62h3.36c0.49,0 0.69,0.62 0.29,0.91l-2.74,1.96l1.07,3.44C15.7,16.97 15.16,17.35 14.77,17.06z"/>
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM15.22,17.39L12,15.45l-3.22,1.94c-0.38,0.23 -0.85,-0.11 -0.75,-0.54l0.85,-3.66 -2.83,-2.45c-0.33,-0.29 -0.15,-0.84 0.29,-0.88l3.74,-0.32 1.46,-3.45c0.17,-0.41 0.75,-0.41 0.92,0l1.46,3.44 3.74,0.32c0.44,0.04 0.62,0.59 0.28,0.88l-2.83,2.45 0.85,3.67c0.1,0.43 -0.36,0.77 -0.74,0.54z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stay_current_landscape.xml b/compose/material/material/icons/generator/raw-icons/rounded/stay_current_landscape.xml
index f371f82..798c036 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stay_current_landscape.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stay_current_landscape.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M1.01,7L1,17c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H3C1.9,5 1.01,5.9 1.01,7zM18,7v10H6V7H18z"/>
+ android:pathData="M1.01,7L1,17c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H3c-1.1,0 -1.99,0.9 -1.99,2zM19,7v10H5V7h14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stay_current_portrait.xml b/compose/material/material/icons/generator/raw-icons/rounded/stay_current_portrait.xml
index 191a691..7b9fc07 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stay_current_portrait.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stay_current_portrait.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,18H7V6h10V18z"/>
+ android:pathData="M17,1.01L7,1c-1.1,0 -1.99,0.9 -1.99,2v18c0,1.1 0.89,2 1.99,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19H7V5h10v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_landscape.xml b/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_landscape.xml
index f371f82..798c036 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_landscape.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_landscape.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M1.01,7L1,17c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H3C1.9,5 1.01,5.9 1.01,7zM18,7v10H6V7H18z"/>
+ android:pathData="M1.01,7L1,17c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H3c-1.1,0 -1.99,0.9 -1.99,2zM19,7v10H5V7h14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_portrait.xml b/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_portrait.xml
index 191a691..7b9fc07 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_portrait.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stay_primary_portrait.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,18H7V6h10V18z"/>
+ android:pathData="M17,1.01L7,1c-1.1,0 -1.99,0.9 -1.99,2v18c0,1.1 0.89,2 1.99,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19H7V5h10v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stop.xml b/compose/material/material/icons/generator/raw-icons/rounded/stop.xml
index ceb3936..812b445 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stop.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stop.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,6h8c1.1,0 2,0.9 2,2v8c0,1.1 -0.9,2 -2,2H8c-1.1,0 -2,-0.9 -2,-2V8C6,6.9 6.9,6 8,6z"/>
+ android:pathData="M8,6h8c1.1,0 2,0.9 2,2v8c0,1.1 -0.9,2 -2,2H8c-1.1,0 -2,-0.9 -2,-2V8c0,-1.1 0.9,-2 2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stop_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/stop_circle.xml
index 5abb278..b6e8c2e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stop_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stop_circle.xml
@@ -6,6 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,16h6c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1H9C8.45,8 8,8.45 8,9v6C8,15.55 8.45,16 9,16zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2L12,2z"
- android:fillType="evenOdd"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM15,16H9c-0.55,0 -1,-0.45 -1,-1V9c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v6C16,15.55 15.55,16 15,16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/stop_screen_share.xml b/compose/material/material/icons/generator/raw-icons/rounded/stop_screen_share.xml
index 0d03088..ee0d19c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/stop_screen_share.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/stop_screen_share.xml
@@ -7,8 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H5.83l6,6H13V8.21c0,-0.45 0.54,-0.67 0.85,-0.35l1.79,1.79c0.2,0.2 0.2,0.51 0,0.71l-1.23,1.23l6.28,6.28c0.75,-0.29 1.29,-1.01 1.29,-1.87L22,5C22,3.9 21.1,3 20,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M0.69,3.51l1.33,1.33C2.01,4.9 2,4.95 2,5v11c0,1.1 0.9,2 2,2h11.17l1,1H2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h16.17l2.31,2.31l1.41,-1.41L2.1,2.1L0.69,3.51zM8,12c0,-0.35 0.07,-0.68 0.18,-0.99L10,12.83V13c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V12z"/>
+ android:pathData="M23,18h-1.2l1.79,1.79c0.24,-0.18 0.41,-0.46 0.41,-0.79 0,-0.55 -0.45,-1 -1,-1zM3.23,2.28c-0.39,-0.39 -1.03,-0.39 -1.42,0 -0.39,0.39 -0.39,1.02 0,1.41l0.84,0.86s-0.66,0.57 -0.66,1.47C2,6.92 2,16 2,16l0.01,0.01c0,1.09 0.88,1.98 1.97,1.99L1,18c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h17.13l2,2c0.39,0.39 1.02,0.39 1.41,0s0.39,-1.02 0,-1.41L3.23,2.28zM7,15c0.31,-1.48 0.94,-2.93 2.08,-4.05l1.59,1.59C9.13,12.92 7.96,13.71 7,15zM13,9.13v-0.98c0,-0.44 0.52,-0.66 0.84,-0.37L15,8.87l1.61,1.5c0.21,0.2 0.21,0.53 0,0.73l-0.89,0.83 5.58,5.58c0.43,-0.37 0.7,-0.9 0.7,-1.51L22,6c0,-1.09 -0.89,-1.98 -1.98,-1.98L7.8,4.02l5.14,5.13c0.02,-0.01 0.04,-0.02 0.06,-0.02z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/storage.xml b/compose/material/material/icons/generator/raw-icons/rounded/storage.xml
index 2ea3e7f..46a63e2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/storage.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/storage.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,20h16c1.1,0 2,-0.9 2,-2l0,0c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0 -2,0.9 -2,2l0,0C2,19.1 2.9,20 4,20zM4,17h2v2H4V17zM2,6L2,6c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2l0,0c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6zM6,7H4V5h2V7zM4,14h16c1.1,0 2,-0.9 2,-2l0,0c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0 -2,0.9 -2,2l0,0C2,13.1 2.9,14 4,14zM4,11h2v2H4V11z"/>
+ android:pathData="M4,20h16c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2L4,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2zM4,17h2v2L4,19v-2zM2,6c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2zM6,7L4,7L4,5h2v2zM4,14h16c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2L4,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2zM4,11h2v2L4,13v-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/store.xml b/compose/material/material/icons/generator/raw-icons/rounded/store.xml
index aa97bfb..db931e2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/store.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/store.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,6h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5C4.45,4 4,4.45 4,5S4.45,6 5,6zM20.16,7.8C20.07,7.34 19.66,7 19.18,7H4.82C4.34,7 3.93,7.34 3.84,7.8l-1,5C2.72,13.42 3.19,14 3.82,14H4v5c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-5h4v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5h0.18c0.63,0 1.1,-0.58 0.98,-1.2L20.16,7.8zM12,18H6v-4h6V18z"/>
+ android:pathData="M5,6h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM20.16,7.8c-0.09,-0.46 -0.5,-0.8 -0.98,-0.8L4.82,7c-0.48,0 -0.89,0.34 -0.98,0.8l-1,5c-0.12,0.62 0.35,1.2 0.98,1.2L4,14v5c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-5h4v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5h0.18c0.63,0 1.1,-0.58 0.98,-1.2l-1,-5zM12,18L6,18v-4h6v4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/store_mall_directory.xml b/compose/material/material/icons/generator/raw-icons/rounded/store_mall_directory.xml
index aa97bfb..aecafd3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/store_mall_directory.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/store_mall_directory.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,6h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5C4.45,4 4,4.45 4,5S4.45,6 5,6zM20.16,7.8C20.07,7.34 19.66,7 19.18,7H4.82C4.34,7 3.93,7.34 3.84,7.8l-1,5C2.72,13.42 3.19,14 3.82,14H4v5c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-5h4v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5h0.18c0.63,0 1.1,-0.58 0.98,-1.2L20.16,7.8zM12,18H6v-4h6V18z"/>
+ android:pathData="M20.16,7.8c-0.09,-0.46 -0.5,-0.8 -0.98,-0.8H4.82c-0.48,0 -0.89,0.34 -0.98,0.8L3,12v1c0,0.55 0.45,1 1,1v5c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-5h4v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5c0.55,0 1,-0.45 1,-1v-1l-0.84,-4.2zM12,18H6v-4h6v4zM5,6h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/straighten.xml b/compose/material/material/icons/generator/raw-icons/rounded/straighten.xml
index 9d33755..1772057 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/straighten.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/straighten.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6H4C2.9,6 2,6.9 2,8v8c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM20,16H4V8h3v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V8h2v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V8h2v3c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V8h3V16z"/>
+ android:pathData="M21,6L3,6c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,8c0,-1.1 -0.9,-2 -2,-2zM20,16L4,16c-0.55,0 -1,-0.45 -1,-1L3,9c0,-0.55 0.45,-1 1,-1h1v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L7,8h2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L11,8h2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L15,8h2v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1L19,8h1c0.55,0 1,0.45 1,1v6c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/streetview.xml b/compose/material/material/icons/generator/raw-icons/rounded/streetview.xml
index a6cced5..4085e83 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/streetview.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/streetview.xml
@@ -6,11 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
+ android:pathData="M12.56,14.33c-0.34,0.27 -0.56,0.7 -0.56,1.17V21h7c1.1,0 2,-0.9 2,-2v-5.98c-0.94,-0.33 -1.95,-0.52 -3,-0.52 -2.03,0 -3.93,0.7 -5.44,1.83z"/>
+ <path
+ android:fillColor="@android:color/white"
android:pathData="M18,6m-5,0a5,5 0,1 1,10 0a5,5 0,1 1,-10 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M11,6c0,-1.07 0.25,-2.09 0.69,-3H5C3.9,3 3,3.9 3,5v14c0,0.55 0.23,1.05 0.59,1.41l9.46,-9.46C11.79,9.68 11,7.93 11,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14.29,12.66c-1.35,0.3 -2.29,1.53 -2.29,2.92V21h7c1.1,0 2,-0.9 2,-2v-6.48c-0.95,-0.17 -1.95,-0.27 -3,-0.27C16.68,12.25 15.44,12.4 14.29,12.66z"/>
+ android:pathData="M11.5,6c0,-1.08 0.27,-2.1 0.74,-3H5c-1.1,0 -2,0.9 -2,2v14c0,0.55 0.23,1.05 0.59,1.41l9.82,-9.82C12.23,9.42 11.5,7.8 11.5,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/strikethrough_s.xml b/compose/material/material/icons/generator/raw-icons/rounded/strikethrough_s.xml
index d18caa4..cf9a013 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/strikethrough_s.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/strikethrough_s.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.32,6.78c0.48,-0.36 1.07,-0.54 1.76,-0.54c0.7,0 1.27,0.19 1.71,0.56c0.2,0.16 0.36,0.34 0.5,0.52c0.32,0.42 0.89,0.55 1.37,0.34c0.7,-0.3 0.96,-1.18 0.49,-1.78c-0.25,-0.32 -0.56,-0.63 -0.91,-0.92C14.45,4.33 13.38,4 12.04,4c-0.93,0 -1.76,0.19 -2.49,0.57C8.72,4.99 8.1,5.59 7.68,6.35C7.4,6.85 7.25,7.42 7.22,8h2.4C9.66,7.51 9.89,7.1 10.32,6.78z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14.93,15.51c0,0.68 -0.26,1.22 -0.79,1.62s-1.17,0.59 -1.92,0.59c-0.81,0 -1.51,-0.27 -2.09,-0.8c-0.33,-0.31 -0.61,-0.67 -0.83,-1.08c-0.29,-0.54 -0.96,-0.75 -1.52,-0.52c-0.65,0.26 -0.98,1.03 -0.66,1.65c0.4,0.78 0.94,1.42 1.63,1.93C9.76,19.63 10.9,20 12.17,20c0.84,0 1.66,-0.17 2.45,-0.49c0.79,-0.33 1.44,-0.83 1.96,-1.51s0.77,-1.52 0.77,-2.51c0,-0.55 -0.08,-1.04 -0.23,-1.49h-2.85C14.71,14.4 14.93,14.9 14.93,15.51z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h18c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H3z"/>
+ android:pathData="M14.59,7.52c0,-0.31 -0.05,-0.59 -0.15,-0.85 -0.09,-0.27 -0.24,-0.49 -0.44,-0.68 -0.2,-0.19 -0.45,-0.33 -0.75,-0.44 -0.3,-0.1 -0.66,-0.16 -1.06,-0.16 -0.39,0 -0.74,0.04 -1.03,0.13s-0.53,0.21 -0.72,0.36c-0.19,0.16 -0.34,0.34 -0.44,0.55 -0.1,0.21 -0.15,0.43 -0.15,0.66 0,0.48 0.25,0.88 0.74,1.21 0.38,0.25 0.77,0.48 1.41,0.7H7.39c-0.05,-0.08 -0.11,-0.17 -0.15,-0.25 -0.26,-0.48 -0.39,-1.03 -0.39,-1.67 0,-0.61 0.13,-1.16 0.4,-1.67 0.26,-0.5 0.63,-0.93 1.11,-1.29 0.48,-0.35 1.05,-0.63 1.7,-0.83 0.66,-0.19 1.39,-0.29 2.18,-0.29 0.81,0 1.54,0.11 2.21,0.34 0.66,0.22 1.23,0.54 1.69,0.94 0.47,0.4 0.83,0.88 1.08,1.43s0.38,1.15 0.38,1.81h-3.01M20,10H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h8.62c0.18,0.07 0.4,0.14 0.55,0.2 0.37,0.17 0.66,0.34 0.87,0.51s0.35,0.36 0.43,0.57c0.07,0.2 0.11,0.43 0.11,0.69 0,0.23 -0.05,0.45 -0.14,0.66 -0.09,0.2 -0.23,0.38 -0.42,0.53 -0.19,0.15 -0.42,0.26 -0.71,0.35 -0.29,0.08 -0.63,0.13 -1.01,0.13 -0.43,0 -0.83,-0.04 -1.18,-0.13s-0.66,-0.23 -0.91,-0.42c-0.25,-0.19 -0.45,-0.44 -0.59,-0.75s-0.25,-0.76 -0.25,-1.21H6.4c0,0.55 0.08,1.13 0.24,1.58s0.37,0.85 0.65,1.21c0.28,0.35 0.6,0.66 0.98,0.92 0.37,0.26 0.78,0.48 1.22,0.65 0.44,0.17 0.9,0.3 1.38,0.39 0.48,0.08 0.96,0.13 1.44,0.13 0.8,0 1.53,-0.09 2.18,-0.28s1.21,-0.45 1.67,-0.79c0.46,-0.34 0.82,-0.77 1.07,-1.27s0.38,-1.07 0.38,-1.71c0,-0.6 -0.1,-1.14 -0.31,-1.61 -0.05,-0.11 -0.11,-0.23 -0.17,-0.33H20c0.55,0 1,-0.45 1,-1V11c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/style.xml b/compose/material/material/icons/generator/raw-icons/rounded/style.xml
index 7dabb9e..8420955 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/style.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/style.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2.53,19.65l1.34,0.56v-9.03l-2.43,5.86C1.03,18.06 1.52,19.23 2.53,19.65zM22.03,15.95L17.07,3.98c-0.31,-0.75 -1.04,-1.21 -1.81,-1.23c-0.26,0 -0.53,0.04 -0.79,0.15L7.1,5.95c-0.75,0.31 -1.21,1.03 -1.23,1.8c-0.01,0.27 0.04,0.54 0.15,0.8l4.96,11.97c0.31,0.76 1.05,1.22 1.83,1.23c0.26,0 0.52,-0.05 0.77,-0.15l7.36,-3.05C21.96,18.13 22.45,16.96 22.03,15.95zM11,10c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S11.55,10 11,10zM5.88,19.75c0,1.1 0.9,2 2,2h1.45l-3.45,-8.34V19.75z"/>
+ android:pathData="M2.53,19.65l1.34,0.56v-9.03l-2.43,5.86c-0.41,1.02 0.08,2.19 1.09,2.61zM22.03,15.95L17.07,3.98c-0.31,-0.75 -1.04,-1.21 -1.81,-1.23 -0.26,0 -0.53,0.04 -0.79,0.15L7.1,5.95c-0.75,0.31 -1.21,1.03 -1.23,1.8 -0.01,0.27 0.04,0.54 0.15,0.8l4.96,11.97c0.31,0.76 1.05,1.22 1.83,1.23 0.26,0 0.52,-0.05 0.77,-0.15l7.36,-3.05c1.02,-0.42 1.51,-1.59 1.09,-2.6zM7.88,8.75c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM5.88,19.75c0,1.1 0.9,2 2,2h1.45l-3.45,-8.34v6.34z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_left.xml b/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_left.xml
index 7da6049..5a615ec 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_left.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_left.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4.71,15.71l3.59,3.59C8.92,19.92 10,19.48 10,18.59V16h7c1.1,0 2,-0.9 2,-2V5c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v9h-7v-2.59c0,-0.89 -1.08,-1.34 -1.71,-0.71l-3.59,3.59C4.32,14.68 4.32,15.32 4.71,15.71z"/>
+ android:pathData="M5.71,15.71l4.58,4.58c0.39,0.39 1.03,0.39 1.42,0 0.39,-0.39 0.39,-1.03 0,-1.42L8.83,16H19c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v9H8.83l2.88,-2.87c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.03,-0.39 -1.42,0l-4.58,4.58c-0.39,0.39 -0.39,1.03 0,1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_right.xml b/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_right.xml
index 962d8a8..c72707f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_right.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/subdirectory_arrow_right.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.71,15.71l-3.59,3.59c-0.63,0.63 -1.71,0.18 -1.71,-0.71V16h-7c-1.1,0 -2,-0.9 -2,-2V5c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v9h7v-2.59c0,-0.89 1.08,-1.34 1.71,-0.71l3.59,3.59C20.1,14.68 20.1,15.32 19.71,15.71z"/>
+ android:pathData="M18.29,15.71l-4.58,4.58c-0.39,0.39 -1.03,0.39 -1.42,0 -0.39,-0.39 -0.39,-1.03 0,-1.42L15.17,16H5c-0.55,0 -1,-0.45 -1,-1V5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v9h9.17l-2.88,-2.87c-0.39,-0.39 -0.39,-1.03 0,-1.42 0.39,-0.39 1.03,-0.39 1.42,0l4.58,4.58c0.39,0.39 0.39,1.03 0,1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/subject.xml b/compose/material/material/icons/generator/raw-icons/rounded/subject.xml
index 86d0747..9d58e6d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/subject.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/subject.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,17H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h8c0.55,0 1,-0.45 1,-1S13.55,17 13,17zM19,9H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1S19.55,9 19,9zM5,15h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1S4.45,15 5,15zM4,6c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6z"/>
+ android:pathData="M13,17L5,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h8c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM19,9L5,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM5,15h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,6c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/subscriptions.xml b/compose/material/material/icons/generator/raw-icons/rounded/subscriptions.xml
index 5ae57ae..813dab2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/subscriptions.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/subscriptions.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,2H8C7.45,2 7,2.45 7,3v0c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v0C17,2.45 16.55,2 16,2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,5H5C4.45,5 4,5.45 4,6v0c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0C20,5.45 19.55,5 19,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,8H4c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V10C22,8.9 21.1,8 20,8zM10,17.13v-4.26c0,-0.8 0.89,-1.28 1.55,-0.83l3.2,2.13c0.59,0.4 0.59,1.27 0,1.66l-3.2,2.13C10.89,18.41 10,17.93 10,17.13z"/>
+ android:pathData="M19,8L5,8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h14c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM17,2L7,2c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM22,12v8c0,1.1 -0.9,2 -2,2L4,22c-1.1,0 -2,-0.9 -2,-2v-8c0,-1.1 0.9,-2 2,-2h16c1.1,0 2,0.9 2,2zM15.19,15.56L10,12.73v6.53l5.19,-2.82c0.35,-0.19 0.35,-0.69 0,-0.88z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/subtitles.xml b/compose/material/material/icons/generator/raw-icons/rounded/subtitles.xml
index 48c2627c..e785953 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/subtitles.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/subtitles.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM13,16H7c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v0C14,15.55 13.55,16 13,16zM17,12h-6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v0C18,11.55 17.55,12 17,12zM8,11c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1s0.45,-1 1,-1S8,10.45 8,11zM18,15c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1s0.45,-1 1,-1S18,14.45 18,15z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM5,12h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM13,18L5,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM19,18h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM19,14h-8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/subtitles_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/subtitles_off.xml
index dedf59b..3c5a32f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/subtitles_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/subtitles_off.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H6.83l6,6H17c0.55,0 1,0.45 1,1s-0.45,1 -1,1h-2.17l6.93,6.93C21.91,18.65 22,18.34 22,18V6C22,4.9 21.1,4 20,4z"/>
+ android:pathData="M20,4H6.83l8,8H19c0.55,0 1,0.45 1,1c0,0.55 -0.45,1 -1,1h-2.17l4.93,4.93C21.91,18.65 22,18.34 22,18V6C22,4.9 21.1,4 20,4z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22l0.85,0.85C2.09,5.35 2,5.66 2,6v12c0,1.1 0.9,2 2,2h13.17l2.61,2.61c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81zM7,10c0.08,0 0.14,0.03 0.21,0.04l0.74,0.74C7.97,10.86 8,10.92 8,11c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1S6.45,10 7,10zM13,16H7c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h4.17l1.97,1.97C13.09,15.98 13.05,16 13,16z"/>
+ android:pathData="M20,20l-6,-6l-1.71,-1.71L12,12L3.16,3.16c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l0.49,0.49C2.09,5.35 2,5.66 2,6v12c0,1.1 0.9,2 2,2h13.17l2.25,2.25c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L20,20zM8,13c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h2C7.55,12 8,12.45 8,13zM14,17c0,0.55 -0.45,1 -1,1H5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h8c0.08,0 0.14,0.03 0.21,0.04l0.74,0.74C13.97,16.86 14,16.92 14,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/subway.xml b/compose/material/material/icons/generator/raw-icons/rounded/subway.xml
index 3094b20..eece4b0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/subway.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/subway.xml
@@ -6,14 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.8,2.8C16,2.09 13.86,2 12,2S8,2.09 6.2,2.8C3.53,3.84 2,6.05 2,8.86V20c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8.86C22,6.05 20.47,3.84 17.8,2.8zM18,15.5c0,1.5 -1.11,2.73 -2.55,2.95l0.26,0.26c0.47,0.47 0.14,1.28 -0.53,1.28h0c-0.2,0 -0.39,-0.08 -0.53,-0.22l-1.28,-1.28h-2.75l-1.28,1.28C9.2,19.92 9.01,20 8.81,20h0c-0.67,0 -1,-0.81 -0.53,-1.28l0.26,-0.26C7.11,18.23 6,17 6,15.5V9c0,-2.62 3,-3 6,-3c3.32,0 6,0.38 6,3V15.5z"/>
+ android:pathData="M8.5,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M8.5,15.5m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M15.5,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M7.5,9h9v4h-9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,15.5m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M7.01,9h10v5h-10zM17.8,2.8C16,2.09 13.86,2 12,2s-4,0.09 -5.8,0.8C3.53,3.84 2,6.05 2,8.86L2,22h20L22,8.86c0,-2.81 -1.53,-5.02 -4.2,-6.06zM18,15.5c0,1.54 -1.16,2.79 -2.65,2.96l1.15,1.16L16.5,20h-1.67l-1.5,-1.5h-2.66L9.17,20L7.5,20v-0.38l1.15,-1.16C7.16,18.29 6,17.04 6,15.5L6,9c0,-2.63 3,-3 6,-3s6,0.37 6,3v6.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/supervised_user_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/supervised_user_circle.xml
index c8148b3..b494c0b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/supervised_user_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/supervised_user_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM9.5,6.5c1.93,0 3.5,1.57 3.5,3.5s-1.57,3.5 -3.5,3.5S6,11.93 6,10S7.57,6.5 9.5,6.5zM5.13,16.07C6.44,15.39 7.92,15 9.5,15c1.06,0 2.07,0.18 3.02,0.5c-1.6,0.85 -2.89,2.21 -3.68,3.85C7.28,18.67 5.99,17.52 5.13,16.07zM12,20c-0.59,0 -1.17,-0.07 -1.72,-0.19c0.31,-0.6 2.13,-3.81 6.22,-3.81c0.77,0 1.51,0.13 2.2,0.36C17.27,18.54 14.78,20 12,20zM16.5,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5S19,10.62 19,12C19,13.38 17.88,14.5 16.5,14.5z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM15.61,8.34c1.07,0 1.93,0.86 1.93,1.93s-0.86,1.93 -1.93,1.93 -1.93,-0.86 -1.93,-1.93c-0.01,-1.07 0.86,-1.93 1.93,-1.93zM9.61,6.76c1.3,0 2.36,1.06 2.36,2.36s-1.06,2.36 -2.36,2.36 -2.36,-1.06 -2.36,-2.36c0,-1.31 1.05,-2.36 2.36,-2.36zM9.61,15.89v3.75c-2.4,-0.75 -4.3,-2.6 -5.14,-4.96 1.05,-1.12 3.67,-1.69 5.14,-1.69 0.53,0 1.2,0.08 1.9,0.22 -1.64,0.87 -1.9,2.02 -1.9,2.68zM12,20c-0.27,0 -0.53,-0.01 -0.79,-0.04v-4.07c0,-1.42 2.94,-2.13 4.4,-2.13 1.07,0 2.92,0.39 3.84,1.15C18.28,17.88 15.39,20 12,20z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/supervisor_account.xml b/compose/material/material/icons/generator/raw-icons/rounded/supervisor_account.xml
index e93c666..f2ae882 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/supervisor_account.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/supervisor_account.xml
@@ -6,17 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.64,15.17v0.01V15.17C10.65,15.17 10.64,15.17 10.64,15.17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22,19l0,-0.41c0,-0.79 -0.46,-1.53 -1.19,-1.83C19.64,16.27 18.35,16 17,16s-2.64,0.27 -3.81,0.76C12.46,17.06 12,17.8 12,18.59L12,19c0,0.55 0.45,1 1,1h8C21.55,20 22,19.55 22,19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,4C7.79,4 6,5.79 6,8c0,2.21 1.79,4 4,4s4,-1.79 4,-4C14,5.79 12.21,4 10,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,13.4c-1.06,-0.25 -2.12,-0.4 -3,-0.4c-2.67,0 -8,1.34 -8,4v2c0,0.55 0.45,1 1,1h7v-1.41c0,-2.94 2.55,-3.72 3,-3.88V13.4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+ android:pathData="M16.5,12c1.38,0 2.49,-1.12 2.49,-2.5S17.88,7 16.5,7 14,8.12 14,9.5s1.12,2.5 2.5,2.5zM9,11c1.66,0 2.99,-1.34 2.99,-3S10.66,5 9,5 6,6.34 6,8s1.34,3 3,3zM16.5,14c-1.83,0 -5.5,0.92 -5.5,2.75L11,18c0,0.55 0.45,1 1,1h9c0.55,0 1,-0.45 1,-1v-1.25c0,-1.83 -3.67,-2.75 -5.5,-2.75zM9,13c-2.33,0 -7,1.17 -7,3.5L2,18c0,0.55 0.45,1 1,1h6v-2.25c0,-0.85 0.33,-2.34 2.37,-3.47C10.5,13.1 9.66,13 9,13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/support.xml b/compose/material/material/icons/generator/raw-icons/rounded/support.xml
index bffbd8d..b9b10ed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/support.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/support.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM19.46,9.12l-2.78,1.15c-0.51,-1.36 -1.58,-2.44 -2.95,-2.94l1.15,-2.78C16.98,5.35 18.65,7.02 19.46,9.12zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S13.66,15 12,15zM9.13,4.54l1.17,2.78c-1.38,0.5 -2.47,1.59 -2.98,2.97L4.54,9.13C5.35,7.02 7.02,5.35 9.13,4.54zM4.54,14.87l2.78,-1.15c0.51,1.38 1.59,2.46 2.97,2.96l-1.17,2.78C7.02,18.65 5.35,16.98 4.54,14.87zM14.88,19.46l-1.15,-2.78c1.37,-0.51 2.45,-1.59 2.95,-2.97l2.78,1.17C18.65,16.98 16.98,18.65 14.88,19.46z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM19.46,9.12l-2.78,1.15c-0.51,-1.36 -1.58,-2.44 -2.95,-2.94l1.15,-2.78C16.98,5.35 18.65,7.02 19.46,9.12zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S13.66,15 12,15zM9.13,4.54l1.17,2.78c-1.38,0.5 -2.47,1.59 -2.98,2.97L4.54,9.13C5.35,7.02 7.02,5.35 9.13,4.54zM4.54,14.87l2.78,-1.15c0.51,1.38 1.59,2.46 2.97,2.96l-1.17,2.78C7.02,18.65 5.35,16.98 4.54,14.87zM14.88,19.46l-1.15,-2.78c1.37,-0.51 2.45,-1.59 2.95,-2.97l2.78,1.17C18.65,16.98 16.98,18.65 14.88,19.46z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/surround_sound.xml b/compose/material/material/icons/generator/raw-icons/rounded/surround_sound.xml
index 00d59df..deaa997 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/surround_sound.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/surround_sound.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM7.82,16.18L7.82,16.18c-0.43,0.43 -1.15,0.4 -1.5,-0.09C5.49,14.94 5,13.53 5,12c0,-1.53 0.49,-2.94 1.32,-4.09c0.35,-0.49 1.08,-0.52 1.5,-0.09l0,0c0.35,0.35 0.38,0.9 0.09,1.31C7.34,9.94 7,10.93 7,12c0,1.07 0.34,2.06 0.91,2.87C8.2,15.28 8.17,15.83 7.82,16.18zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S13.66,15 12,15zM16.18,16.18L16.18,16.18c-0.35,-0.35 -0.38,-0.9 -0.09,-1.31C16.66,14.06 17,13.07 17,12c0,-1.07 -0.34,-2.06 -0.91,-2.87c-0.29,-0.41 -0.26,-0.95 0.09,-1.31l0,0c0.43,-0.43 1.15,-0.4 1.5,0.09C18.51,9.06 19,10.47 19,12c0,1.53 -0.49,2.94 -1.32,4.09C17.33,16.58 16.61,16.61 16.18,16.18z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM7.11,16.89c-0.43,0.43 -1.14,0.39 -1.51,-0.09C4.53,15.39 4,13.69 4,12s0.53,-3.38 1.59,-4.8c0.37,-0.48 1.08,-0.53 1.51,-0.1 0.35,0.35 0.39,0.9 0.1,1.29C6.4,9.46 6,10.73 6,12s0.4,2.53 1.2,3.6c0.3,0.39 0.26,0.94 -0.09,1.29zM12,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4zM16.9,16.9c-0.35,-0.35 -0.39,-0.9 -0.09,-1.29C17.6,14.54 18,13.27 18,12s-0.4,-2.53 -1.2,-3.6c-0.3,-0.39 -0.26,-0.95 0.09,-1.3 0.43,-0.43 1.14,-0.39 1.51,0.09 1.07,1.41 1.6,3.1 1.6,4.8 0,1.69 -0.53,3.38 -1.59,4.8 -0.37,0.49 -1.08,0.54 -1.51,0.11zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/swap_calls.xml b/compose/material/material/icons/generator/raw-icons/rounded/swap_calls.xml
index 882642a..bc19ba9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/swap_calls.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/swap_calls.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.65,4.35l-2.79,2.79C14.54,7.46 14.76,8 15.21,8H17v6.88c0,1 -0.67,1.93 -1.66,2.09C14.09,17.18 13,16.21 13,15V8.17c0,-2.09 -1.53,-3.95 -3.61,-4.15C7.01,3.79 5,5.66 5,8v7H3.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79C9.46,15.54 9.24,15 8.79,15H7V8.12c0,-1 0.67,-1.93 1.66,-2.09C9.91,5.82 11,6.79 11,8v6.83c0,2.09 1.53,3.95 3.61,4.15C16.99,19.21 19,17.34 19,15V8h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79C18.16,4.16 17.84,4.16 17.65,4.35z"/>
+ android:pathData="M17.65,4.35l-2.79,2.79c-0.32,0.32 -0.1,0.86 0.35,0.86H17v6.88c0,1 -0.67,1.93 -1.66,2.09 -1.25,0.21 -2.34,-0.76 -2.34,-1.97V8.17c0,-2.09 -1.53,-3.95 -3.61,-4.15C7.01,3.79 5,5.66 5,8v7H3.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.36,-0.85H7V8.12c0,-1 0.67,-1.93 1.66,-2.09C9.91,5.82 11,6.79 11,8v6.83c0,2.09 1.53,3.95 3.61,4.15C16.99,19.21 19,17.34 19,15V8h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79c-0.19,-0.2 -0.51,-0.2 -0.7,-0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/swap_horiz.xml b/compose/material/material/icons/generator/raw-icons/rounded/swap_horiz.xml
index dcae18a..456800b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/swap_horiz.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/swap_horiz.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.14,11.86l-2.78,2.79c-0.19,0.2 -0.19,0.51 0,0.71l2.78,2.79c0.31,0.32 0.85,0.09 0.85,-0.35V16H12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5.99v-1.79C5.99,11.76 5.45,11.54 5.14,11.86zM21.65,8.65l-2.78,-2.79c-0.31,-0.32 -0.85,-0.09 -0.85,0.35V8H12c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6.01v1.79c0,0.45 0.54,0.67 0.85,0.35l2.78,-2.79C21.84,9.16 21.84,8.84 21.65,8.65z"/>
+ android:pathData="M6.14,11.86l-2.78,2.79c-0.19,0.2 -0.19,0.51 0,0.71l2.78,2.79c0.31,0.32 0.85,0.09 0.85,-0.35L6.99,16L13,16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6.99,14v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35zM20.65,8.65l-2.78,-2.79c-0.31,-0.32 -0.85,-0.09 -0.85,0.35L17.02,8L11,8c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6.01v1.79c0,0.45 0.54,0.67 0.85,0.35l2.78,-2.79c0.2,-0.19 0.2,-0.51 0.01,-0.7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/swap_horizontal_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/swap_horizontal_circle.xml
index 7a86b30..843dc05 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/swap_horizontal_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/swap_horizontal_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12s4.48,10 10,10S22,17.52 22,12zM15.85,7.35l2.3,2.3c0.2,0.2 0.2,0.51 0,0.71l-2.3,2.29C15.54,12.96 15,12.74 15,12.3V11h-3c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h3V7.71C15,7.26 15.54,7.04 15.85,7.35zM8.15,16.65l-2.3,-2.3c-0.2,-0.2 -0.2,-0.51 0,-0.71l2.3,-2.29C8.46,11.04 9,11.26 9,11.7V13h3c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H9v1.29C9,16.74 8.46,16.96 8.15,16.65z"/>
+ android:pathData="M22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10zM15,6.5l3.15,3.15c0.2,0.2 0.2,0.51 0,0.71L15,13.5L15,11h-4L11,9h4L15,6.5zM9,17.5l-3.15,-3.15c-0.2,-0.2 -0.2,-0.51 0,-0.71L9,10.5L9,13h4v2L9,15v2.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/swap_vert.xml b/compose/material/material/icons/generator/raw-icons/rounded/swap_vert.xml
index bc4cddc..1af00b0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/swap_vert.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/swap_vert.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,17.01V11c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6.01h-1.79c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.78c0.2,0.19 0.51,0.19 0.71,0l2.79,-2.78c0.32,-0.31 0.09,-0.85 -0.35,-0.85H16zM8.65,3.35L5.86,6.14c-0.32,0.31 -0.1,0.85 0.35,0.85H8V13c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6.99h1.79c0.45,0 0.67,-0.54 0.35,-0.85L9.35,3.35C9.16,3.16 8.84,3.16 8.65,3.35z"/>
+ android:pathData="M16,17.01V11c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6.01h-1.79c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.78c0.2,0.19 0.51,0.19 0.71,0l2.79,-2.78c0.32,-0.31 0.09,-0.85 -0.35,-0.85H16zM8.65,3.35L5.86,6.14c-0.32,0.31 -0.1,0.85 0.35,0.85H8V13c0,0.55 0.45,1 1,1s1,-0.45 1,-1V6.99h1.79c0.45,0 0.67,-0.54 0.35,-0.85L9.35,3.35c-0.19,-0.19 -0.51,-0.19 -0.7,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/swap_vertical_circle.xml b/compose/material/material/icons/generator/raw-icons/rounded/swap_vertical_circle.xml
index 08e954d..a4e5b7f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/swap_vertical_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/swap_vertical_circle.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7.35,8.15l2.3,-2.3c0.2,-0.2 0.51,-0.2 0.71,0l2.29,2.3C12.96,8.46 12.74,9 12.3,9H11v3c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1V9H7.71C7.26,9 7.04,8.46 7.35,8.15zM14.35,18.15c-0.2,0.2 -0.51,0.2 -0.71,0l-2.29,-2.3C11.04,15.54 11.26,15 11.7,15H13v-3c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3h1.29c0.45,0 0.67,0.54 0.35,0.85L14.35,18.15z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM6.5,9l3.15,-3.15c0.2,-0.2 0.51,-0.2 0.71,0L13.5,9L11,9v4L9,13L9,9L6.5,9zM14.35,18.15c-0.2,0.2 -0.51,0.2 -0.71,0L10.5,15L13,15v-4h2v4h2.5l-3.15,3.15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/switch_access_shortcut.xml b/compose/material/material/icons/generator/raw-icons/rounded/switch_access_shortcut.xml
new file mode 100644
index 0000000..2116f5f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/switch_access_shortcut.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM19,20.41c0,0.78 -0.84,1.25 -1.51,0.86C14.21,19.36 12,15.79 12,12c0,-2.73 1.08,-5.27 2.75,-7.25l-1.9,-1.9C12.54,2.54 12.76,2 13.21,2h5.29C18.78,2 19,2.22 19,2.5v5.29c0,0.45 -0.54,0.67 -0.85,0.35l-1.97,-1.97C14.84,7.82 14,9.88 14,12c0,3.13 1.86,6.01 4.51,7.55C18.81,19.73 19,20.06 19,20.41z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/switch_access_shortcut_add.xml b/compose/material/material/icons/generator/raw-icons/rounded/switch_access_shortcut_add.xml
new file mode 100644
index 0000000..91ce3c7
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/switch_access_shortcut_add.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,18c0.55,0 1,-0.45 1,-1v-1h1c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-1v-1c0,-0.55 -0.45,-1 -1,-1c-0.55,0 -1,0.45 -1,1v1h-1c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h1v1C20,17.55 20.45,18 21,18zM7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM19,20.41c0,0.78 -0.84,1.25 -1.51,0.86C14.21,19.36 12,15.79 12,12c0,-2.73 1.08,-5.27 2.75,-7.25l-1.9,-1.9C12.54,2.54 12.76,2 13.21,2h5.29C18.78,2 19,2.22 19,2.5v5.29c0,0.45 -0.54,0.67 -0.85,0.35l-1.97,-1.97C14.84,7.82 14,9.88 14,12c0,3.13 1.86,6.01 4.51,7.55C18.81,19.73 19,20.06 19,20.41z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/switch_camera.xml b/compose/material/material/icons/generator/raw-icons/rounded/switch_camera.xml
index a03b768..c856dac 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/switch_camera.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/switch_camera.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,5h-3.17l-1.24,-1.35C15.22,3.24 14.68,3 14.12,3H9.88C9.32,3 8.78,3.24 8.4,3.65L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM18.65,13.35l-2.79,2.79C15.54,16.46 15,16.24 15,15.79v-1.75H9v1.75c0,0.45 -0.54,0.67 -0.85,0.35l-2.79,-2.79c-0.2,-0.2 -0.2,-0.51 0,-0.71l2.79,-2.79C8.46,9.54 9,9.76 9,10.21v1.83h6v-1.83c0,-0.45 0.54,-0.67 0.85,-0.35l2.79,2.79C18.84,12.84 18.84,13.16 18.65,13.35z"/>
+ android:pathData="M20,4h-3.17l-1.24,-1.35c-0.37,-0.41 -0.91,-0.65 -1.47,-0.65L9.88,2c-0.56,0 -1.1,0.24 -1.48,0.65L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM15,15.5L15,13L9,13v2.5l-3.15,-3.15c-0.2,-0.2 -0.2,-0.51 0,-0.71L9,8.5L9,11h6L15,8.5l3.15,3.15c0.2,0.2 0.2,0.51 0,0.71L15,15.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/switch_video.xml b/compose/material/material/icons/generator/raw-icons/rounded/switch_video.xml
index f30d805..bd20128 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/switch_video.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/switch_video.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,10.48V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l2.29,2.28c0.63,0.63 1.71,0.18 1.71,-0.71V8.91c0,-0.89 -1.07,-1.34 -1.71,-0.71L18,10.48zM12.5,14.29V13h-5v1.29c0,0.45 -0.54,0.67 -0.85,0.35l-2.29,-2.29c-0.2,-0.2 -0.2,-0.51 0,-0.71l2.29,-2.29C6.96,9.04 7.5,9.26 7.5,9.71V11h5V9.71c0,-0.45 0.54,-0.67 0.85,-0.35l2.29,2.29c0.2,0.2 0.2,0.51 0,0.71l-2.29,2.29C13.04,14.96 12.5,14.74 12.5,14.29z"/>
+ android:pathData="M18,9.5L18,6c0,-0.55 -0.45,-1 -1,-1L3,5c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-3.5l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71L22,7.91c0,-0.89 -1.08,-1.34 -1.71,-0.71L18,9.5zM13,15.5L13,13L7,13v2.5l-3.15,-3.15c-0.2,-0.2 -0.2,-0.51 0,-0.71L7,8.5L7,11h6L13,8.5l3.15,3.15c0.2,0.2 0.2,0.51 0,0.71L13,15.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sync.xml b/compose/material/material/icons/generator/raw-icons/rounded/sync.xml
index 32e858a..0ea3056 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sync.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sync.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,12c0,2.21 0.9,4.2 2.35,5.65l-1.5,1.5C4.54,19.46 4.76,20 5.21,20H9.5c0.28,0 0.5,-0.22 0.5,-0.5v-4.29c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.38,1.38C6.68,15.15 6,13.65 6,12c0,-2.39 1.41,-4.45 3.43,-5.41C9.77,6.43 10,6.11 10,5.74V5.56c0,-0.68 -0.71,-1.11 -1.33,-0.83C5.92,6 4,8.77 4,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.79,4H14.5C14.22,4 14,4.22 14,4.5v4.29c0,0.45 0.54,0.67 0.85,0.35l1.38,-1.38C17.32,8.85 18,10.35 18,12c0,2.39 -1.41,4.45 -3.43,5.41C14.23,17.57 14,17.89 14,18.26v0.18c0,0.68 0.71,1.11 1.33,0.83C18.08,18 20,15.23 20,12c0,-2.21 -0.9,-4.2 -2.35,-5.65l1.5,-1.5C19.46,4.54 19.24,4 18.79,4z"/>
+ android:pathData="M12,4L12,2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.8,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.32,0.31 0.86,0.09 0.86,-0.36L12,6c3.31,0 6,2.69 6,6 0,0.79 -0.15,1.56 -0.44,2.25 -0.15,0.36 -0.04,0.77 0.23,1.04 0.51,0.51 1.37,0.33 1.64,-0.34 0.37,-0.91 0.57,-1.91 0.57,-2.95 0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-0.79 0.15,-1.56 0.44,-2.25 0.15,-0.36 0.04,-0.77 -0.23,-1.04 -0.51,-0.51 -1.37,-0.33 -1.64,0.34C4.2,9.96 4,10.96 4,12c0,4.42 3.58,8 8,8v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L12,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sync_disabled.xml b/compose/material/material/icons/generator/raw-icons/rounded/sync_disabled.xml
index 3de4978f..73df03c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sync_disabled.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sync_disabled.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.85,9.15l1.4,-1.39c1.94,1.94 2.17,4.67 1.16,6.81l1.48,1.48c1.73,-2.95 1.56,-6.93 -1.22,-9.71l1.49,-1.49C19.47,4.54 19.24,4 18.8,4l-4.3,0C14.22,4 14,4.22 14,4.5v4.3C14,9.24 14.54,9.47 14.85,9.15zM10.01,5.75V5.59c0,-0.66 -0.68,-1.13 -1.28,-0.86C8.45,4.84 8.2,4.98 7.95,5.13L9.43,6.6C9.77,6.44 10.01,6.12 10.01,5.75zM20.49,20.49L3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l3.03,3.03c-1.73,2.95 -1.56,6.93 1.22,9.71l-1.49,1.48C4.54,19.46 4.76,20 5.21,20H9.5c0.28,0 0.5,-0.22 0.5,-0.5v-4.29c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.38,1.39c-1.91,-1.91 -2.19,-4.64 -1.16,-6.81l7.98,7.98c-0.34,0.16 -0.58,0.48 -0.58,0.86v0.15c0,0.66 0.68,1.13 1.28,0.87c0.27,-0.12 0.52,-0.26 0.77,-0.4l3.02,3.02c0.39,0.39 1.02,0.39 1.41,0C20.88,21.51 20.88,20.88 20.49,20.49z"/>
+ android:pathData="M10,5.74v-0.19c0,-0.68 -0.71,-1.11 -1.32,-0.82 -0.19,0.09 -0.36,0.2 -0.54,0.3L9.6,6.49c0.24,-0.18 0.4,-0.45 0.4,-0.75zM20,12c0,-2.21 -0.91,-4.2 -2.36,-5.64l1.51,-1.51c0.31,-0.31 0.09,-0.85 -0.36,-0.85H14v4.79c0,0.45 0.54,0.67 0.85,0.35l1.39,-1.39C17.32,8.85 18,10.34 18,12c0,0.85 -0.18,1.66 -0.5,2.39l1.48,1.48C19.62,14.72 20,13.41 20,12zM3.57,4.7c-0.39,0.39 -0.39,1.02 0,1.41l1.65,1.65C4.45,9 4,10.44 4,12c0,2.21 0.91,4.2 2.36,5.64l-1.51,1.51c-0.31,0.31 -0.09,0.85 0.36,0.85H9.5c0.28,0 0.5,-0.22 0.5,-0.5v-4.29c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.39,1.39C6.68,15.15 6,13.66 6,12c0,-1 0.26,-1.93 0.69,-2.76l8.07,8.07c-0.01,0.02 -0.01,0.02 -0.01,0.04 -0.43,0.12 -0.75,0.48 -0.75,0.91v0.18c0,0.68 0.71,1.11 1.32,0.82 0.31,-0.14 0.61,-0.31 0.9,-0.49l1.87,1.87c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.98,4.7c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/sync_problem.xml b/compose/material/material/icons/generator/raw-icons/rounded/sync_problem.xml
index 8eed6a7..875b299 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/sync_problem.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/sync_problem.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,7c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1V8C13,7.45 12.55,7 12,7zM12,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1s1,-0.45 1,-1S12.55,15 12,15zM7.72,4.73C2.8,6.91 1.26,13.58 5.34,17.66l-1.49,1.48C3.54,19.46 3.76,20 4.21,20H8.5C8.77,20 9,19.78 9,19.5v-4.29c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.38,1.39C3.81,13.3 4.73,8.35 8.43,6.6C8.77,6.44 9,6.12 9,5.75V5.59C9,4.93 8.32,4.46 7.72,4.73zM18.66,6.35l1.49,-1.49C20.46,4.54 20.24,4 19.79,4l-4.3,0c-0.28,0 -0.5,0.22 -0.5,0.5v4.3c0,0.44 0.54,0.67 0.85,0.35l1.4,-1.39c3.03,3.03 1.91,7.98 -1.66,9.65C15.24,17.57 15,17.89 15,18.27v0.15c0,0.66 0.68,1.13 1.28,0.87C21.2,17.1 22.74,10.43 18.66,6.35z"/>
+ android:pathData="M3,12c0,2.21 0.91,4.2 2.36,5.64l-1.51,1.51c-0.31,0.31 -0.09,0.85 0.36,0.85L8.5,20c0.28,0 0.5,-0.22 0.5,-0.5v-4.29c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.39,1.39C5.68,15.15 5,13.66 5,12c0,-2.39 1.4,-4.46 3.43,-5.42 0.34,-0.16 0.57,-0.47 0.57,-0.84v-0.19c0,-0.68 -0.71,-1.11 -1.32,-0.82C4.92,5.99 3,8.77 3,12zM11,17h2v-2h-2v2zM19.79,4L15.5,4c-0.28,0 -0.5,0.22 -0.5,0.5v4.29c0,0.45 0.54,0.67 0.85,0.35l1.39,-1.39C18.32,8.85 19,10.34 19,12c0,2.39 -1.4,4.46 -3.43,5.42 -0.34,0.16 -0.57,0.47 -0.57,0.84v0.18c0,0.68 0.71,1.11 1.32,0.82C19.08,18.01 21,15.23 21,12c0,-2.21 -0.91,-4.2 -2.36,-5.64l1.51,-1.51c0.31,-0.31 0.09,-0.85 -0.36,-0.85zM12,13c0.55,0 1,-0.45 1,-1L13,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/system_update.xml b/compose/material/material/icons/generator/raw-icons/rounded/system_update.xml
index f17c1de..8136e6d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/system_update.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/system_update.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,18H7V6h10V18zM14.79,12.21H13V9c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v3.21H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79C15.46,12.75 15.24,12.21 14.79,12.21z"/>
+ android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM14.79,13L13,13L13,9c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4L9.21,13c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.36,-0.85z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/system_update_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/system_update_alt.xml
index 08c8526..ad19875 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/system_update_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/system_update_alt.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.85,11.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.32,-0.31 0.09,-0.85 -0.35,-0.85H13V5c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v6H9.21C8.76,11 8.54,11.54 8.85,11.85z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,4h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4v12H4V6h4c0.55,0 1,-0.45 1,-1S8.55,4 8,4H4C2.9,4 2,4.89 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4z"/>
+ android:pathData="M12.35,15.65l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85H13V4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.19,0.2 0.51,0.2 0.7,0.01zM21,3h-5.01c-0.54,0 -0.99,0.45 -0.99,0.99 0,0.55 0.45,0.99 0.99,0.99H20c0.55,0 1,0.45 1,1v12.03c0,0.55 -0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1V5.99c0,-0.55 0.45,-1 1,-1h4.01c0.54,0 0.99,-0.45 0.99,-0.99 0,-0.55 -0.45,-1 -0.99,-1H3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tab.xml b/compose/material/material/icons/generator/raw-icons/rounded/tab.xml
index 431306d..b236027 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tab.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tab.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,18H4V6h9v2c0,1.1 0.9,2 2,2h5V18z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM20,19L4,19c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h9v3c0,0.55 0.45,1 1,1h7v9c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tab_unselected.xml b/compose/material/material/icons/generator/raw-icons/rounded/tab_unselected.xml
index 8345624..89471a7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tab_unselected.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tab_unselected.xml
@@ -6,35 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,18h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8,4h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,4h-8v4c0,1.1 0.9,2 2,2h8V6C22,4.9 21.1,4 20,4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,18L20,18l-2,0v2l2,0c1.1,0 2,-0.9 2,-2v-2h-2V18z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,18h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,12h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2,14h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2,10h2v2h-2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,20L4,20l0,-2H2v0C2,19.1 2.9,20 4,20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,4H4C2.9,4 2,4.9 2,6v2h2V6h2V4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,18h2v2h-2z"/>
+ android:pathData="M1,9h2L3,7L1,7v2zM1,13h2v-2L1,11v2zM1,5h2L3,3c-1.1,0 -2,0.9 -2,2zM9,21h2v-2L9,19v2zM1,17h2v-2L1,15v2zM3,21v-2L1,19c0,1.1 0.9,2 2,2zM21,3h-8v5c0,0.55 0.45,1 1,1h9L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17h2v-2h-2v2zM9,5h2L11,3L9,3v2zM5,21h2v-2L5,19v2zM5,5h2L7,3L5,3v2zM21,21c1.1,0 2,-0.9 2,-2h-2v2zM21,13h2v-2h-2v2zM13,21h2v-2h-2v2zM17,21h2v-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/table_chart.xml b/compose/material/material/icons/generator/raw-icons/rounded/table_chart.xml
index 66821ec..ca6e494 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/table_chart.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/table_chart.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,10.02h5V21h-5V10.02zM17,21h3c1.1,0 2,-0.9 2,-2v-9h-5V21zM20,3H5C3.9,3 3,3.9 3,5v3h19V5C22,3.9 21.1,3 20,3zM3,19c0,1.1 0.9,2 2,2h3V10H3V19z"/>
+ android:pathData="M10,10.02h5L15,21h-5L10,10.02zM17,21h3c1.1,0 2,-0.9 2,-2v-9h-5v11zM20,3L5,3c-1.1,0 -2,0.9 -2,2v3h19L22,5c0,-1.1 -0.9,-2 -2,-2zM3,19c0,1.1 0.9,2 2,2h3L8,10L3,10v9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tablet.xml b/compose/material/material/icons/generator/raw-icons/rounded/tablet.xml
index 21adc25..66bb458 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tablet.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tablet.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M1.01,6L1,18c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2H3C1.9,4 1.01,4.9 1.01,6zM18,6v12H6V6H18z"/>
+ android:pathData="M21,4L3,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h18c1.1,0 1.99,-0.9 1.99,-2L23,6c0,-1.1 -0.9,-2 -2,-2zM19,18L5,18L5,6h14v12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tablet_android.xml b/compose/material/material/icons/generator/raw-icons/rounded/tablet_android.xml
index e8db985..196147c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tablet_android.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tablet_android.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,1H5C3.9,1 3,1.9 3,3v18c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V3C21,1.9 20.1,1 19,1zM13.5,20h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5l0,0c0,-0.28 0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5l0,0C14,19.78 13.78,20 13.5,20zM19,16H5V6h14V16z"/>
+ android:pathData="M18,0L6,0C4.34,0 3,1.34 3,3v18c0,1.66 1.34,3 3,3h12c1.66,0 3,-1.34 3,-3L21,3c0,-1.66 -1.34,-3 -3,-3zM13.5,22h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5s-0.22,0.5 -0.5,0.5zM19.25,19L4.75,19L4.75,3h14.5v16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tablet_mac.xml b/compose/material/material/icons/generator/raw-icons/rounded/tablet_mac.xml
index 44f98b5..84c2007 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tablet_mac.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tablet_mac.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,1H5C3.9,1 3,1.9 3,3v18c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V3C21,1.9 20.1,1 19,1zM12,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,20.5 12,20.5zM19,16H5V6h14V16z"/>
+ android:pathData="M18.5,0h-14C3.12,0 2,1.12 2,2.5v19C2,22.88 3.12,24 4.5,24h14c1.38,0 2.5,-1.12 2.5,-2.5v-19C21,1.12 19.88,0 18.5,0zM11.5,23c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19,19L4,19L4,3h15v16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tap_and_play.xml b/compose/material/material/icons/generator/raw-icons/rounded/tap_and_play.xml
index a188276..ad7463c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tap_and_play.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tap_and_play.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,21v2h2C7,21.9 6.1,21 5,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.2,17.12c-0.55,-0.1 -1.07,0.24 -1.18,0.78c-0.11,0.54 0.24,1.07 0.78,1.18c1.58,0.32 2.8,1.54 3.12,3.12C9.02,22.67 9.43,23 9.9,23c0.07,0 0.13,-0.01 0.2,-0.02c0.54,-0.11 0.89,-0.64 0.78,-1.18C10.4,19.44 8.56,17.6 6.2,17.12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v9h2V6h10v15h-1v2h1c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6.11,13.06c-0.56,-0.05 -1.04,0.34 -1.1,0.88c-0.06,0.55 0.33,1.04 0.88,1.1c3.68,0.41 6.65,3.38 7.06,7.06C13,22.62 13.44,23 13.94,23c0.04,0 0.07,0 0.11,-0.01c0.55,-0.06 0.94,-0.56 0.88,-1.1C14.43,17.29 10.71,13.57 6.11,13.06z"/>
+ android:pathData="M3.14,16.09c-0.6,-0.1 -1.14,0.39 -1.14,1 0,0.49 0.36,0.9 0.85,0.98 2.08,0.36 3.72,2 4.08,4.08 0.08,0.49 0.49,0.85 0.98,0.85 0.61,0 1.09,-0.54 1,-1.14 -0.48,-2.95 -2.81,-5.29 -5.77,-5.77zM2,20v3h3c0,-1.66 -1.34,-3 -3,-3zM3.11,12.06c-0.59,-0.06 -1.11,0.4 -1.11,0.99 0,0.5 0.37,0.94 0.87,0.99 4.27,0.41 7.67,3.81 8.08,8.08 0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1 -0.51,-5.2 -4.63,-9.32 -9.83,-9.84zM17,1.01L7,1c-1.1,0 -2,0.9 -2,2v7.37c0.69,0.16 1.36,0.37 2,0.64L7,5h10v13h-3.03c0.52,1.25 0.84,2.59 0.95,4L17,22c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/terrain.xml b/compose/material/material/icons/generator/raw-icons/rounded/terrain.xml
index 0b804bb..515fe49 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/terrain.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/terrain.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.2,7.07L10.25,11l2.25,3c0.33,0.44 0.24,1.07 -0.2,1.4l0,0c-0.44,0.33 -1.07,0.25 -1.4,-0.2c-1.05,-1.4 -2.31,-3.07 -3.1,-4.14c-0.4,-0.53 -1.2,-0.53 -1.6,0l-4,5.33C1.71,17.06 2.18,18 3,18h18c0.82,0 1.29,-0.94 0.8,-1.6l-7,-9.33C14.4,6.53 13.6,6.53 13.2,7.07z"/>
+ android:pathData="M13.2,7.07L10.25,11l2.25,3c0.33,0.44 0.24,1.07 -0.2,1.4 -0.44,0.33 -1.07,0.25 -1.4,-0.2 -1.05,-1.4 -2.31,-3.07 -3.1,-4.14 -0.4,-0.53 -1.2,-0.53 -1.6,0l-4,5.33c-0.49,0.67 -0.02,1.61 0.8,1.61h18c0.82,0 1.29,-0.94 0.8,-1.6l-7,-9.33c-0.4,-0.54 -1.2,-0.54 -1.6,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_fields.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_fields.xml
index b4407d9..9a62f73 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_fields.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_fields.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.5,4h-10C2.67,4 2,4.67 2,5.5v0C2,6.33 2.67,7 3.5,7H7v11.5C7,19.33 7.67,20 8.5,20h0c0.83,0 1.5,-0.67 1.5,-1.5V7h3.5C14.33,7 15,6.33 15,5.5v0C15,4.67 14.33,4 13.5,4zM22,10.5L22,10.5C22,9.67 21.33,9 20.5,9h-6C13.67,9 13,9.67 13,10.5v0c0,0.83 0.67,1.5 1.5,1.5H16v6.5c0,0.83 0.67,1.5 1.5,1.5h0c0.83,0 1.5,-0.67 1.5,-1.5V12h1.5C21.33,12 22,11.33 22,10.5z"/>
+ android:pathData="M2.5,5.5C2.5,6.33 3.17,7 4,7h3.5v10.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5V7H14c0.83,0 1.5,-0.67 1.5,-1.5S14.83,4 14,4H4c-0.83,0 -1.5,0.67 -1.5,1.5zM20,9h-6c-0.83,0 -1.5,0.67 -1.5,1.5S13.17,12 14,12h1.5v5.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5V12H20c0.83,0 1.5,-0.67 1.5,-1.5S20.83,9 20,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_format.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_format.xml
index 74f838f..a4c6756 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_format.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_format.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9.79,12.19h4.44L15,14.41c0.12,0.35 0.46,0.59 0.83,0.59h0.01c0.61,0 1.04,-0.61 0.82,-1.19l-3.34,-8.89C13.12,4.37 12.59,4 12,4h0c-0.59,0 -1.12,0.37 -1.33,0.92l-3.34,8.89C7.11,14.39 7.54,15 8.15,15h0.01c0.37,0 0.7,-0.23 0.83,-0.59L9.79,12.19zM11.95,6.04h0.09l1.6,4.55h-3.29L11.95,6.04zM18,19H6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v0C19,18.55 18.55,19 18,19z"/>
+ android:pathData="M5,18c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L6,17c-0.55,0 -1,0.45 -1,1zM9.5,12.8h5l0.66,1.6c0.15,0.36 0.5,0.6 0.89,0.6 0.69,0 1.15,-0.71 0.88,-1.34l-3.88,-8.97C12.87,4.27 12.46,4 12,4c-0.46,0 -0.87,0.27 -1.05,0.69l-3.88,8.97c-0.27,0.63 0.2,1.34 0.89,1.34 0.39,0 0.74,-0.24 0.89,-0.6l0.65,-1.6zM12,5.98L13.87,11h-3.74L12,5.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_up.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_up.xml
index 49cac9b..8680f49 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_up.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_up.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.65,3.35l-1.79,1.79C15.54,5.46 15.76,6 16.21,6H17v13c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V6h0.79c0.45,0 0.67,-0.54 0.35,-0.85l-1.79,-1.79C18.16,3.16 17.84,3.16 17.65,3.35zM3.92,13.33l8.88,3.34c0.58,0.22 1.2,-0.21 1.2,-0.83v0c0,-0.37 -0.24,-0.71 -0.59,-0.83l-2.22,-0.79V9.77L13.41,9C13.76,8.87 14,8.54 14,8.16v0c0,-0.62 -0.62,-1.05 -1.2,-0.83l-8.88,3.34C3.37,10.88 3,11.41 3,12v0C3,12.59 3.37,13.12 3.92,13.33zM5.04,11.95l4.55,-1.6v3.29l-4.55,-1.6V11.95z"/>
+ android:pathData="M18.35,4.35c-0.2,-0.2 -0.51,-0.2 -0.71,0l-1.79,1.79c-0.31,0.32 -0.09,0.86 0.36,0.86H17v12c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7h0.79c0.45,0 0.67,-0.54 0.35,-0.85l-1.79,-1.8zM11.8,15.5v-5l1.6,-0.66c0.36,-0.14 0.6,-0.49 0.6,-0.88 0,-0.69 -0.71,-1.15 -1.34,-0.88l-8.97,3.88c-0.42,0.17 -0.69,0.58 -0.69,1.04 0,0.46 0.27,0.87 0.69,1.05l8.97,3.88c0.63,0.27 1.34,-0.2 1.34,-0.89 0,-0.39 -0.24,-0.74 -0.6,-0.89l-1.6,-0.65zM4.98,13L10,11.13v3.74L4.98,13z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_vertical.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_vertical.xml
index ce5e0f8..303272e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_vertical.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_rotate_vertical.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,5L6,5C5.45,5 5,5.45 5,6v10H4.21c-0.45,0 -0.67,0.54 -0.35,0.85l1.79,1.79c0.2,0.2 0.51,0.2 0.71,0l1.79,-1.79C8.46,16.54 8.24,16 7.79,16H7V6C7,5.45 6.55,5 6,5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M16,6L16,6c-0.59,0 -1.12,0.37 -1.33,0.92l-3.34,8.88c-0.22,0.58 0.21,1.2 0.83,1.2h0c0.37,0 0.71,-0.24 0.83,-0.59l0.79,-2.22h4.44L19,16.41c0.12,0.35 0.46,0.59 0.83,0.59h0c0.62,0 1.05,-0.62 0.83,-1.2l-3.34,-8.88C17.12,6.37 16.59,6 16,6zM14.36,12.59l1.6,-4.55h0.09l1.6,4.55H14.36z"/>
+ android:pathData="M15,5c-0.46,0 -0.87,0.27 -1.05,0.69l-3.88,8.97c-0.27,0.63 0.2,1.34 0.89,1.34 0.39,0 0.74,-0.24 0.89,-0.6l0.66,-1.6h5l0.66,1.6c0.15,0.36 0.5,0.6 0.89,0.6 0.69,0 1.15,-0.71 0.88,-1.34l-3.88,-8.97C15.87,5.27 15.46,5 15,5zM13.13,12L15,6.98 16.87,12h-3.74zM6.35,19.64l1.79,-1.79c0.32,-0.31 0.1,-0.85 -0.35,-0.85L7,17L7,5c0,-0.55 -0.45,-1 -1,-1s-1,0.44 -1,1v12h-0.79c-0.45,0 -0.67,0.54 -0.35,0.85l1.79,1.79c0.19,0.2 0.51,0.2 0.7,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angledown.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angledown.xml
index ac1be0f..1e81ea3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angledown.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angledown.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.96,21h2.54c0.28,0 0.5,-0.22 0.5,-0.5v-2.54c0,-0.45 -0.54,-0.67 -0.85,-0.35l-0.56,0.56L4.39,8.98C4,8.59 3.37,8.59 2.98,8.98s-0.39,1.02 0,1.41l9.19,9.19l-0.56,0.56C11.3,20.46 11.52,21 11.96,21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.68,3.77L9.04,7.7c-0.56,0.26 -0.7,0.99 -0.26,1.43l0,0C9.05,9.39 9.45,9.46 9.79,9.3l2.13,-1.01l3.14,3.14l-1.02,2.12c-0.16,0.34 -0.09,0.74 0.17,1.01l0,0c0.44,0.44 1.18,0.3 1.43,-0.26l3.92,-8.64c0.24,-0.54 0.13,-1.17 -0.29,-1.59l0,0C18.86,3.64 18.22,3.53 17.68,3.77zM17.86,5.54l-2.09,4.35l-2.32,-2.32l4.35,-2.09L17.86,5.54z"/>
+ android:pathData="M15,20.5v-2.54c0,-0.45 -0.54,-0.67 -0.85,-0.35l-0.56,0.56L5.1,9.68c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l8.49,8.49 -0.56,0.56c-0.32,0.32 -0.1,0.86 0.34,0.86h2.54c0.28,0 0.5,-0.23 0.5,-0.5zM11.25,8.48l3.54,3.54 -0.67,1.6c-0.15,0.36 -0.07,0.77 0.21,1.05 0.49,0.49 1.31,0.32 1.57,-0.32l3.61,-9.09c0.17,-0.42 0.07,-0.91 -0.25,-1.23 -0.32,-0.32 -0.8,-0.42 -1.23,-0.25l-9.1,3.6c-0.64,0.25 -0.81,1.08 -0.32,1.57 0.27,0.27 0.68,0.35 1.04,0.2l1.6,-0.67zM17.84,5.43l-2.23,4.87 -2.64,-2.64 4.87,-2.23z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angleup.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angleup.xml
index 9a1fffb..72b83cf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angleup.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_angleup.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,12.04V9.5C21,9.23 20.78,9 20.5,9h-2.54c-0.45,0 -0.67,0.54 -0.35,0.85l0.56,0.56l-9.19,9.19c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0l9.19,-9.19l0.56,0.56C20.46,12.71 21,12.48 21,12.04z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.77,6.32l3.92,8.64c0.26,0.56 0.99,0.7 1.43,0.26l0,0c0.26,-0.26 0.33,-0.67 0.17,-1.01l-1.01,-2.13l3.14,-3.14l2.12,1.02c0.34,0.16 0.74,0.09 1.01,-0.17l0,0c0.44,-0.44 0.3,-1.18 -0.26,-1.43L5.65,4.44C5.11,4.19 4.48,4.31 4.06,4.73l0,0C3.64,5.14 3.53,5.78 3.77,6.32zM5.54,6.14l4.35,2.09l-2.32,2.32L5.47,6.2L5.54,6.14z"/>
+ android:pathData="M17.61,9.85l0.56,0.56 -8.48,8.49c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l8.49,-8.49 0.56,0.56c0.31,0.32 0.85,0.1 0.85,-0.34L21,9.5c0,-0.28 -0.22,-0.5 -0.5,-0.5h-2.54c-0.44,0 -0.66,0.54 -0.35,0.85zM8.48,12.75l3.54,-3.54 1.6,0.67c0.36,0.15 0.77,0.07 1.05,-0.21 0.49,-0.49 0.32,-1.31 -0.32,-1.57L5.26,4.5c-0.43,-0.16 -0.91,-0.06 -1.23,0.26 -0.32,0.32 -0.42,0.8 -0.25,1.23l3.61,9.09c0.25,0.64 1.08,0.81 1.57,0.32 0.28,-0.28 0.36,-0.69 0.21,-1.05l-0.69,-1.6zM7.66,11.03L5.43,6.16l4.87,2.23 -2.64,2.64z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_down.xml
index 728ac04..f5ee726 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_down.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_down.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.35,20.65l1.79,-1.79C8.46,18.54 8.24,18 7.79,18H7V5c0,-0.55 -0.45,-1 -1,-1h0C5.45,4 5,4.45 5,5v13H4.21c-0.45,0 -0.67,0.54 -0.35,0.85l1.79,1.79C5.84,20.84 6.16,20.84 6.35,20.65zM20.08,10.67L11.2,7.33C10.62,7.12 10,7.54 10,8.16v0c0,0.37 0.24,0.71 0.59,0.83l2.22,0.79v4.44L10.59,15C10.24,15.13 10,15.46 10,15.84v0c0,0.62 0.62,1.05 1.2,0.83l8.88,-3.34C20.63,13.12 21,12.59 21,12v0C21,11.41 20.63,10.88 20.08,10.67zM18.96,12.05l-4.55,1.6v-3.29l4.55,1.6V12.05z"/>
+ android:pathData="M6.35,19.65l1.79,-1.79c0.32,-0.32 0.1,-0.86 -0.35,-0.86L7,17L7,5c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v12h-0.79c-0.45,0 -0.67,0.54 -0.35,0.85l1.79,1.79c0.19,0.2 0.51,0.2 0.7,0.01zM12.2,8.5v5l-1.6,0.66c-0.36,0.15 -0.6,0.5 -0.6,0.89 0,0.69 0.71,1.15 1.34,0.88l8.97,-3.88c0.42,-0.18 0.69,-0.59 0.69,-1.05 0,-0.46 -0.27,-0.87 -0.69,-1.05l-8.97,-3.88c-0.63,-0.27 -1.34,0.2 -1.34,0.89 0,0.39 0.24,0.74 0.6,0.89l1.6,0.65zM19.02,11L14,12.87L14,9.13L19.02,11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_none.xml b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_none.xml
index 541ad5b..a564809 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_none.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/text_rotation_none.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.65,17.65l-1.79,-1.79C18.54,15.54 18,15.76 18,16.21V17H5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h13v0.79c0,0.45 0.54,0.67 0.85,0.35l1.79,-1.79C20.84,18.16 20.84,17.84 20.65,17.65zM10.67,3.92L7.33,12.8C7.12,13.38 7.54,14 8.16,14h0c0.37,0 0.71,-0.24 0.83,-0.59l0.79,-2.22h4.44L15,13.41c0.12,0.35 0.46,0.59 0.83,0.59h0c0.62,0 1.05,-0.62 0.83,-1.2l-3.34,-8.88C13.12,3.37 12.59,3 12,3h0C11.41,3 10.88,3.37 10.67,3.92zM12.05,5.04l1.6,4.55h-3.29l1.6,-4.55H12.05z"/>
+ android:pathData="M20.65,17.65l-1.79,-1.79c-0.32,-0.32 -0.86,-0.1 -0.86,0.35V17H6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12v0.79c0,0.45 0.54,0.67 0.85,0.35l1.79,-1.79c0.2,-0.19 0.2,-0.51 0.01,-0.7zM9.5,11.8h5l0.66,1.6c0.15,0.36 0.5,0.6 0.89,0.6 0.69,0 1.15,-0.71 0.88,-1.34l-3.88,-8.97C12.87,3.27 12.46,3 12,3c-0.46,0 -0.87,0.27 -1.05,0.69l-3.88,8.97c-0.27,0.63 0.2,1.34 0.89,1.34 0.39,0 0.74,-0.24 0.89,-0.6l0.65,-1.6zM12,4.98L13.87,10h-3.74L12,4.98z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/textsms.xml b/compose/material/material/icons/generator/raw-icons/rounded/textsms.xml
index 5cebe5f..ab72164 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/textsms.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/textsms.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2.01,2.9 2.01,4L2,19.58c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM8,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S8.55,11 8,11zM12,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S12.55,11 12,11zM16,11c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S16.55,11 16,11z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM9,11L7,11L7,9h2v2zM13,11h-2L11,9h2v2zM17,11h-2L15,9h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/texture.xml b/compose/material/material/icons/generator/raw-icons/rounded/texture.xml
index a65d026..47894fc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/texture.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/texture.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.58,3.08L3.15,19.51c0.09,0.34 0.27,0.65 0.51,0.9c0.25,0.24 0.56,0.42 0.9,0.51L21,4.49C20.81,3.8 20.27,3.26 19.58,3.08zM11.95,3l-8.88,8.88v2.83L14.78,3H11.95zM5.07,3c-1.1,0 -2,0.9 -2,2v2l4,-4H5.07zM19.07,21c0.55,0 1.05,-0.22 1.41,-0.59c0.37,-0.36 0.59,-0.86 0.59,-1.41v-2l-4,4H19.07zM9.36,21h2.83l8.88,-8.88V9.29L9.36,21z"/>
+ android:pathData="M19.58,3.08L3.15,19.51c0.09,0.34 0.27,0.65 0.51,0.9 0.25,0.24 0.56,0.42 0.9,0.51L21,4.49c-0.19,-0.69 -0.73,-1.23 -1.42,-1.41zM11.95,3l-8.88,8.88v2.83L14.78,3h-2.83zM5.07,3c-1.1,0 -2,0.9 -2,2v2l4,-4h-2zM19.07,21c0.55,0 1.05,-0.22 1.41,-0.59 0.37,-0.36 0.59,-0.86 0.59,-1.41v-2l-4,4h2zM9.36,21h2.83l8.88,-8.88L21.07,9.29L9.36,21z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/theaters.xml b/compose/material/material/icons/generator/raw-icons/rounded/theaters.xml
index f0d6236..3fe1f95 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/theaters.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/theaters.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,4v1h-2V4c0,-0.55 -0.45,-1 -1,-1H9C8.45,3 8,3.45 8,4v1H6V4c0,-0.55 -0.45,-1 -1,-1S4,3.45 4,4v16c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1S18,3.45 18,4zM8,17H6v-2h2V17zM8,13H6v-2h2V13zM8,9H6V7h2V9zM18,17h-2v-2h2V17zM18,13h-2v-2h2V13zM18,9h-2V7h2V9z"/>
+ android:pathData="M18,4v1h-2L16,4c0,-0.55 -0.45,-1 -1,-1L9,3c-0.55,0 -1,0.45 -1,1v1L6,5L6,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v16c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1L20,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM8,17L6,17v-2h2v2zM8,13L6,13v-2h2v2zM8,9L6,9L6,7h2v2zM18,17h-2v-2h2v2zM18,13h-2v-2h2v2zM18,9h-2L16,7h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/thermostat.xml b/compose/material/material/icons/generator/raw-icons/rounded/thermostat.xml
index 06fdc13..7c4e852 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/thermostat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/thermostat.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,13V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v8c-1.21,0.91 -2,2.37 -2,4c0,2.76 2.24,5 5,5s5,-2.24 5,-5C17,15.37 16.21,13.91 15,13zM11,11V5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v1h-1v1h1v1v1h-1v1h1v1H11z"/>
+ android:pathData="M15,13L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v8c-1.21,0.91 -2,2.37 -2,4 0,2.76 2.24,5 5,5s5,-2.24 5,-5c0,-1.63 -0.79,-3.09 -2,-4zM13,11h-2L11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1h-0.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h0.5v2h-0.5c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5h0.5v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/thumb_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/thumb_down.xml
index eebae44..a708b03 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/thumb_down.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/thumb_down.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.88,21.94l5.53,-5.54c0.37,-0.37 0.58,-0.88 0.58,-1.41V5c0,-1.1 -0.9,-2 -2,-2H6C5.2,3 4.48,3.48 4.17,4.21l-3.26,7.61C0.06,13.8 1.51,16 3.66,16h5.65l-0.95,4.58c-0.1,0.5 0.05,1.01 0.41,1.37C9.36,22.53 10.3,22.53 10.88,21.94zM21,3c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2s2,-0.9 2,-2V5C23,3.9 22.1,3 21,3z"/>
+ android:pathData="M10.88,21.94l5.53,-5.54c0.37,-0.37 0.58,-0.88 0.58,-1.41V5c0,-1.1 -0.9,-2 -2,-2H6c-0.8,0 -1.52,0.48 -1.83,1.21L0.91,11.82C0.06,13.8 1.51,16 3.66,16h5.65l-0.95,4.58c-0.1,0.5 0.05,1.01 0.41,1.37 0.59,0.58 1.53,0.58 2.11,-0.01zM21,3c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2s2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/thumb_down_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/thumb_down_alt.xml
index eebae44..a708b03 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/thumb_down_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/thumb_down_alt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.88,21.94l5.53,-5.54c0.37,-0.37 0.58,-0.88 0.58,-1.41V5c0,-1.1 -0.9,-2 -2,-2H6C5.2,3 4.48,3.48 4.17,4.21l-3.26,7.61C0.06,13.8 1.51,16 3.66,16h5.65l-0.95,4.58c-0.1,0.5 0.05,1.01 0.41,1.37C9.36,22.53 10.3,22.53 10.88,21.94zM21,3c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2s2,-0.9 2,-2V5C23,3.9 22.1,3 21,3z"/>
+ android:pathData="M10.88,21.94l5.53,-5.54c0.37,-0.37 0.58,-0.88 0.58,-1.41V5c0,-1.1 -0.9,-2 -2,-2H6c-0.8,0 -1.52,0.48 -1.83,1.21L0.91,11.82C0.06,13.8 1.51,16 3.66,16h5.65l-0.95,4.58c-0.1,0.5 0.05,1.01 0.41,1.37 0.59,0.58 1.53,0.58 2.11,-0.01zM21,3c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2s2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/thumb_up.xml b/compose/material/material/icons/generator/raw-icons/rounded/thumb_up.xml
index 363e6e0..e20fc37 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/thumb_up.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/thumb_up.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.12,2.06L7.58,7.6C7.21,7.97 7,8.48 7,9.01V19c0,1.1 0.9,2 2,2h9c0.8,0 1.52,-0.48 1.84,-1.21l3.26,-7.61C23.94,10.2 22.49,8 20.34,8h-5.65l0.95,-4.58c0.1,-0.5 -0.05,-1.01 -0.41,-1.37C14.64,1.47 13.7,1.47 13.12,2.06zM3,21c1.1,0 2,-0.9 2,-2v-8c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v8C1,20.1 1.9,21 3,21z"/>
+ android:pathData="M13.12,2.06L7.58,7.6c-0.37,0.37 -0.58,0.88 -0.58,1.41V19c0,1.1 0.9,2 2,2h9c0.8,0 1.52,-0.48 1.84,-1.21l3.26,-7.61C23.94,10.2 22.49,8 20.34,8h-5.65l0.95,-4.58c0.1,-0.5 -0.05,-1.01 -0.41,-1.37 -0.59,-0.58 -1.53,-0.58 -2.11,0.01zM3,21c1.1,0 2,-0.9 2,-2v-8c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v8c0,1.1 0.9,2 2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/thumb_up_alt.xml b/compose/material/material/icons/generator/raw-icons/rounded/thumb_up_alt.xml
index 363e6e0..e20fc37 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/thumb_up_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/thumb_up_alt.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.12,2.06L7.58,7.6C7.21,7.97 7,8.48 7,9.01V19c0,1.1 0.9,2 2,2h9c0.8,0 1.52,-0.48 1.84,-1.21l3.26,-7.61C23.94,10.2 22.49,8 20.34,8h-5.65l0.95,-4.58c0.1,-0.5 -0.05,-1.01 -0.41,-1.37C14.64,1.47 13.7,1.47 13.12,2.06zM3,21c1.1,0 2,-0.9 2,-2v-8c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v8C1,20.1 1.9,21 3,21z"/>
+ android:pathData="M13.12,2.06L7.58,7.6c-0.37,0.37 -0.58,0.88 -0.58,1.41V19c0,1.1 0.9,2 2,2h9c0.8,0 1.52,-0.48 1.84,-1.21l3.26,-7.61C23.94,10.2 22.49,8 20.34,8h-5.65l0.95,-4.58c0.1,-0.5 -0.05,-1.01 -0.41,-1.37 -0.59,-0.58 -1.53,-0.58 -2.11,0.01zM3,21c1.1,0 2,-0.9 2,-2v-8c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v8c0,1.1 0.9,2 2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/thumbs_up_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/thumbs_up_down.xml
index 3896846..fed4b3f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/thumbs_up_down.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/thumbs_up_down.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.06,5H5.82l0.66,-3.18c0.08,-0.37 -0.04,-0.75 -0.3,-1.02c-0.44,-0.44 -1.15,-0.44 -1.58,0l-4,4C0.21,5.17 0,5.68 0,6.21V12c0,1.1 0.9,2 2,2h5.92c0.8,0 1.52,-0.48 1.84,-1.21l2.14,-5C12.46,6.47 11.49,5 10.06,5zM22,10h-5.92c-0.8,0 -1.52,0.48 -1.84,1.21l-2.14,5C11.54,17.53 12.5,19 13.94,19h4.24l-0.66,3.18c-0.08,0.37 0.04,0.75 0.3,1.02c0.44,0.44 1.15,0.44 1.58,0l4,-4c0.38,-0.38 0.59,-0.88 0.59,-1.41V12C24,10.9 23.1,10 22,10z"/>
+ android:pathData="M10.06,5H5.82l0.66,-3.18c0.08,-0.37 -0.04,-0.75 -0.3,-1.02C5.74,0.36 5.03,0.36 4.6,0.8l-4,4c-0.39,0.37 -0.6,0.88 -0.6,1.41V12c0,1.1 0.9,2 2,2h5.92c0.8,0 1.52,-0.48 1.84,-1.21l2.14,-5C12.46,6.47 11.49,5 10.06,5zM22,10h-5.92c-0.8,0 -1.52,0.48 -1.84,1.21l-2.14,5c-0.56,1.32 0.4,2.79 1.84,2.79h4.24l-0.66,3.18c-0.08,0.37 0.04,0.75 0.3,1.02 0.44,0.44 1.15,0.44 1.58,0l4,-4c0.38,-0.38 0.59,-0.88 0.59,-1.41V12c0.01,-1.1 -0.89,-2 -1.99,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/time_to_leave.xml b/compose/material/material/icons/generator/raw-icons/rounded/time_to_leave.xml
index fbfe158..f1714e4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/time_to_leave.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/time_to_leave.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5h-11C5.84,5 5.29,5.42 5.08,6.01L3,12v7.5C3,20.33 3.67,21 4.5,21h0C5.33,21 6,20.33 6,19.5V19h12v0.5c0,0.82 0.67,1.5 1.5,1.5h0c0.82,0 1.5,-0.67 1.5,-1.5V12L18.92,6.01zM7.5,16C6.67,16 6,15.33 6,14.5S6.67,13 7.5,13S9,13.67 9,14.5S8.33,16 7.5,16zM16.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S17.33,16 16.5,16zM5.81,10l1.04,-3h10.29l1.04,3H5.81z"/>
+ android:pathData="M18.92,5.01C18.72,4.42 18.16,4 17.5,4h-11c-0.66,0 -1.21,0.42 -1.42,1.01l-1.97,5.67c-0.07,0.21 -0.11,0.43 -0.11,0.66v7.16c0,0.83 0.67,1.5 1.5,1.5S6,19.33 6,18.5L6,18h12v0.5c0,0.82 0.67,1.5 1.5,1.5 0.82,0 1.5,-0.67 1.5,-1.5v-7.16c0,-0.22 -0.04,-0.45 -0.11,-0.66l-1.97,-5.67zM6.5,15c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,12 6.5,12s1.5,0.67 1.5,1.5S7.33,15 6.5,15zM17.5,15c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,10l1.27,-3.82c0.14,-0.4 0.52,-0.68 0.95,-0.68h9.56c0.43,0 0.81,0.28 0.95,0.68L19,10L5,10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/timelapse.xml b/compose/material/material/icons/generator/raw-icons/rounded/timelapse.xml
index c21db2f..b03e05f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/timelapse.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/timelapse.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.24,7.76c-0.88,-0.88 -1.96,-1.43 -3.1,-1.65C12.55,5.99 12,6.49 12,7.1V12l-3.46,3.46c-0.43,0.43 -0.39,1.17 0.11,1.52c2.33,1.57 5.53,1.33 7.6,-0.74C18.59,13.9 18.59,10.1 16.24,7.76zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20z"/>
+ android:pathData="M16.24,7.76C15.07,6.59 13.54,6 12,6v6l-4.24,4.24c2.34,2.34 6.14,2.34 8.49,0 2.34,-2.34 2.34,-6.14 -0.01,-8.48zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/timer.xml b/compose/material/material/icons/generator/raw-icons/rounded/timer.xml
index 731724e..dbbda58 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/timer.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/timer.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14,1h-4C9.45,1 9,1.45 9,2v0c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v0C15,1.45 14.55,1 14,1zM12,14L12,14c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v4C11,13.55 11.45,14 12,14zM19.03,7.39l0.75,-0.75c0.38,-0.38 0.39,-1.01 0,-1.4c0,0 -0.01,-0.01 -0.01,-0.01c-0.39,-0.39 -1.01,-0.38 -1.4,0l-0.75,0.75C16.07,4.74 14.12,4 12,4c-4.8,0 -8.88,3.96 -9,8.76C2.87,17.84 6.94,22 12,22c4.98,0 9,-4.03 9,-9C21,10.88 20.26,8.93 19.03,7.39zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7s7,3.13 7,7S15.87,20 12,20z"/>
+ android:pathData="M14,1h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM12,14c0.55,0 1,-0.45 1,-1L13,9c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM19.03,7.39l0.75,-0.75c0.38,-0.38 0.39,-1.01 0,-1.4l-0.01,-0.01c-0.39,-0.39 -1.01,-0.38 -1.4,0l-0.75,0.75C16.07,4.74 14.12,4 12,4c-4.8,0 -8.88,3.96 -9,8.76C2.87,17.84 6.94,22 12,22c4.98,0 9,-4.03 9,-9 0,-2.12 -0.74,-4.07 -1.97,-5.61zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/timer_10.xml b/compose/material/material/icons/generator/raw-icons/rounded/timer_10.xml
index 4ff9c7d..d707d2d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/timer_10.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/timer_10.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2.5,9.59L2.5,9.59c0.22,0.34 0.68,0.42 1.01,0.18l0.96,-0.7v7.15c0,0.42 0.34,0.77 0.77,0.77h0c0.42,0 0.77,-0.34 0.77,-0.77V7.81C6.01,7.36 5.65,7 5.2,7h0C5.03,7 4.86,7.05 4.72,7.15L2.68,8.63C2.37,8.85 2.29,9.28 2.5,9.59zM13.28,7.66C12.69,7.22 12,7 11.22,7c-0.78,0 -1.47,0.22 -2.07,0.66C8.56,8.09 8.1,8.69 7.78,9.45C7.45,10.21 7.29,11.06 7.29,12c0,0.93 0.16,1.78 0.48,2.53c0.32,0.76 0.78,1.36 1.38,1.8c0.6,0.44 1.28,0.66 2.07,0.66c0.77,0 1.46,-0.22 2.05,-0.66c0.6,-0.44 1.05,-1.04 1.38,-1.8c0.32,-0.76 0.48,-1.6 0.48,-2.53c0,-0.94 -0.16,-1.79 -0.48,-2.55C14.33,8.69 13.87,8.09 13.28,7.66zM13.29,13.81c-0.19,0.54 -0.47,0.96 -0.82,1.27c-0.36,0.31 -0.78,0.47 -1.25,0.47c-0.48,0 -0.9,-0.16 -1.26,-0.47c-0.35,-0.31 -0.63,-0.74 -0.82,-1.27S8.86,12.67 8.86,12c0,-0.67 0.1,-1.28 0.29,-1.82c0.19,-0.54 0.46,-0.96 0.82,-1.27c0.35,-0.31 0.77,-0.46 1.26,-0.46c0.47,0 0.89,0.15 1.25,0.46s0.63,0.73 0.82,1.27c0.19,0.54 0.29,1.15 0.29,1.82C13.58,12.67 13.48,13.27 13.29,13.81zM21.51,13.43c-0.36,-0.36 -0.89,-0.63 -1.58,-0.8l-1.05,-0.26c-0.34,-0.09 -0.61,-0.21 -0.78,-0.34c-0.18,-0.14 -0.27,-0.31 -0.27,-0.52c0,-0.22 0.12,-0.4 0.35,-0.54c0.23,-0.14 0.52,-0.21 0.87,-0.21c0.54,0 0.95,0.15 1.24,0.46c0.19,0.21 0.51,0.24 0.77,0.13l0,0c0.47,-0.21 0.59,-0.84 0.21,-1.18c-0.14,-0.12 -0.3,-0.23 -0.48,-0.33c-0.5,-0.27 -1.08,-0.4 -1.75,-0.4c-0.49,0 -0.95,0.09 -1.37,0.26c-0.42,0.17 -0.75,0.42 -1,0.73c-0.25,0.32 -0.37,0.68 -0.37,1.1c0,0.54 0.19,0.99 0.56,1.34c0.37,0.35 0.84,0.6 1.41,0.74l0.85,0.21c0.47,0.11 0.81,0.24 1.03,0.39c0.22,0.15 0.34,0.35 0.34,0.61c0,0.27 -0.13,0.47 -0.39,0.61c-0.26,0.14 -0.58,0.2 -0.96,0.2c-0.39,0 -0.74,-0.1 -1.04,-0.29c-0.16,-0.1 -0.3,-0.23 -0.42,-0.38c-0.21,-0.26 -0.57,-0.35 -0.88,-0.21v0c-0.47,0.21 -0.6,0.81 -0.26,1.19c0.17,0.19 0.37,0.37 0.59,0.52c0.52,0.36 1.19,0.54 2.01,0.54c0.54,0 1.03,-0.09 1.48,-0.28c0.45,-0.19 0.8,-0.45 1.05,-0.79c0.26,-0.34 0.38,-0.73 0.38,-1.18C22.05,14.23 21.87,13.79 21.51,13.43z"/>
+ android:pathData="M-0.01,7.72L-0.01,9.4l3,-1L2.99,18h2L4.99,6h-0.25L-0.01,7.72zM23.77,14.37c-0.14,-0.28 -0.35,-0.53 -0.63,-0.74 -0.28,-0.21 -0.61,-0.39 -1.01,-0.53s-0.85,-0.27 -1.35,-0.38c-0.35,-0.07 -0.64,-0.15 -0.87,-0.23 -0.23,-0.08 -0.41,-0.16 -0.55,-0.25s-0.23,-0.19 -0.28,-0.3c-0.05,-0.11 -0.08,-0.24 -0.08,-0.39 0,-0.14 0.03,-0.28 0.09,-0.41s0.15,-0.25 0.27,-0.34c0.12,-0.1 0.27,-0.18 0.45,-0.24s0.4,-0.09 0.64,-0.09c0.25,0 0.47,0.04 0.66,0.11s0.35,0.17 0.48,0.29 0.22,0.26 0.29,0.42c0.06,0.16 0.1,0.32 0.1,0.49h1.95c0,-0.39 -0.08,-0.75 -0.24,-1.09s-0.39,-0.63 -0.69,-0.88c-0.3,-0.25 -0.66,-0.44 -1.09,-0.59 -0.43,-0.15 -0.92,-0.22 -1.46,-0.22 -0.51,0 -0.98,0.07 -1.39,0.21s-0.77,0.33 -1.06,0.57c-0.29,0.24 -0.51,0.52 -0.67,0.84 -0.16,0.32 -0.23,0.65 -0.23,1.01s0.08,0.69 0.23,0.96c0.15,0.28 0.36,0.52 0.64,0.73 0.27,0.21 0.6,0.38 0.98,0.53 0.38,0.14 0.81,0.26 1.27,0.36 0.39,0.08 0.71,0.17 0.95,0.26s0.43,0.19 0.57,0.29c0.13,0.1 0.22,0.22 0.27,0.34 0.05,0.12 0.07,0.25 0.07,0.39 0,0.32 -0.13,0.57 -0.4,0.77s-0.66,0.29 -1.17,0.29c-0.22,0 -0.43,-0.02 -0.64,-0.08 -0.21,-0.05 -0.4,-0.13 -0.56,-0.24 -0.17,-0.11 -0.3,-0.26 -0.41,-0.44 -0.11,-0.18 -0.17,-0.41 -0.18,-0.67h-1.89c0,0.36 0.08,0.71 0.24,1.05s0.39,0.65 0.7,0.93c0.31,0.27 0.69,0.49 1.15,0.66s0.98,0.25 1.58,0.25c0.53,0 1.01,-0.06 1.44,-0.19 0.43,-0.13 0.8,-0.31 1.11,-0.54 0.31,-0.23 0.54,-0.51 0.71,-0.83 0.17,-0.32 0.25,-0.67 0.25,-1.06 -0.02,-0.4 -0.09,-0.74 -0.24,-1.02zM13.81,7.05c-0.34,-0.4 -0.75,-0.7 -1.23,-0.88 -0.47,-0.18 -1.01,-0.27 -1.59,-0.27s-1.11,0.09 -1.59,0.27c-0.48,0.18 -0.89,0.47 -1.23,0.88 -0.34,0.41 -0.6,0.93 -0.79,1.59 -0.18,0.65 -0.28,1.45 -0.28,2.39v1.92c0,0.94 0.09,1.74 0.28,2.39 0.19,0.66 0.45,1.19 0.8,1.6 0.34,0.41 0.75,0.71 1.23,0.89s1.01,0.28 1.59,0.28c0.59,0 1.12,-0.09 1.59,-0.28 0.48,-0.18 0.88,-0.48 1.22,-0.89s0.6,-0.94 0.78,-1.6c0.18,-0.65 0.28,-1.45 0.28,-2.39v-1.92c0,-0.94 -0.09,-1.74 -0.28,-2.39 -0.18,-0.66 -0.44,-1.19 -0.78,-1.59zM12.89,13.22c0,0.6 -0.04,1.11 -0.12,1.53s-0.2,0.76 -0.36,1.02c-0.16,0.26 -0.36,0.45 -0.59,0.57 -0.23,0.12 -0.51,0.18 -0.82,0.18 -0.3,0 -0.58,-0.06 -0.82,-0.18s-0.44,-0.31 -0.6,-0.57c-0.16,-0.26 -0.29,-0.6 -0.38,-1.02s-0.13,-0.93 -0.13,-1.53v-2.5c0,-0.6 0.04,-1.11 0.13,-1.52s0.21,-0.74 0.38,-1c0.16,-0.25 0.36,-0.43 0.6,-0.55 0.24,-0.11 0.51,-0.17 0.81,-0.17 0.31,0 0.58,0.06 0.81,0.17 0.24,0.11 0.44,0.29 0.6,0.55 0.16,0.25 0.29,0.58 0.37,0.99s0.13,0.92 0.13,1.52v2.51h-0.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/timer_3.xml b/compose/material/material/icons/generator/raw-icons/rounded/timer_3.xml
index 33be92a..215e2d0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/timer_3.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/timer_3.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.59,16.38c-0.39,-0.26 -0.7,-0.61 -0.94,-1.02c-0.23,-0.4 -0.04,-0.92 0.38,-1.09l0,0c0.35,-0.15 0.77,-0.01 0.96,0.32c0.12,0.21 0.26,0.38 0.43,0.53c0.32,0.27 0.71,0.4 1.17,0.4c0.47,0 0.87,-0.14 1.2,-0.43c0.31,-0.26 0.49,-0.63 0.5,-1.03c0.01,-0.47 -0.16,-0.85 -0.53,-1.15c-0.35,-0.28 -0.8,-0.43 -1.33,-0.43H8.32c-0.39,0 -0.71,-0.32 -0.71,-0.71v0c0,-0.39 0.32,-0.71 0.71,-0.71h0.03c0.46,0 0.84,-0.12 1.15,-0.37c0.31,-0.25 0.47,-0.58 0.47,-1.01c0,-0.38 -0.14,-0.69 -0.42,-0.91C9.27,8.55 8.92,8.44 8.49,8.44c-0.42,0 -0.75,0.11 -1,0.34c-0.11,0.1 -0.2,0.2 -0.28,0.31c-0.2,0.28 -0.57,0.38 -0.89,0.25l0,0c-0.47,-0.19 -0.62,-0.78 -0.3,-1.17c0.16,-0.2 0.34,-0.38 0.56,-0.55C7.08,7.2 7.72,7 8.51,7c0.58,0 1.1,0.11 1.56,0.34c0.46,0.22 0.82,0.53 1.08,0.93c0.26,0.4 0.39,0.84 0.39,1.33c0,0.5 -0.12,0.93 -0.36,1.28c-0.24,0.35 -0.54,0.62 -0.89,0.8v0.08c0.47,0.2 0.85,0.49 1.15,0.89c0.3,0.4 0.45,0.88 0.45,1.44c0,0.56 -0.14,1.06 -0.43,1.49c-0.28,0.44 -0.68,0.78 -1.17,1.03C9.77,16.87 9.21,17 8.59,17C7.87,17 7.21,16.79 6.59,16.38z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.98,16.46c-0.23,-0.16 -0.42,-0.33 -0.59,-0.52c-0.34,-0.39 -0.21,-0.99 0.26,-1.19l0,0c0.31,-0.13 0.67,-0.05 0.88,0.21c0.12,0.15 0.26,0.28 0.42,0.38c0.3,0.2 0.65,0.29 1.04,0.29c0.38,0 0.7,-0.07 0.96,-0.2c0.26,-0.13 0.39,-0.34 0.39,-0.61c0,-0.26 -0.11,-0.47 -0.34,-0.61c-0.22,-0.15 -0.57,-0.28 -1.03,-0.39l-0.85,-0.21c-0.57,-0.14 -1.04,-0.39 -1.41,-0.74c-0.37,-0.35 -0.56,-0.8 -0.56,-1.34c0,-0.42 0.12,-0.79 0.37,-1.1c0.25,-0.32 0.58,-0.56 1,-0.73c0.42,-0.17 0.87,-0.26 1.37,-0.26c0.66,0 1.24,0.13 1.75,0.4c0.18,0.09 0.34,0.2 0.48,0.33c0.39,0.34 0.27,0.97 -0.21,1.18l0,0c-0.26,0.11 -0.58,0.08 -0.77,-0.13c-0.29,-0.31 -0.7,-0.46 -1.24,-0.46c-0.34,0 -0.63,0.07 -0.87,0.21c-0.23,0.14 -0.35,0.32 -0.35,0.54c0,0.21 0.09,0.39 0.27,0.52c0.18,0.14 0.44,0.25 0.78,0.34l1.05,0.26c0.7,0.18 1.23,0.45 1.58,0.8c0.36,0.36 0.54,0.8 0.54,1.32c0,0.45 -0.13,0.84 -0.38,1.18c-0.26,0.34 -0.61,0.6 -1.05,0.79S16.53,17 15.99,17C15.17,17 14.5,16.82 13.98,16.46z"/>
+ android:pathData="M11.61,12.97c-0.16,-0.24 -0.36,-0.46 -0.62,-0.65 -0.25,-0.19 -0.56,-0.35 -0.93,-0.48 0.3,-0.14 0.57,-0.3 0.8,-0.5 0.23,-0.2 0.42,-0.41 0.57,-0.64 0.15,-0.23 0.27,-0.46 0.34,-0.71 0.08,-0.24 0.11,-0.49 0.11,-0.73 0,-0.55 -0.09,-1.04 -0.28,-1.46 -0.18,-0.42 -0.44,-0.77 -0.78,-1.06 -0.33,-0.28 -0.73,-0.5 -1.2,-0.64 -0.45,-0.13 -0.97,-0.2 -1.53,-0.2 -0.55,0 -1.06,0.08 -1.52,0.24 -0.47,0.17 -0.87,0.4 -1.2,0.69 -0.33,0.29 -0.6,0.63 -0.78,1.03 -0.2,0.39 -0.29,0.83 -0.29,1.29h1.98c0,-0.26 0.05,-0.49 0.14,-0.69 0.09,-0.2 0.22,-0.38 0.38,-0.52 0.17,-0.14 0.36,-0.25 0.58,-0.33s0.46,-0.12 0.73,-0.12c0.61,0 1.06,0.16 1.36,0.47 0.3,0.31 0.44,0.75 0.44,1.32 0,0.27 -0.04,0.52 -0.12,0.74 -0.08,0.22 -0.21,0.41 -0.38,0.57s-0.38,0.28 -0.63,0.37 -0.55,0.13 -0.89,0.13L6.72,11.09v1.57L7.9,12.66c0.34,0 0.64,0.04 0.91,0.11 0.27,0.08 0.5,0.19 0.69,0.35 0.19,0.16 0.34,0.36 0.44,0.61 0.1,0.24 0.16,0.54 0.16,0.87 0,0.62 -0.18,1.09 -0.53,1.42 -0.35,0.33 -0.84,0.49 -1.45,0.49 -0.29,0 -0.56,-0.04 -0.8,-0.13 -0.24,-0.08 -0.44,-0.2 -0.61,-0.36s-0.3,-0.34 -0.39,-0.56c-0.09,-0.22 -0.14,-0.46 -0.14,-0.72L4.19,14.74c0,0.55 0.11,1.03 0.32,1.45 0.21,0.42 0.5,0.77 0.86,1.05s0.77,0.49 1.24,0.63 0.96,0.21 1.48,0.21c0.57,0 1.09,-0.08 1.58,-0.23s0.91,-0.38 1.26,-0.68c0.36,-0.3 0.64,-0.66 0.84,-1.1 0.2,-0.43 0.3,-0.93 0.3,-1.48 0,-0.29 -0.04,-0.58 -0.11,-0.86 -0.08,-0.25 -0.19,-0.51 -0.35,-0.76zM20.87,14.37c-0.14,-0.28 -0.35,-0.53 -0.63,-0.74 -0.28,-0.21 -0.61,-0.39 -1.01,-0.53s-0.85,-0.27 -1.35,-0.38c-0.35,-0.07 -0.64,-0.15 -0.87,-0.23 -0.23,-0.08 -0.41,-0.16 -0.55,-0.25s-0.23,-0.19 -0.28,-0.3c-0.05,-0.11 -0.08,-0.24 -0.08,-0.39s0.03,-0.28 0.09,-0.41 0.15,-0.25 0.27,-0.34c0.12,-0.1 0.27,-0.18 0.45,-0.24s0.4,-0.09 0.64,-0.09c0.25,0 0.47,0.04 0.66,0.11s0.35,0.17 0.48,0.29 0.22,0.26 0.29,0.42c0.06,0.16 0.1,0.32 0.1,0.49h1.95c0,-0.39 -0.08,-0.75 -0.24,-1.09s-0.39,-0.63 -0.69,-0.88c-0.3,-0.25 -0.66,-0.44 -1.09,-0.59 -0.43,-0.15 -0.92,-0.22 -1.46,-0.22 -0.51,0 -0.98,0.07 -1.39,0.21s-0.77,0.33 -1.06,0.57c-0.29,0.24 -0.51,0.52 -0.67,0.84s-0.23,0.65 -0.23,1.01 0.08,0.68 0.23,0.96 0.37,0.52 0.64,0.73c0.27,0.21 0.6,0.38 0.98,0.53 0.38,0.14 0.81,0.26 1.27,0.36 0.39,0.08 0.71,0.17 0.95,0.26s0.43,0.19 0.57,0.29c0.13,0.1 0.22,0.22 0.27,0.34 0.05,0.12 0.07,0.25 0.07,0.39 0,0.32 -0.13,0.57 -0.4,0.77s-0.66,0.29 -1.17,0.29c-0.22,0 -0.43,-0.02 -0.64,-0.08 -0.21,-0.05 -0.4,-0.13 -0.56,-0.24 -0.17,-0.11 -0.3,-0.26 -0.41,-0.44 -0.11,-0.18 -0.17,-0.41 -0.18,-0.67h-1.89c0,0.36 0.08,0.71 0.24,1.05s0.39,0.65 0.7,0.93c0.31,0.27 0.69,0.49 1.15,0.66 0.46,0.17 0.98,0.25 1.58,0.25 0.53,0 1.01,-0.06 1.44,-0.19 0.43,-0.13 0.8,-0.31 1.11,-0.54 0.31,-0.23 0.54,-0.51 0.71,-0.83 0.17,-0.32 0.25,-0.67 0.25,-1.06 -0.02,-0.4 -0.09,-0.74 -0.24,-1.02z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/timer_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/timer_off.xml
index ac4862c..64ef1a7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/timer_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/timer_off.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.85,5.02l1.51,1.51c1.56,-0.64 3.36,-0.79 5.29,0.01c1.71,0.71 3.1,2.1 3.8,3.81c0.79,1.93 0.64,3.73 0,5.28l1.51,1.51C20.62,15.91 21,14.5 21,13c0,-2.12 -0.74,-4.07 -1.97,-5.61l0.72,-0.72c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.72,0.72C16.07,4.74 14.12,4 12,4C10.5,4 9.09,4.38 7.85,5.02z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14,1h-4C9.45,1 9,1.45 9,2v0c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v0C15,1.45 14.55,1 14,1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41l2.69,2.69c-1.4,1.87 -2.1,4.29 -1.67,6.89c0.61,3.74 3.63,6.75 7.37,7.37c2.6,0.43 5.02,-0.27 6.88,-1.67l1.69,1.69c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51zM12,20c-3.86,0 -7,-3.14 -7,-7c0,-1.46 0.45,-2.82 1.22,-3.95l9.72,9.72C14.82,19.55 13.46,20 12,20z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13,9c0,-0.55 -0.45,-1 -1,-1c-0.32,0 -0.59,0.16 -0.78,0.4l1.6,1.6L13,10.17V9z"/>
+ android:pathData="M10,3h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM12,8c-0.51,0 -0.92,0.39 -0.98,0.89L13,10.86L13,9c0,-0.55 -0.45,-1 -1,-1zM12,6c3.87,0 7,3.13 7,7 0,1.12 -0.27,2.18 -0.74,3.12l1.47,1.47C20.53,16.25 21,14.68 21,13c0,-2.12 -0.74,-4.07 -1.97,-5.61l0.75,-0.75c0.38,-0.38 0.39,-1.01 0,-1.4l-0.01,-0.01c-0.39,-0.39 -1.01,-0.38 -1.4,0l-0.75,0.75C16.07,4.74 14.12,4 12,4c-1.66,0 -3.22,0.48 -4.57,1.29l1.45,1.45c0.94,-0.47 2,-0.74 3.12,-0.74zM20.19,20.88L3.87,4.56c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.07,2.07C3.61,9.42 3.05,11.03 3,12.76 2.87,17.84 6.94,22 12,22c1.84,0 3.55,-0.55 4.98,-1.5l1.79,1.79c0.39,0.39 1.02,0.39 1.41,0 0.4,-0.39 0.4,-1.02 0.01,-1.41zM12,20c-3.87,0 -7,-3.13 -7,-7 0,-1.29 0.35,-2.49 0.96,-3.52l9.57,9.57c-1.04,0.6 -2.24,0.95 -3.53,0.95z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tips_and_updates.xml b/compose/material/material/icons/generator/raw-icons/rounded/tips_and_updates.xml
new file mode 100644
index 0000000..b5af81f5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tips_and_updates.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,18c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6C5.45,17 5,17.45 5,18zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/title.xml b/compose/material/material/icons/generator/raw-icons/rounded/title.xml
index e2538e3..1daddf2 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/title.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/title.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.5,4h-11C5.67,4 5,4.67 5,5.5v0C5,6.33 5.67,7 6.5,7h4v11.5c0,0.83 0.67,1.5 1.5,1.5h0c0.83,0 1.5,-0.67 1.5,-1.5V7h4C18.33,7 19,6.33 19,5.5v0C19,4.67 18.33,4 17.5,4z"/>
+ android:pathData="M5,5.5C5,6.33 5.67,7 6.5,7h4v10.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5V7h4c0.83,0 1.5,-0.67 1.5,-1.5S18.33,4 17.5,4h-11C5.67,4 5,4.67 5,5.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/toc.xml b/compose/material/material/icons/generator/raw-icons/rounded/toc.xml
index d98f96d..a965a7b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/toc.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/toc.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,9h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4C3.45,7 3,7.45 3,8S3.45,9 4,9zM4,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,13 4,13zM4,17h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1C3,16.55 3.45,17 4,17zM20,17L20,17c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v0C19,16.55 19.45,17 20,17zM19,8L19,8c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h0C19.45,7 19,7.45 19,8zM20,13L20,13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v0C19,12.55 19.45,13 20,13z"/>
+ android:pathData="M4,9h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,7c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,13h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,17h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,15c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM19,17h2v-2h-2v2zM19,7v2h2L21,7h-2zM19,13h2v-2h-2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/today.xml b/compose/material/material/icons/generator/raw-icons/rounded/today.xml
index 5c72f7b..5d633eb 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/today.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/today.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,4h-1V3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1H8V3c0,-0.55 -0.45,-1 -1,-1S6,2.45 6,3v1H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V10h14V20zM8,12h3c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1v-3C7,12.45 7.45,12 8,12z"/>
+ android:pathData="M19,3h-1L18,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L8,3L8,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L5,3c-1.11,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM18,19L6,19c-0.55,0 -1,-0.45 -1,-1L5,8h14v10c0,0.55 -0.45,1 -1,1zM8,10h3c0.55,0 1,0.45 1,1v3c0,0.55 -0.45,1 -1,1L8,15c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/toggle_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/toggle_off.xml
index 61d66d8..1af8c24 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/toggle_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/toggle_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,6H7c-3.31,0 -6,2.69 -6,6s2.69,6 6,6h10c3.31,0 6,-2.69 6,-6S20.31,6 17,6zM7,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S8.66,15 7,15z"/>
+ android:pathData="M17,7H7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h10c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5zM7,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/toggle_on.xml b/compose/material/material/icons/generator/raw-icons/rounded/toggle_on.xml
index 5aa626b..914671e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/toggle_on.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/toggle_on.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,6H7c-3.31,0 -6,2.69 -6,6s2.69,6 6,6h10c3.31,0 6,-2.69 6,-6S20.31,6 17,6zM17,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S18.66,15 17,15z"/>
+ android:pathData="M17,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h10c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5zM17,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/token.xml b/compose/material/material/icons/generator/raw-icons/rounded/token.xml
new file mode 100644
index 0000000..6b6c385
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/token.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.97,2.54c-0.6,-0.34 -1.34,-0.34 -1.94,0l-7,3.89L9.1,9.24C9.83,8.48 10.86,8 12,8s2.17,0.48 2.9,1.24l5.07,-2.82L12.97,2.54zM10,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2s-0.9,2 -2,2S10,13.1 10,12zM3,8.14l5.13,2.85C8.04,11.31 8,11.65 8,12c0,1.86 1.27,3.43 3,3.87v5.57l-6.97,-3.87C3.39,17.22 3,16.55 3,15.82V8.14zM13,21.44v-5.57c1.73,-0.44 3,-2.01 3,-3.87c0,-0.35 -0.04,-0.69 -0.13,-1.01L21,8.14l0,7.68c0,0.73 -0.39,1.4 -1.03,1.75L13,21.44z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/toll.xml b/compose/material/material/icons/generator/raw-icons/rounded/toll.xml
index 0f7bbd2..3ee7a7a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/toll.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/toll.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8s8,-3.58 8,-8S19.42,4 15,4zM15,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6s6,2.69 6,6S18.31,18 15,18zM3,12c0,-2.39 1.4,-4.46 3.43,-5.42C6.77,6.42 7,6.11 7,5.74V5.55c0,-0.68 -0.71,-1.11 -1.32,-0.82C2.92,5.99 1,8.77 1,12s1.92,6.01 4.68,7.27C6.29,19.55 7,19.13 7,18.45v-0.18c0,-0.37 -0.23,-0.69 -0.57,-0.85C4.4,16.46 3,14.39 3,12z"/>
+ android:pathData="M15,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8 8,-3.58 8,-8 -3.58,-8 -8,-8zM15,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6zM3,12c0,-2.39 1.4,-4.46 3.43,-5.42 0.34,-0.16 0.57,-0.47 0.57,-0.84v-0.19c0,-0.68 -0.71,-1.11 -1.32,-0.82C2.92,5.99 1,8.77 1,12s1.92,6.01 4.68,7.27c0.61,0.28 1.32,-0.14 1.32,-0.82v-0.18c0,-0.37 -0.23,-0.69 -0.57,-0.85C4.4,16.46 3,14.39 3,12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tonality.xml b/compose/material/material/icons/generator/raw-icons/rounded/tonality.xml
index 204e26a..5b331db 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tonality.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tonality.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM11,19.93C7.06,19.44 4,16.08 4,12s3.05,-7.44 7,-7.93V19.93zM13,4.07C14.03,4.2 15,4.52 15.87,5H13V4.07zM13,7h5.24c0.25,0.31 0.48,0.65 0.68,1H13V7zM13,10h6.74c0.08,0.33 0.15,0.66 0.19,1H13V10zM13,19.93V19h2.87C15,19.48 14.03,19.8 13,19.93zM18.24,17H13v-1h5.92C18.72,16.35 18.49,16.69 18.24,17zM19.74,14H13v-1h6.93C19.89,13.34 19.82,13.67 19.74,14z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.94,-0.49 -7,-3.85 -7,-7.93s3.05,-7.44 7,-7.93v15.86zM13,4.07c1.03,0.13 2,0.45 2.87,0.93L13,5v-0.93zM13,7h5.24c0.25,0.31 0.48,0.65 0.68,1L13,8L13,7zM13,10h6.74c0.08,0.33 0.15,0.66 0.19,1L13,11v-1zM13,19.93L13,19h2.87c-0.87,0.48 -1.84,0.8 -2.87,0.93zM18.24,17L13,17v-1h5.92c-0.2,0.35 -0.43,0.69 -0.68,1zM19.74,14L13,14v-1h6.93c-0.04,0.34 -0.11,0.67 -0.19,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/touch_app.xml b/compose/material/material/icons/generator/raw-icons/rounded/touch_app.xml
index d457a9d..7b31bd4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/touch_app.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/touch_app.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9,9.24V5.5C9,4.12 10.12,3 11.5,3S14,4.12 14,5.5v3.74c1.21,-0.81 2,-2.18 2,-3.74C16,3.01 13.99,1 11.5,1S7,3.01 7,5.5C7,7.06 7.79,8.43 9,9.24z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14.5,11.71c-0.28,-0.14 -0.58,-0.21 -0.89,-0.21H13v-6C13,4.67 12.33,4 11.5,4S10,4.67 10,5.5v10.74l-3.44,-0.72c-0.37,-0.08 -0.76,0.04 -1.03,0.31l0,0c-0.43,0.44 -0.43,1.14 0.01,1.58l4.01,4.01C9.92,21.79 10.43,22 10.96,22h6.41c1,0 1.84,-0.73 1.98,-1.72l0.63,-4.46c0.12,-0.85 -0.32,-1.69 -1.09,-2.07L14.5,11.71z"/>
+ android:pathData="M8.79,9.24V5.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5v3.74c1.21,-0.81 2,-2.18 2,-3.74c0,-2.49 -2.01,-4.5 -4.5,-4.5s-4.5,2.01 -4.5,4.5C6.79,7.06 7.58,8.43 8.79,9.24zM14.29,11.71c-0.28,-0.14 -0.58,-0.21 -0.89,-0.21h-0.61v-6c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v10.74l-3.44,-0.72c-0.37,-0.08 -0.76,0.04 -1.03,0.31c-0.43,0.44 -0.43,1.14 0,1.58l4.01,4.01C9.71,21.79 10.22,22 10.75,22h6.1c1,0 1.84,-0.73 1.98,-1.72l0.63,-4.47c0.12,-0.85 -0.32,-1.69 -1.09,-2.07L14.29,11.71z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tour.xml b/compose/material/material/icons/generator/raw-icons/rounded/tour.xml
index ba9601c..a48905f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tour.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tour.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.52,4H7V3c0,-0.55 -0.45,-1 -1,-1h0C5.45,2 5,2.45 5,3v19h2v-8h12.52c0.71,0 1.19,-0.71 0.93,-1.37L19,9l1.45,-3.63C20.71,4.71 20.23,4 19.52,4zM12.5,11c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.6,11 12.5,11z"/>
+ android:pathData="M20.45,5.37C20.71,4.71 20.23,4 19.52,4H13h-1H7V3c0,-0.55 -0.45,-1 -1,-1h0C5.45,2 5,2.45 5,3v1v10v8h2v-8h4h1h7.52c0.71,0 1.19,-0.71 0.93,-1.37L19,9L20.45,5.37zM15,9c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2s0.9,-2 2,-2S15,7.9 15,9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/track_changes.xml b/compose/material/material/icons/generator/raw-icons/rounded/track_changes.xml
index fed4e70..aff2c76 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/track_changes.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/track_changes.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.31,5.67c-0.36,0.36 -0.39,0.92 -0.07,1.32c1.45,1.82 2.21,4.31 1.53,6.92c-0.79,3.05 -3.18,5.33 -6.21,5.94c-5.1,1.01 -9.57,-2.93 -9.57,-7.86c0,-4.08 3.05,-7.44 7,-7.93v2.02c-3.13,0.53 -5.43,3.46 -4.93,6.83c0.39,2.61 2.56,4.71 5.18,5.03c3.64,0.45 6.75,-2.39 6.75,-5.95c0,-1.25 -0.38,-2.4 -1.03,-3.36c-0.34,-0.5 -1.07,-0.53 -1.5,-0.11l-0.01,0.01c-0.34,0.34 -0.37,0.87 -0.11,1.27c0.6,0.92 0.84,2.1 0.49,3.32c-0.39,1.37 -1.54,2.46 -2.94,2.77c-2.6,0.57 -4.9,-1.39 -4.9,-3.9c0,-1.86 1.28,-3.41 3,-3.86v2.14c-0.6,0.35 -1,0.98 -1,1.72c0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-0.74 -0.4,-1.38 -1,-1.72V2.7c0,-0.39 -0.32,-0.71 -0.71,-0.71c-5.36,-0.2 -9.98,4.06 -10.27,9.4c-0.36,6.55 5.41,11.82 12.01,10.4c3.88,-0.83 6.88,-3.8 7.75,-7.67c0.71,-3.16 -0.2,-6.16 -1.97,-8.37C19.43,5.28 18.73,5.25 18.31,5.67z"/>
+ android:pathData="M18.32,5.68c-0.36,0.36 -0.39,0.92 -0.07,1.32 1.45,1.82 2.21,4.31 1.53,6.92 -0.79,3.05 -3.18,5.33 -6.21,5.94C8.47,20.87 4,16.93 4,12c0,-4.08 3.05,-7.44 7,-7.93v2.02c-3.13,0.53 -5.43,3.46 -4.93,6.83 0.39,2.61 2.56,4.71 5.18,5.03C14.89,18.4 18,15.56 18,12c0,-1.25 -0.38,-2.4 -1.03,-3.36 -0.34,-0.5 -1.07,-0.53 -1.5,-0.11l-0.01,0.01c-0.34,0.34 -0.37,0.87 -0.11,1.27 0.6,0.92 0.84,2.1 0.49,3.32 -0.39,1.37 -1.54,2.46 -2.94,2.77 -2.6,0.57 -4.9,-1.39 -4.9,-3.9 0,-1.86 1.28,-3.41 3,-3.86v2.14c-0.6,0.35 -1,0.98 -1,1.72 0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-0.74 -0.4,-1.38 -1,-1.72V2.71c0,-0.39 -0.32,-0.71 -0.71,-0.71 -5.36,-0.2 -9.98,4.06 -10.27,9.4 -0.36,6.55 5.41,11.82 12.01,10.4 3.88,-0.83 6.88,-3.8 7.75,-7.67 0.71,-3.16 -0.2,-6.16 -1.97,-8.37 -0.37,-0.47 -1.07,-0.5 -1.49,-0.08z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/traffic.xml b/compose/material/material/icons/generator/raw-icons/rounded/traffic.xml
index cce682e..a8fedd3 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/traffic.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/traffic.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19.96,10.59C20,10.28 19.77,10 19.46,10H17V8.86c1.54,-0.4 2.72,-1.68 2.96,-3.27C20,5.28 19.77,5 19.46,5H17v0c0,-1.1 -0.9,-2 -2,-2H9C7.9,3 7,3.9 7,5v0H4.54C4.23,5 4,5.28 4.04,5.59C4.28,7.18 5.46,8.46 7,8.86V10H4.54c-0.31,0 -0.54,0.28 -0.5,0.59c0.24,1.59 1.42,2.87 2.96,3.27V15H4.54c-0.31,0 -0.54,0.28 -0.5,0.59c0.24,1.59 1.42,2.87 2.96,3.27V19c0,1.1 0.9,2 2,2h6c1.1,0 2,-0.9 2,-2v-0.14c1.54,-0.4 2.72,-1.68 2.96,-3.27C20,15.28 19.77,15 19.46,15H17v-1.14C18.54,13.46 19.72,12.18 19.96,10.59zM12,15c0.83,0 1.5,0.67 1.5,1.5S12.83,18 12,18s-1.5,-0.67 -1.5,-1.5S11.17,15 12,15zM10.5,12c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5s-0.67,1.5 -1.5,1.5S10.5,12.83 10.5,12zM12,9c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,6 12,6s1.5,0.67 1.5,1.5S12.83,9 12,9z"/>
+ android:pathData="M19.96,10.59c0.04,-0.31 -0.19,-0.59 -0.5,-0.59L17,10L17,8.86c1.54,-0.4 2.72,-1.68 2.96,-3.27 0.04,-0.31 -0.19,-0.59 -0.5,-0.59L17,5L17,4c0,-0.55 -0.45,-1 -1,-1L8,3c-0.55,0 -1,0.45 -1,1v1L4.54,5c-0.31,0 -0.54,0.28 -0.5,0.59C4.28,7.18 5.46,8.46 7,8.86L7,10L4.54,10c-0.31,0 -0.54,0.28 -0.5,0.59 0.24,1.59 1.42,2.87 2.96,3.27L7,15L4.54,15c-0.31,0 -0.54,0.28 -0.5,0.59 0.24,1.59 1.42,2.87 2.96,3.27L7,20c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-1.14c1.54,-0.4 2.72,-1.68 2.96,-3.27 0.04,-0.31 -0.19,-0.59 -0.5,-0.59L17,15v-1.14c1.54,-0.4 2.72,-1.68 2.96,-3.27zM12,19c-1.11,0 -2,-0.9 -2,-2s0.89,-2 2,-2c1.1,0 2,0.9 2,2s-0.89,2 -2,2zM12,14c-1.11,0 -2,-0.9 -2,-2s0.89,-2 2,-2c1.1,0 2,0.9 2,2s-0.89,2 -2,2zM12,9c-1.11,0 -2,-0.9 -2,-2 0,-1.11 0.89,-2 2,-2 1.1,0 2,0.89 2,2 0,1.1 -0.89,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/train.xml b/compose/material/material/icons/generator/raw-icons/rounded/train.xml
index e3c0e9b..b6fb42a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/train.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/train.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C8,2 4,2.5 4,6v9.5C4,17.43 5.57,19 7.5,19l-0.49,0.49C6.45,20.05 6.85,21 7.63,21h0c0.23,0 0.46,-0.09 0.62,-0.26L10,19h4l1.74,1.74c0.17,0.17 0.39,0.26 0.62,0.26h0.01c0.79,0 1.18,-0.95 0.62,-1.51L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5V6C20,2.5 16.42,2 12,2zM8.5,16C7.67,16 7,15.33 7,14.5S7.67,13 8.5,13s1.5,0.67 1.5,1.5S9.33,16 8.5,16zM11,10H6V7h5V10zM15.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S16.33,16 15.5,16zM18,10h-5V7h5V10z"/>
+ android:pathData="M12,2c-4,0 -8,0.5 -8,4v9.5C4,17.43 5.57,19 7.5,19l-1.15,1.15c-0.31,0.31 -0.09,0.85 0.36,0.85L7.8,21c0.13,0 0.26,-0.05 0.35,-0.15L10,19h4l1.85,1.85c0.09,0.09 0.22,0.15 0.35,0.15h1.09c0.45,0 0.67,-0.54 0.35,-0.85L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5L20,6c0,-3.5 -4,-4 -8,-4zM7.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,14 7.5,14s1.5,0.67 1.5,1.5S8.33,17 7.5,17zM11,10L6,10L6,6h5v4zM16.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM18,10h-5L13,6h5v4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tram.xml b/compose/material/material/icons/generator/raw-icons/rounded/tram.xml
index 725ea7d..97f5e25 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tram.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tram.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,4.01l0.75,-1.51h2.5C16.66,2.5 17,2.16 17,1.75v0C17,1.34 16.66,1 16.25,1h-8.5C7.34,1 7,1.34 7,1.75v0C7,2.16 7.34,2.5 7.75,2.5h4L11,4l0.03,0.01C7.38,4.1 4,4.78 4,8v9.5C4,19.43 5.57,21 7.5,21l-0.49,0.49C6.45,22.05 6.85,23 7.63,23h0c0.23,0 0.46,-0.09 0.62,-0.26L10,21h4l1.74,1.74c0.17,0.17 0.39,0.26 0.62,0.26h0c0.79,0 1.18,-0.95 0.63,-1.51L16.5,21c1.93,0 3.5,-1.57 3.5,-3.5V8C20,4.77 16.95,4.1 13,4.01zM12,18c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,15 12,15s1.5,0.67 1.5,1.5S12.83,18 12,18zM18,12H6V9h12V12z"/>
+ android:pathData="M13,5l0.75,-1.5L17,3.5L17,2L7,2v1.5h4.75L11,5c-3.13,0.09 -6,0.73 -6,3.5L5,17c0,1.5 1.11,2.73 2.55,2.95l-1.19,1.19c-0.32,0.32 -0.1,0.86 0.35,0.86L7.8,22c0.13,0 0.26,-0.05 0.35,-0.15L10,20h4l1.85,1.85c0.09,0.09 0.22,0.15 0.35,0.15h1.09c0.45,0 0.67,-0.54 0.35,-0.85l-1.19,-1.19C17.89,19.73 19,18.5 19,17L19,8.5c0,-2.77 -2.87,-3.41 -6,-3.5zM12,18.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM17,14L7,14L7,9h10v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/transfer_within_a_station.xml b/compose/material/material/icons/generator/raw-icons/rounded/transfer_within_a_station.xml
index edb631a..f4b7191 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/transfer_within_a_station.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/transfer_within_a_station.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,16.25c0,-0.41 -0.34,-0.75 -0.75,-0.75h-4.77v-0.77c0,-0.36 -0.44,-0.54 -0.69,-0.29l-1.51,1.52c-0.16,0.16 -0.16,0.41 0,0.57l1.51,1.52c0.26,0.26 0.69,0.08 0.69,-0.29V17h4.77C21.66,17 22,16.66 22,16.25L22,16.25z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21.72,20.21l-1.51,-1.52c-0.26,-0.26 -0.69,-0.08 -0.69,0.29v0.77h-4.77c-0.41,0 -0.75,0.34 -0.75,0.75l0,0c0,0.41 0.34,0.75 0.75,0.75h4.77v0.77c0,0.36 0.44,0.54 0.69,0.29l1.51,-1.52C21.88,20.63 21.88,20.37 21.72,20.21z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S8.4,5.5 9.5,5.5zM5.75,8.9L3.23,21.81C3.11,22.43 3.58,23 4.21,23H4.3c0.47,0 0.88,-0.33 0.98,-0.79L6.85,15L9,17v5c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-5.72c0,-0.53 -0.21,-1.04 -0.59,-1.41L8.95,13.4l0.6,-3c1.07,1.32 2.58,2.23 4.31,2.51c0.6,0.1 1.14,-0.39 1.14,-1l0,0c0,-0.49 -0.36,-0.9 -0.84,-0.98c-1.49,-0.25 -2.75,-1.15 -3.51,-2.38L9.7,6.95C9.35,6.35 8.7,6 8,6C7.75,6 7.5,6.05 7.25,6.15L3.24,7.79C2.49,8.1 2,8.83 2,9.64V12c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1V9.65L5.75,8.9"/>
+ android:pathData="M22,15.5h-5.52v-0.77c0,-0.36 -0.44,-0.54 -0.69,-0.29l-1.51,1.52c-0.16,0.16 -0.16,0.41 0,0.57l1.51,1.52c0.26,0.26 0.69,0.08 0.69,-0.29L16.48,17L22,17v-1.5zM21.72,20.21l-1.51,-1.52c-0.26,-0.26 -0.69,-0.08 -0.69,0.29v0.77L14,19.75v1.5h5.52v0.77c0,0.36 0.44,0.54 0.69,0.29l1.51,-1.52c0.16,-0.16 0.16,-0.42 0,-0.58zM9.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM5.75,8.9L3.23,21.81c-0.12,0.62 0.35,1.19 0.98,1.19h0.09c0.47,0 0.88,-0.33 0.98,-0.79L6.85,15 9,17v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-5.72c0,-0.53 -0.21,-1.04 -0.59,-1.41L8.95,13.4l0.6,-3c1.07,1.32 2.58,2.23 4.31,2.51 0.6,0.1 1.14,-0.39 1.14,-1 0,-0.49 -0.36,-0.9 -0.84,-0.98 -1.49,-0.25 -2.75,-1.15 -3.51,-2.38l-0.95,-1.6C9.35,6.35 8.7,6 8,6c-0.25,0 -0.5,0.05 -0.75,0.15L3.24,7.79C2.49,8.1 2,8.83 2,9.64L2,12c0,0.55 0.45,1 1,1s1,-0.45 1,-1L4,9.65l1.75,-0.75"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/transform.xml b/compose/material/material/icons/generator/raw-icons/rounded/transform.xml
index f308146..1cbf298 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/transform.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/transform.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,9h4v4h2V9c0,-1.1 -0.9,-2 -2,-2h-4V9z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22,16L22,16c0,-0.55 -0.45,-1 -1,-1H9V5h1.79c0.45,0 0.67,-0.54 0.35,-0.85L8.35,1.35c-0.2,-0.2 -0.51,-0.2 -0.71,0L4.85,4.15C4.54,4.46 4.76,5 5.21,5h1.77H7v2H3C2.45,7 2,7.45 2,8v0c0,0.55 0.45,1 1,1h4v6c0,1.1 0.9,2 2,2h6v2h-1.79c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85h-1.77H17v-2h4C21.55,17 22,16.55 22,16z"/>
+ android:pathData="M21,16L9,16c-0.55,0 -1,-0.45 -1,-1L8,4h0.79c0.45,0 0.67,-0.54 0.35,-0.85l-1.79,-1.8c-0.2,-0.2 -0.51,-0.2 -0.71,0l-1.79,1.8c-0.31,0.31 -0.09,0.85 0.36,0.85L6,4v2L3,6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v8c0,1.1 0.9,2 2,2h8v2h-0.79c-0.45,0 -0.67,0.54 -0.35,0.85l1.79,1.79c0.2,0.2 0.51,0.2 0.71,0l1.79,-1.79c0.32,-0.31 0.09,-0.85 -0.35,-0.85L18,20v-2h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM16,14h2L18,8c0,-1.1 -0.9,-2 -2,-2h-6v2h5c0.55,0 1,0.45 1,1v5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/transit_enterexit.xml b/compose/material/material/icons/generator/raw-icons/rounded/transit_enterexit.xml
index 21483fc..d3fec36 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/transit_enterexit.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/transit_enterexit.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.5,18H8c-1.1,0 -2,-0.9 -2,-2V9.5C6,8.67 6.67,8 7.5,8l0,0C8.33,8 9,8.67 9,9.5v3.27L14.95,7c0.57,-0.55 1.48,-0.54 2.04,0.02l0,0c0.56,0.56 0.56,1.47 0.01,2.04L11.15,15h3.35c0.83,0 1.5,0.67 1.5,1.5l0,0C16,17.33 15.33,18 14.5,18z"/>
+ android:pathData="M14.5,18H8c-1.1,0 -2,-0.9 -2,-2V9.5C6,8.67 6.67,8 7.5,8S9,8.67 9,9.5v3.27L14.95,7c0.57,-0.55 1.48,-0.54 2.04,0.02s0.56,1.47 0.01,2.04L11.15,15h3.35c0.83,0 1.5,0.67 1.5,1.5s-0.67,1.5 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/translate.xml b/compose/material/material/icons/generator/raw-icons/rounded/translate.xml
index 00df285..c8a3b46 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/translate.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/translate.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.65,15.67c0.14,-0.36 0.05,-0.77 -0.23,-1.05l-2.09,-2.06l0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53h1.93C16.55,6 17,5.55 17,5.01V4.99C17,4.45 16.55,4 16.01,4H10V3c0,-0.55 -0.45,-1 -1,-1h0C8.45,2 8,2.45 8,3v1H1.99C1.45,4 1,4.45 1,4.99v0c0,0.55 0.45,0.99 0.99,0.99h10.17C11.5,7.92 10.44,9.75 9,11.35c-0.81,-0.89 -1.49,-1.86 -2.06,-2.88C6.78,8.18 6.49,8 6.16,8h0C5.47,8 5.03,8.75 5.37,9.35c0.63,1.13 1.4,2.21 2.3,3.21L3.3,16.87c-0.4,0.39 -0.4,1.03 0,1.42l0,0c0.39,0.39 1.02,0.39 1.42,0L9,14l2.02,2.02C11.53,16.53 12.4,16.34 12.65,15.67L12.65,15.67z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.42,10L17.42,10c-0.65,0 -1.22,0.4 -1.45,1l-3.64,9.69c-0.24,0.63 0.23,1.3 0.9,1.3h0c0.41,0 0.77,-0.26 0.91,-0.64l0.86,-2.43h4.84l0.85,2.42c0.14,0.39 0.5,0.65 0.91,0.65h0c0.67,0 1.14,-0.67 0.9,-1.3L18.87,11C18.64,10.4 18.06,10 17.42,10zM15.63,17.19l1.74,-4.96h0.1l1.74,4.96H15.63z"/>
+ android:pathData="M12.65,15.67c0.14,-0.36 0.05,-0.77 -0.23,-1.05l-2.09,-2.06 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53h1.94c0.54,0 0.99,-0.45 0.99,-0.99v-0.02c0,-0.54 -0.45,-0.99 -0.99,-0.99L10,4L10,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L1.99,4c-0.54,0 -0.99,0.45 -0.99,0.99 0,0.55 0.45,0.99 0.99,0.99h10.18C11.5,7.92 10.44,9.75 9,11.35c-0.81,-0.89 -1.49,-1.86 -2.06,-2.88 -0.16,-0.29 -0.45,-0.47 -0.78,-0.47 -0.69,0 -1.13,0.75 -0.79,1.35 0.63,1.13 1.4,2.21 2.3,3.21L3.3,16.87c-0.4,0.39 -0.4,1.03 0,1.42 0.39,0.39 1.02,0.39 1.42,0L9,14l2.02,2.02c0.51,0.51 1.38,0.32 1.63,-0.35zM17.5,10c-0.6,0 -1.14,0.37 -1.35,0.94l-3.67,9.8c-0.24,0.61 0.22,1.26 0.87,1.26 0.39,0 0.74,-0.24 0.88,-0.61l0.89,-2.39h4.75l0.9,2.39c0.14,0.36 0.49,0.61 0.88,0.61 0.65,0 1.11,-0.65 0.88,-1.26l-3.67,-9.8c-0.22,-0.57 -0.76,-0.94 -1.36,-0.94zM15.88,17l1.62,-4.33L19.12,17h-3.24z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/trending_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/trending_down.xml
index 64100d1..e3ebf2e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/trending_down.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/trending_down.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.85,17.15l1.44,-1.44l-4.88,-4.88l-3.29,3.29c-0.39,0.39 -1.02,0.39 -1.41,0l-6,-6.01c-0.39,-0.39 -0.39,-1.02 0,-1.41s1.02,-0.39 1.41,0L9.41,12l3.29,-3.29c0.39,-0.39 1.02,-0.39 1.41,0l5.59,5.58l1.44,-1.44c0.31,-0.31 0.85,-0.09 0.85,0.35v4.29c0,0.28 -0.22,0.5 -0.5,0.5H17.2C16.76,18 16.54,17.46 16.85,17.15z"/>
+ android:pathData="M16.85,17.15l1.44,-1.44 -4.88,-4.88 -3.29,3.29c-0.39,0.39 -1.02,0.39 -1.41,0l-6,-6.01c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L9.41,12l3.29,-3.29c0.39,-0.39 1.02,-0.39 1.41,0l5.59,5.58 1.44,-1.44c0.31,-0.31 0.85,-0.09 0.85,0.35v4.29c0,0.28 -0.22,0.5 -0.5,0.5H17.2c-0.44,0.01 -0.66,-0.53 -0.35,-0.84z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/trending_flat.xml b/compose/material/material/icons/generator/raw-icons/rounded/trending_flat.xml
index 429162e..f8da8a9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/trending_flat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/trending_flat.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.65,11.65l-2.79,-2.79C18.54,8.54 18,8.76 18,9.21V11H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79C21.84,12.16 21.84,11.84 21.65,11.65z"/>
+ android:pathData="M21.65,11.65l-2.79,-2.79c-0.32,-0.32 -0.86,-0.1 -0.86,0.35V11H4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.19 0.2,-0.51 0.01,-0.7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/trending_up.xml b/compose/material/material/icons/generator/raw-icons/rounded/trending_up.xml
index 46dc34d..0a5ce01 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/trending_up.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/trending_up.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.85,6.85l1.44,1.44l-4.88,4.88l-3.29,-3.29c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6,6.01c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0L9.41,12l3.29,3.29c0.39,0.39 1.02,0.39 1.41,0l5.59,-5.58l1.44,1.44c0.31,0.31 0.85,0.09 0.85,-0.35V6.5C22,6.22 21.78,6 21.5,6h-4.29C16.76,6 16.54,6.54 16.85,6.85z"/>
+ android:pathData="M16.85,6.85l1.44,1.44 -4.88,4.88 -3.29,-3.29c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6,6.01c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L9.41,12l3.29,3.29c0.39,0.39 1.02,0.39 1.41,0l5.59,-5.58 1.44,1.44c0.31,0.31 0.85,0.09 0.85,-0.35V6.5c0.01,-0.28 -0.21,-0.5 -0.49,-0.5h-4.29c-0.45,0 -0.67,0.54 -0.36,0.85z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/trip_origin.xml b/compose/material/material/icons/generator/raw-icons/rounded/trip_origin.xml
index 2599ccc..ed73ba9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/trip_origin.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/trip_origin.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,12C2,6.48 6.48,2 12,2s10,4.48 10,10s-4.48,10 -10,10S2,17.52 2,12zM12,18c3.31,0 6,-2.69 6,-6s-2.69,-6 -6,-6s-6,2.69 -6,6S8.69,18 12,18z"/>
+ android:pathData="M2,12C2,6.48 6.48,2 12,2s10,4.48 10,10 -4.48,10 -10,10S2,17.52 2,12zM12,18c3.31,0 6,-2.69 6,-6s-2.69,-6 -6,-6 -6,2.69 -6,6 2.69,6 6,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tune.xml b/compose/material/material/icons/generator/raw-icons/rounded/tune.xml
index 202855f..eec23d1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tune.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tune.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,18L3,18c0,0.55 0.45,1 1,1h5v-2H4C3.45,17 3,17.45 3,18zM3,6L3,6c0,0.55 0.45,1 1,1h9V5H4C3.45,5 3,5.45 3,6zM13,20v-1h7c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-7v-1c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1l0,0C12.55,21 13,20.55 13,20zM7,10v1H4c-0.55,0 -1,0.45 -1,1l0,0c0,0.55 0.45,1 1,1h3v1c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1l0,0C7.45,9 7,9.45 7,10zM21,12L21,12c0,-0.55 -0.45,-1 -1,-1h-9v2h9C20.55,13 21,12.55 21,12zM16,9L16,9c0.55,0 1,-0.45 1,-1V7h3c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1h-3V4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v4C15,8.55 15.45,9 16,9z"/>
+ android:pathData="M3,18c0,0.55 0.45,1 1,1h5v-2L4,17c-0.55,0 -1,0.45 -1,1zM3,6c0,0.55 0.45,1 1,1h9L13,5L4,5c-0.55,0 -1,0.45 -1,1zM13,20v-1h7c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-7v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1zM7,10v1L4,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM21,12c0,-0.55 -0.45,-1 -1,-1h-9v2h9c0.55,0 1,-0.45 1,-1zM16,9c0.55,0 1,-0.45 1,-1L17,7h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L17,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tv.xml b/compose/material/material/icons/generator/raw-icons/rounded/tv.xml
index 3129718..bdf805e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tv.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tv.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H4C2.9,3 2,3.9 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h4c1.1,0 1.99,-0.9 1.99,-2L22,5C22,3.9 21.1,3 20,3zM20,17H4V5h16V17z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM20,17L4,17c-0.55,0 -1,-0.45 -1,-1L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/tv_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/tv_off.xml
index 31fb070..e4ffc2b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/tv_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/tv_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3H5.83l2,2H20v12.17l1.32,1.32c0.41,-0.37 0.67,-0.9 0.67,-1.49L22,5C22,3.9 21.1,3 20,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1.39,2.81C1,3.2 1,3.83 1.39,4.22l0.62,0.62C2.01,4.9 2,4.95 2,5v12c0,1.1 0.9,2 2,2h4v1c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-1h0.17l3.61,3.61c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L2.81,2.81C2.42,2.42 1.78,2.42 1.39,2.81L1.39,2.81zM4,6.83L14.17,17H4V6.83z"/>
+ android:pathData="M21,8v9.88l1.85,1.85c0.1,-0.22 0.15,-0.47 0.15,-0.73V7c0,-1.11 -0.9,-2 -2,-2h-7.59l2.94,-2.94c0.2,-0.2 0.2,-0.51 0,-0.71s-0.51,-0.2 -0.71,0L12,4.99 8.36,1.35c-0.2,-0.2 -0.51,-0.2 -0.71,0s-0.2,0.51 0,0.71L10.59,5H8.12l2,2H20c0.55,0 1,0.45 1,1zM3.12,2.83c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l0.82,0.82C1.65,5.28 1,6.06 1,7v12c0,1.1 0.9,2 2,2h15.46l1.29,1.29c0.39,0.39 1.02,0.39 1.41,0 0.36,-0.36 0.37,-0.92 0.07,-1.31h0.03L3.12,2.83zM3,18V8c0,-0.55 0.45,-1 1,-1h0.46l12,12H4c-0.55,0 -1,-0.45 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/two_wheeler.xml b/compose/material/material/icons/generator/raw-icons/rounded/two_wheeler.xml
index 19ee6ae..a0b9027 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/two_wheeler.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/two_wheeler.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.64,11.05c-0.78,-0.12 -1.52,-0.02 -2.17,0.26L16.68,9h1.82C18.78,9 19,8.78 19,8.5V6.81c0,-0.37 -0.39,-0.61 -0.72,-0.45l-2.63,1.31l-1.48,-1.9C13.79,5.29 13.21,5 12.59,5H11c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1.59l1.55,2h-2.78c-0.24,0 -0.48,0.04 -0.7,0.13L7,10.5L4.98,9.29C4.66,9.1 4.31,9 3.95,9h-3.2C0.34,9 0,9.34 0,9.75v0c0,0.41 0.34,0.75 0.75,0.75h1.82l0.66,0.58c-2.13,0.42 -3.66,2.51 -3.13,4.86c0.33,1.44 1.48,2.61 2.92,2.95c2.56,0.6 4.81,-1.24 4.95,-3.65l1.46,1.28C9.8,16.82 10.27,17 10.75,17h1.18c0.67,0 1.29,-0.33 1.66,-0.89l2.8,-4.21l0.48,0.62c-0.64,0.81 -1,1.85 -0.85,2.99c0.23,1.74 1.63,3.19 3.37,3.44c2.68,0.39 4.94,-1.87 4.56,-4.55C23.71,12.71 22.33,11.32 20.64,11.05zM4,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2c1.1,0 2,0.9 2,2S5.1,17 4,17zM20,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S21.1,17 20,17z"/>
+ android:pathData="M20,11c-0.18,0 -0.36,0.03 -0.53,0.05L17.41,9H19c0.55,0 1,-0.45 1,-1V7.62c0,-0.74 -0.78,-1.23 -1.45,-0.89l-2.28,1.14l-2.57,-2.57C13.52,5.11 13.26,5 13,5h-3C9.45,5 9,5.45 9,6v0c0,0.55 0.45,1 1,1h2.17c0.27,0 0.52,0.11 0.71,0.29L14.59,9h-3.35c-0.16,0 -0.31,0.04 -0.45,0.11l-3.14,1.57c-0.38,0.19 -0.85,0.12 -1.15,-0.19l-1.2,-1.2C5.11,9.11 4.85,9 4.59,9H1c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h3c-2.52,0 -4.49,2.32 -3.89,4.94c0.33,1.45 1.5,2.62 2.95,2.95C5.68,19.49 8,17.52 8,15l1.41,1.41C9.79,16.79 10.3,17 10.83,17h1.01c0.72,0 1.38,-0.38 1.74,-1.01l2.91,-5.09l1.01,1.01c-1.13,0.91 -1.76,2.41 -1.38,4.05c0.34,1.44 1.51,2.61 2.95,2.94C21.68,19.49 24,17.51 24,15C24,12.79 22.21,11 20,11zM4,17c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2c1.1,0 2,0.9 2,2C6,16.1 5.1,17 4,17zM20,17c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C22,16.1 21.1,17 20,17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/unarchive.xml b/compose/material/material/icons/generator/raw-icons/rounded/unarchive.xml
index 94b40c4..46dda22 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/unarchive.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/unarchive.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6C5.53,3 5.12,3.21 4.84,3.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5C21,6.02 20.83,5.57 20.54,5.23zM14.79,13H13v3.04c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V13H9.21c-0.45,0 -0.67,-0.54 -0.35,-0.85l2.79,-2.79c0.2,-0.2 0.51,-0.2 0.71,0l2.79,2.79C15.46,12.46 15.24,13 14.79,13zM5.41,6l0.83,-1h11.52l0.84,1H5.41z"/>
+ android:pathData="M20.55,5.22l-1.39,-1.68C18.88,3.21 18.47,3 18,3L6,3c-0.47,0 -0.88,0.21 -1.15,0.55L3.46,5.22C3.17,5.57 3,6.01 3,6.5L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6.5c0,-0.49 -0.17,-0.93 -0.45,-1.28zM12.35,9.85L17.5,15L14,15v2h-4v-2L6.5,15l5.15,-5.15c0.19,-0.19 0.51,-0.19 0.7,0zM5.12,5l0.82,-1h12l0.93,1L5.12,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/undo.xml b/compose/material/material/icons/generator/raw-icons/rounded/undo.xml
index 67cc60b..eca90675 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/undo.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/undo.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.4,10.91c3.9,-3.88 10.23,-3.88 14.12,0.02c1.09,1.09 1.9,2.4 2.39,3.82C22.12,15.36 21.65,16 21,16H20.9c-0.42,0 -0.77,-0.28 -0.91,-0.67c-0.39,-1.11 -1.02,-2.13 -1.88,-2.99c-3.11,-3.11 -8.18,-3.12 -11.3,-0.02l1.97,1.97C9.41,14.92 8.96,16 8.07,16H3.49c-0.55,0 -1,-0.45 -1,-1v-4.59c0,-0.89 1.08,-1.34 1.71,-0.71L5.4,10.91z"/>
+ android:pathData="M12.5,8c-2.65,0 -5.05,0.99 -6.9,2.6L3.71,8.71C3.08,8.08 2,8.52 2,9.41V15c0,0.55 0.45,1 1,1h5.59c0.89,0 1.34,-1.08 0.71,-1.71l-1.91,-1.91c1.39,-1.16 3.16,-1.88 5.12,-1.88 3.16,0 5.89,1.84 7.19,4.5 0.27,0.56 0.91,0.84 1.5,0.64 0.71,-0.23 1.07,-1.04 0.75,-1.72C20.23,10.42 16.65,8 12.5,8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/unfold_less.xml b/compose/material/material/icons/generator/raw-icons/rounded/unfold_less.xml
index 9da3167..8b13997 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/unfold_less.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/unfold_less.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.38,4.7L12,7.08L9.62,4.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.03 0,1.42l3.08,3.08c0.39,0.39 1.02,0.39 1.41,0l3.08,-3.08c0.39,-0.39 0.39,-1.03 0,-1.42l0,0C15.4,4.31 14.76,4.32 14.38,4.7zM9.62,19.3L12,16.92l2.38,2.38c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.03 0,-1.42l-3.08,-3.08c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.08,3.08c-0.39,0.39 -0.39,1.03 0,1.42l0,0C8.6,19.69 9.24,19.68 9.62,19.3z"/>
+ android:pathData="M8.12,19.3c0.39,0.39 1.02,0.39 1.41,0L12,16.83l2.47,2.47c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41l-3.17,-3.17c-0.39,-0.39 -1.02,-0.39 -1.41,0l-3.17,3.17c-0.4,0.38 -0.4,1.02 -0.01,1.41zM15.88,4.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,7.17 9.53,4.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.03 0,1.42l3.17,3.17c0.39,0.39 1.02,0.39 1.41,0l3.17,-3.17c0.4,-0.39 0.4,-1.03 0.01,-1.42z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/unfold_more.xml b/compose/material/material/icons/generator/raw-icons/rounded/unfold_more.xml
index 8e01bda..1748641 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/unfold_more.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/unfold_more.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,5.83l2.46,2.46c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L12.7,3.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.12,6.88c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,5.83zM12,18.17l-2.46,-2.46c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l3.17,3.18c0.39,0.39 1.02,0.39 1.41,0l3.17,-3.17c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,18.17z"/>
+ android:pathData="M12,5.83l2.46,2.46c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L12.7,3.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.12,6.88c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,5.83zM12,18.17l-2.46,-2.46c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l3.17,3.18c0.39,0.39 1.02,0.39 1.41,0l3.17,-3.17c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L12,18.17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/unsubscribe.xml b/compose/material/material/icons/generator/raw-icons/rounded/unsubscribe.xml
index e30ce76..e3157e0 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/unsubscribe.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/unsubscribe.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c1.08,0 2.09,0.25 3,0.68V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h8.29C12.1,19.37 12,18.7 12,18C12,14.13 15.13,11 19,11zM4.4,8.25C4.15,8.09 4,7.82 4,7.53c0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19C19.27,6.46 20,6.86 20,7.53c0,0.29 -0.15,0.56 -0.4,0.72l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25zM19,13c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S21.76,13 19,13zM21.5,18.5h-5c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5h5c0.28,0 0.5,0.22 0.5,0.5S21.78,18.5 21.5,18.5z"/>
+ android:pathData="M18.5,11.5c0.92,0 1.75,0.26 2.49,0.69L20.99,5c0,-1.1 -0.89,-2 -1.99,-2L5,3c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h8.55c-0.02,-0.17 -0.05,-0.33 -0.05,-0.5 0,-2.76 2.24,-5 5,-5zM12.89,10.05c-0.56,0.28 -1.23,0.28 -1.79,0l-5.61,-2.8c-0.3,-0.15 -0.49,-0.46 -0.49,-0.8 0,-0.66 0.7,-1.1 1.29,-0.8L12,8.5l5.71,-2.85c0.59,-0.3 1.29,0.13 1.29,0.8 0,0.34 -0.19,0.65 -0.49,0.8l-5.62,2.8zM18.5,13c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5 3.5,-1.57 3.5,-3.5 -1.57,-3.5 -3.5,-3.5zM20.5,16.5c0,0.28 -0.22,0.5 -0.5,0.5h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5h3c0.28,0 0.5,0.22 0.5,0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/update.xml b/compose/material/material/icons/generator/raw-icons/rounded/update.xml
index b6283c4..2425d97 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/update.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/update.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,8v4c0,0.27 0.11,0.52 0.29,0.71l2.79,2.79c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41l-2.5,-2.5V8c0,-0.55 -0.45,-1 -1,-1h0C11.45,7 11,7.45 11,8zM20.15,4.85l-1.31,1.31c-1.6,-1.88 -3.96,-3.09 -6.6,-3.16C7.35,2.88 3.14,6.86 3,11.74C2.86,16.83 6.94,21 12,21c4.2,0 7.72,-2.88 8.72,-6.76c0.16,-0.63 -0.33,-1.24 -0.98,-1.24h0c-0.45,0 -0.85,0.3 -0.96,0.73c-0.87,3.41 -4.25,5.83 -8.05,5.16c-2.78,-0.49 -5.04,-2.71 -5.58,-5.47C4.26,8.94 7.68,5 12,5c2.18,0 4.12,1.02 5.41,2.59l-1.55,1.55C15.54,9.46 15.76,10 16.21,10h4.29c0.28,0 0.5,-0.22 0.5,-0.5V5.21C21,4.76 20.46,4.54 20.15,4.85z"/>
+ android:pathData="M11,8.75v3.68c0,0.35 0.19,0.68 0.49,0.86l3.12,1.85c0.36,0.21 0.82,0.09 1.03,-0.26c0.21,-0.36 0.1,-0.82 -0.26,-1.03l-2.87,-1.71v-3.4C12.5,8.34 12.16,8 11.75,8S11,8.34 11,8.75zM21,9.5V4.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.78,1.78c-1.81,-1.81 -4.39,-2.85 -7.21,-2.6c-4.19,0.38 -7.64,3.75 -8.1,7.94C2.46,16.4 6.69,21 12,21c4.59,0 8.38,-3.44 8.93,-7.88c0.07,-0.6 -0.4,-1.12 -1,-1.12c-0.5,0 -0.92,0.37 -0.98,0.86c-0.43,3.49 -3.44,6.19 -7.05,6.14c-3.71,-0.05 -6.84,-3.18 -6.9,-6.9C4.94,8.2 8.11,5 12,5c1.93,0 3.68,0.79 4.95,2.05l-2.09,2.09C14.54,9.46 14.76,10 15.21,10h5.29C20.78,10 21,9.78 21,9.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/upload.xml b/compose/material/material/icons/generator/raw-icons/rounded/upload.xml
index d5c2075..ff67014 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/upload.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/upload.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7.4,10h1.59v5c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-5h1.59c0.89,0 1.34,-1.08 0.71,-1.71L12.7,3.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L6.7,8.29C6.07,8.92 6.51,10 7.4,10zM5,19c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6C5.45,18 5,18.45 5,19z"/>
+ android:pathData="M10,16h4c0.55,0 1,-0.45 1,-1v-5h1.59c0.89,0 1.34,-1.08 0.71,-1.71L12.71,3.7c-0.39,-0.39 -1.02,-0.39 -1.41,0L6.71,8.29c-0.63,0.63 -0.19,1.71 0.7,1.71L9,10v5c0,0.55 0.45,1 1,1zM6,18h12c0.55,0 1,0.45 1,1s-0.45,1 -1,1L6,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/usb.xml b/compose/material/material/icons/generator/raw-icons/rounded/usb.xml
index 11f38b2..616bdbe 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/usb.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/usb.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15,8.5v3c0,0.28 0.22,0.5 0.5,0.5H16v2h-3V6h1c0.41,0 0.65,-0.47 0.4,-0.8l-2,-2.67c-0.2,-0.27 -0.6,-0.27 -0.8,0l-2,2.67C9.35,5.53 9.59,6 10,6h1v8H8v-2.28c0.66,-0.38 1.07,-1.1 0.99,-1.93C8.9,8.9 8.19,8.16 7.31,8.02C6.07,7.84 5,8.8 5,10c0,0.74 0.4,1.38 1,1.72V14c0,1.1 0.9,2 2,2h3v2.28c-0.66,0.38 -1.07,1.1 -0.99,1.93c0.09,0.89 0.8,1.63 1.68,1.77C12.93,22.16 14,21.2 14,20c0,-0.74 -0.4,-1.38 -1,-1.72V16h3c1.1,0 2,-0.9 2,-2v-2h0.5c0.28,0 0.5,-0.22 0.5,-0.5v-3C19,8.22 18.78,8 18.5,8h-3C15.22,8 15,8.22 15,8.5z"/>
+ android:pathData="M18,7h-2c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1v2h-3V5h1c0.41,0 0.65,-0.47 0.4,-0.8l-2,-2.67c-0.2,-0.27 -0.6,-0.27 -0.8,0l-2,2.67c-0.25,0.33 -0.01,0.8 0.4,0.8h1v8H8v-2.07c0.83,-0.44 1.38,-1.36 1.14,-2.43 -0.17,-0.77 -0.77,-1.4 -1.52,-1.61C6.15,6.48 4.8,7.59 4.8,9c0,0.85 0.5,1.56 1.2,1.93V13c0,1.1 0.9,2 2,2h3v3.05c-0.86,0.45 -1.39,1.42 -1.13,2.49 0.18,0.75 0.79,1.38 1.54,1.58 1.46,0.39 2.8,-0.7 2.8,-2.12 0,-0.85 -0.49,-1.58 -1.2,-1.95V15h3c1.1,0 2,-0.9 2,-2v-2c0.55,0 1,-0.45 1,-1V8C19,7.45 18.55,7 18,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vaccines.xml b/compose/material/material/icons/generator/raw-icons/rounded/vaccines.xml
new file mode 100644
index 0000000..94fb5a5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vaccines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,22.5c0.55,0 1,-0.45 1,-1V17h1c1.1,0 2,-0.9 2,-2V7.5c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1H8V4h0.5c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1H6v1.5H3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1V15c0,1.1 0.9,2 2,2h1v4.5C6,22.05 6.45,22.5 7,22.5zM9,9H7.25C6.84,9 6.5,9.34 6.5,9.75c0,0.41 0.34,0.75 0.75,0.75H9V12H7.25c-0.41,0 -0.75,0.34 -0.75,0.75c0,0.41 0.34,0.75 0.75,0.75H9L9,15H5V7.5h4V9zM19.5,10.5V10c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-5c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1v0.5c0,0.5 -1.5,1.16 -1.5,3V20c0,1.1 0.9,2 2,2h4c1.1,0 2,-0.9 2,-2v-6.5C21,11.66 19.5,11 19.5,10.5zM16.5,10.5V10h1v0.5c0,1.6 1.5,2 1.5,3V14h-4c0,-0.21 0,-0.39 0,-0.5C15,12.5 16.5,12.1 16.5,10.5zM15,20c0,0 0,-0.63 0,-1.5h4V20H15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/verified.xml b/compose/material/material/icons/generator/raw-icons/rounded/verified.xml
index 36db70d..45660ed 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/verified.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/verified.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22.42,11.34l-1.86,-2.13l0.26,-2.82c0.05,-0.5 -0.29,-0.96 -0.77,-1.07L17.29,4.7l-1.44,-2.44c-0.26,-0.43 -0.79,-0.61 -1.26,-0.41L12,2.96L9.41,1.85c-0.46,-0.2 -1,-0.02 -1.25,0.41L6.71,4.69L3.96,5.31C3.47,5.42 3.13,5.87 3.18,6.37L3.44,9.2l-1.87,2.14c-0.33,0.38 -0.33,0.94 0,1.32l1.87,2.13l-0.26,2.83c-0.05,0.5 0.29,0.96 0.77,1.07l2.76,0.63l1.44,2.43c0.26,0.43 0.8,0.61 1.26,0.41L12,21.03l2.59,1.11c0.46,0.2 1,0.02 1.25,-0.41l1.44,-2.43l2.76,-0.63c0.49,-0.11 0.82,-0.57 0.77,-1.07l-0.26,-2.82l1.86,-2.13C22.75,12.28 22.75,11.72 22.42,11.34zM10.23,14.83l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-4.24,4.24C11.26,15.22 10.62,15.22 10.23,14.83z"/>
+ android:pathData="M23,12l-2.44,-2.79l0.34,-3.69l-3.61,-0.82L15.4,1.5L12,2.96L8.6,1.5L6.71,4.69L3.1,5.5L3.44,9.2L1,12l2.44,2.79l-0.34,3.7l3.61,0.82L8.6,22.5l3.4,-1.47l3.4,1.46l1.89,-3.19l3.61,-0.82l-0.34,-3.69L23,12zM9.38,16.01L7,13.61c-0.39,-0.39 -0.39,-1.02 0,-1.41l0.07,-0.07c0.39,-0.39 1.03,-0.39 1.42,0l1.61,1.62l5.15,-5.16c0.39,-0.39 1.03,-0.39 1.42,0l0.07,0.07c0.39,0.39 0.39,1.02 0,1.41l-5.92,5.94C10.41,16.4 9.78,16.4 9.38,16.01z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/verified_user.xml b/compose/material/material/icons/generator/raw-icons/rounded/verified_user.xml
index 1ec98b1..620af50 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/verified_user.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/verified_user.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.3,2.26l-6,2.25C4.52,4.81 4,5.55 4,6.39v4.71c0,5.05 3.41,9.76 8,10.91c4.59,-1.15 8,-5.86 8,-10.91V6.39c0,-0.83 -0.52,-1.58 -1.3,-1.87l-6,-2.25C12.25,2.09 11.75,2.09 11.3,2.26zM10.23,14.83l-2.12,-2.12c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0l1.41,1.41l3.54,-3.54c0.39,-0.39 1.02,-0.39 1.41,0l0,0c0.39,0.39 0.39,1.02 0,1.41l-4.24,4.24C11.26,15.22 10.62,15.22 10.23,14.83z"/>
+ android:pathData="M11.19,1.36l-7,3.11C3.47,4.79 3,5.51 3,6.3L3,11c0,5.55 3.84,10.74 9,12 5.16,-1.26 9,-6.45 9,-12L21,6.3c0,-0.79 -0.47,-1.51 -1.19,-1.83l-7,-3.11c-0.51,-0.23 -1.11,-0.23 -1.62,0zM9.29,16.29L6.7,13.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L10,14.17l5.88,-5.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-6.59,6.59c-0.38,0.39 -1.02,0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_bottom.xml b/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_bottom.xml
index 01cce38..fba1808 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_bottom.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_bottom.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M14.79,13H13V4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v9H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79C15.46,13.54 15.24,13 14.79,13zM4,20L4,20c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C4.45,19 4,19.45 4,20z"/>
+ android:pathData="M14.79,13H13V4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v9H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.36,-0.85zM4,20c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_center.xml b/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_center.xml
index e2aff75..997228f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_center.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_center.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M9.21,18H11v3c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-3h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.79,2.79C8.54,17.46 8.76,18 9.21,18zM14.79,6H13V3c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v3H9.21C8.76,6 8.54,6.54 8.85,6.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79C15.46,6.54 15.24,6 14.79,6zM4,12L4,12c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C4.45,11 4,11.45 4,12z"/>
+ android:pathData="M9.21,19L11,19v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.79,2.79c-0.31,0.31 -0.09,0.85 0.36,0.85zM14.79,5L13,5L13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3L9.21,5c-0.45,0 -0.67,0.54 -0.36,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.32,-0.31 0.1,-0.85 -0.35,-0.85zM4,12c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,11c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_top.xml b/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_top.xml
index 5826df8..79ad572 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_top.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vertical_align_top.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M15.15,10.15l-2.79,-2.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.79,2.79C8.54,10.46 8.76,11 9.21,11H11v9c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-9h1.79C15.24,11 15.46,10.46 15.15,10.15zM5,5h14c0.55,0 1,-0.45 1,-1l0,0c0,-0.55 -0.45,-1 -1,-1H5C4.45,3 4,3.45 4,4l0,0C4,4.55 4.45,5 5,5z"/>
+ android:pathData="M9.21,11H11v9c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-9h1.79c0.45,0 0.67,-0.54 0.35,-0.85l-2.79,-2.79c-0.2,-0.2 -0.51,-0.2 -0.71,0l-2.79,2.79c-0.31,0.31 -0.09,0.85 0.36,0.85zM4,4c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vertical_split.xml b/compose/material/material/icons/generator/raw-icons/rounded/vertical_split.xml
index cc8bbb6..1041d937 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/vertical_split.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vertical_split.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,15h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,15 4,15zM4,19h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,19 4,19zM4,11h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1S3.45,11 4,11zM3,6c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6zM14,5h6c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1V6C13,5.45 13.45,5 14,5z"/>
+ android:pathData="M4,15h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,19h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,11h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM3,6c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,5c-0.55,0 -1,0.45 -1,1zM14,5h6c0.55,0 1,0.45 1,1v12c0,0.55 -0.45,1 -1,1h-6c-0.55,0 -1,-0.45 -1,-1L13,6c0,-0.55 0.45,-1 1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vibration.xml b/compose/material/material/icons/generator/raw-icons/rounded/vibration.xml
index 1042dca..633f459 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/vibration.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vibration.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M1,15L1,15c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v4C0,14.55 0.45,15 1,15zM4,17L4,17c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1l0,0C3.45,7 3,7.45 3,8v8C3,16.55 3.45,17 4,17zM22,10v4c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1l0,0C22.45,9 22,9.45 22,10zM20,17L20,17c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v8C19,16.55 19.45,17 20,17zM16.5,3h-9C6.67,3 6,3.67 6,4.5v15C6,20.33 6.67,21 7.5,21h9c0.83,0 1.5,-0.67 1.5,-1.5v-15C18,3.67 17.33,3 16.5,3zM16,19H8V5h8V19z"/>
+ android:pathData="M1,15c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM4,17c0.55,0 1,-0.45 1,-1L5,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8c0,0.55 0.45,1 1,1zM22,10v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM20,17c0.55,0 1,-0.45 1,-1L21,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v8c0,0.55 0.45,1 1,1zM16.5,3h-9C6.67,3 6,3.67 6,4.5v15c0,0.83 0.67,1.5 1.5,1.5h9c0.83,0 1.5,-0.67 1.5,-1.5v-15c0,-0.83 -0.67,-1.5 -1.5,-1.5zM16,19L8,19L8,5h8v14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/video_call.xml b/compose/material/material/icons/generator/raw-icons/rounded/video_call.xml
index 7dc3166..8b5a3a7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/video_call.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/video_call.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.15,7.35L18,10.48V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l3.15,3.13C21.46,16.97 22,16.74 22,16.3V7.7C22,7.26 21.46,7.03 21.15,7.35zM13,13h-2v2c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-2H7c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h2V9c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v2h2c0.55,0 1,0.45 1,1v0C14,12.55 13.55,13 13,13z"/>
+ android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71V8.91c0,-0.89 -1.08,-1.34 -1.71,-0.71L17,10.5zM13,13h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2H7c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2V9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/video_label.xml b/compose/material/material/icons/generator/raw-icons/rounded/video_label.xml
index 4c7d7fe..6b9445b 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/video_label.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/video_label.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM20,15H4V6h16V15z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,16L3,16L3,6c0,-0.55 0.45,-1 1,-1h16c0.55,0 1,0.45 1,1v10z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/video_library.xml b/compose/material/material/icons/generator/raw-icons/rounded/video_library.xml
index 576c7eb..1062992 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/video_library.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/video_library.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,6L3,6C2.45,6 2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V7C4,6.45 3.55,6 3,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM11.5,12.67V7.33c0,-0.79 0.88,-1.27 1.54,-0.84l4.15,2.67c0.61,0.39 0.61,1.29 0,1.68l-4.15,2.67C12.38,13.94 11.5,13.46 11.5,12.67z"/>
+ android:pathData="M3,6c-0.55,0 -1,0.45 -1,1v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1L4,7c0,-0.55 -0.45,-1 -1,-1zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM12,14.5v-9l5.47,4.1c0.27,0.2 0.27,0.6 0,0.8L12,14.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/video_settings.xml b/compose/material/material/icons/generator/raw-icons/rounded/video_settings.xml
index 4731e6d..f94cfe7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/video_settings.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/video_settings.xml
@@ -6,5 +6,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,6h16v4c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h7c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H4V6zM22.58,18c0,-0.22 -0.03,-0.42 -0.06,-0.63l0.84,-0.73c0.18,-0.16 0.22,-0.42 0.1,-0.63l-0.59,-1.02c-0.12,-0.21 -0.37,-0.3 -0.59,-0.22l-1.06,0.36c-0.32,-0.27 -0.68,-0.48 -1.08,-0.63l-0.22,-1.09c-0.05,-0.23 -0.25,-0.4 -0.49,-0.4h-1.18c-0.24,0 -0.44,0.17 -0.49,0.4l-0.22,1.09c-0.4,0.15 -0.76,0.36 -1.08,0.63l-1.06,-0.36c-0.23,-0.08 -0.47,0.02 -0.59,0.22l-0.59,1.02c-0.12,0.21 -0.08,0.47 0.1,0.63l0.84,0.73c-0.03,0.21 -0.06,0.41 -0.06,0.63s0.03,0.42 0.06,0.63l-0.84,0.73c-0.18,0.16 -0.22,0.42 -0.1,0.63l0.59,1.02c0.12,0.21 0.37,0.3 0.59,0.22l1.06,-0.36c0.32,0.27 0.68,0.48 1.08,0.63l0.22,1.09C17.8,22.83 18,23 18.24,23h1.18c0.24,0 0.44,-0.17 0.49,-0.4l0.22,-1.09c0.4,-0.15 0.76,-0.36 1.08,-0.63l1.06,0.36c0.23,0.08 0.47,-0.02 0.59,-0.22l0.59,-1.02c0.12,-0.21 0.08,-0.47 -0.1,-0.63l-0.84,-0.73C22.55,18.42 22.58,18.22 22.58,18zM18.83,20c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S19.93,20 18.83,20zM15.19,11.16l-4.15,-2.67C10.38,8.06 9.5,8.54 9.5,9.33v5.34c0,0.79 0.88,1.27 1.54,0.84l4.15,-2.67C15.8,12.45 15.8,11.55 15.19,11.16z"/>
+ android:pathData="M4,6h16c0.55,0 1,0.45 1,1v4h2V6c0,-1.1 -0.9,-2 -2,-2H3C1.9,4 1,4.9 1,6v12c0,1.1 0.9,2 2,2h9v-2H4c-0.55,0 -1,-0.45 -1,-1V7C3,6.45 3.45,6 4,6z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,12l-6,-4l0,8z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22.71,18.43c0.03,-0.29 0.04,-0.58 0.01,-0.86l1.07,-0.85c0.1,-0.08 0.12,-0.21 0.06,-0.32l-1.03,-1.79c-0.06,-0.11 -0.19,-0.15 -0.31,-0.11L21.23,15c-0.23,-0.17 -0.48,-0.31 -0.75,-0.42l-0.2,-1.36C20.26,13.09 20.16,13 20.03,13h-2.07c-0.12,0 -0.23,0.09 -0.25,0.21l-0.2,1.36c-0.26,0.11 -0.51,0.26 -0.74,0.42l-1.28,-0.5c-0.12,-0.05 -0.25,0 -0.31,0.11l-1.03,1.79c-0.06,0.11 -0.04,0.24 0.06,0.32l1.07,0.86c-0.03,0.29 -0.04,0.58 -0.01,0.86l-1.07,0.85c-0.1,0.08 -0.12,0.21 -0.06,0.32l1.03,1.79c0.06,0.11 0.19,0.15 0.31,0.11l1.27,-0.5c0.23,0.17 0.48,0.31 0.75,0.42l0.2,1.36c0.02,0.12 0.12,0.21 0.25,0.21h2.07c0.12,0 0.23,-0.09 0.25,-0.21l0.2,-1.36c0.26,-0.11 0.51,-0.26 0.74,-0.42l1.28,0.5c0.12,0.05 0.25,0 0.31,-0.11l1.03,-1.79c0.06,-0.11 0.04,-0.24 -0.06,-0.32L22.71,18.43zM19,19.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S19.83,19.5 19,19.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/videocam.xml b/compose/material/material/icons/generator/raw-icons/rounded/videocam.xml
index 67ac49d..f755b5a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/videocam.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/videocam.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,10.48V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l3.15,3.13C21.46,16.97 22,16.74 22,16.3V7.7c0,-0.44 -0.54,-0.67 -0.85,-0.35L18,10.48z"/>
+ android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71V8.91c0,-0.89 -1.08,-1.34 -1.71,-0.71L17,10.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/videocam_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/videocam_off.xml
index bbe193e6e..495cd0e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/videocam_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/videocam_off.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,15.17v-1.65l3.15,3.13C21.46,16.97 22,16.74 22,16.3V7.7c0,-0.44 -0.54,-0.67 -0.85,-0.35L18,10.48V6c0,-1.1 -0.9,-2 -2,-2H6.83L18,15.17z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,18L2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C1,3.2 1,3.83 1.39,4.22l0.85,0.85C2.09,5.35 2,5.66 2,6v12c0,1.1 0.9,2 2,2h12c0.34,0 0.65,-0.09 0.93,-0.24l2.85,2.85c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L18,18L18,18z"/>
+ android:pathData="M21,14.2V8.91c0,-0.89 -1.08,-1.34 -1.71,-0.71L17,10.5V7c0,-0.55 -0.45,-1 -1,-1h-5.61l8.91,8.91c0.62,0.63 1.7,0.18 1.7,-0.71zM2.71,2.56c-0.39,0.39 -0.39,1.02 0,1.41L4.73,6H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.21,0 0.39,-0.08 0.55,-0.18l2.48,2.48c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.12,2.56c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/videogame_asset.xml b/compose/material/material/icons/generator/raw-icons/rounded/videogame_asset.xml
index 3635b70..ea4d3d1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/videogame_asset.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/videogame_asset.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6H4C2.9,6 2,6.9 2,8v8c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM10,13H9v1c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-1H6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h1v-1c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v1h1c0.55,0 1,0.45 1,1v0C11,12.55 10.55,13 10,13zM14.5,15c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5S15.33,15 14.5,15zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9S19,9.67 19,10.5S18.33,12 17.5,12z"/>
+ android:pathData="M21,6L3,6c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,8c0,-1.1 -0.9,-2 -2,-2zM10,13L8,13v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2L4,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2L6,9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM15.5,15c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S18.67,9 19.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_array.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_array.xml
index 62ab91b..53aba8e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_array.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_array.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,18h1c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6v11C4,17.55 4.45,18 5,18zM18,6v11c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-1C18.45,5 18,5.45 18,6zM9,18h7c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H9C8.45,5 8,5.45 8,6v11C8,17.55 8.45,18 9,18z"/>
+ android:pathData="M20,5h-1c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1V6C21,5.45 20.55,5 20,5zM16,5H8C7.45,5 7,5.45 7,6v12c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1V6C17,5.45 16.55,5 16,5zM5,5H4C3.45,5 3,5.45 3,6v12c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1V6C6,5.45 5.55,5 5,5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_carousel.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_carousel.xml
index 8517f67..98ad8b60 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_carousel.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_carousel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,19h8c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1H8C7.45,4 7,4.45 7,5v13C7,18.55 7.45,19 8,19zM3,17h2c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1H3C2.45,6 2,6.45 2,7v9C2,16.55 2.45,17 3,17zM18,7v9c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1h-2C18.45,6 18,6.45 18,7z"/>
+ android:pathData="M3,7h2c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1H3c-0.55,0 -1,-0.45 -1,-1V8C2,7.45 2.45,7 3,7zM8,19h8c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H8C7.45,5 7,5.45 7,6v12C7,18.55 7.45,19 8,19zM19,7h2c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,-0.45 -1,-1V8C18,7.45 18.45,7 19,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_column.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_column.xml
index 49845ef..12e231d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_column.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_column.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,18h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v11C10,17.55 10.45,18 11,18zM5,18h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6v11C4,17.55 4.45,18 5,18zM16,6v11c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-3C16.45,5 16,5.45 16,6z"/>
+ android:pathData="M14.67,6v12c0,0.55 -0.45,1 -1,1h-3.33c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1h3.33C14.22,5 14.67,5.45 14.67,6zM16.67,19H20c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-3.33c-0.55,0 -1,0.45 -1,1v12C15.67,18.55 16.11,19 16.67,19zM8.33,18V6c0,-0.55 -0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6v12c0,0.55 0.45,1 1,1h3.33C7.89,19 8.33,18.55 8.33,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_comfy.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_comfy.xml
index f2330a0..723e9e4 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_comfy.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_comfy.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h2.5v-2.5H4V18zM4,13.25h2.5v-2.5H4V13.25zM4,8.5h2.5V6H4V8.5zM17.5,6v2.5H20V6H17.5zM13,8.5h2.5V6H13V8.5zM17.5,18H20v-2.5h-2.5V18zM17.5,13.25H20v-2.5h-2.5V13.25zM8.5,18H11v-2.5H8.5V18zM13,18h2.5v-2.5H13V18zM8.5,8.5H11V6H8.5V8.5zM13,13.25h2.5v-2.5H13V13.25zM8.5,13.25H11v-2.5H8.5V13.25z"/>
+ android:pathData="M3,9h4L7,5L5,5c-1.1,0 -2,0.9 -2,2v2zM3,14h4v-4L3,10v4zM8,14h4v-4L8,10v4zM13,14h4v-4h-4v4zM8,9h4L12,5L8,5v4zM13,5v4h4L17,5h-4zM18,14h4v-4h-4v4zM5,19h2v-4L3,15v2c0,1.1 0.9,2 2,2zM8,19h4v-4L8,15v4zM13,19h4v-4h-4v4zM18,19h2c1.1,0 2,-0.9 2,-2v-2h-4v4zM18,5v4h4L22,7c0,-1.1 -0.9,-2 -2,-2h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_compact.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_compact.xml
index 517a5fa..bef842e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_compact.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_compact.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2,5v5c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1V5c0,-0.55 -0.45,-1 -1,-1H3C2.45,4 2,4.45 2,5zM11,20h10c0.55,0 1,-0.45 1,-1v-5c0,-0.55 -0.45,-1 -1,-1H11c-0.55,0 -1,0.45 -1,1v5C10,19.55 10.45,20 11,20zM3,20h4c0.55,0 1,-0.45 1,-1v-5c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1v5C2,19.55 2.45,20 3,20z"/>
+ android:pathData="M5,19h4v-7L3,12v5c0,1.1 0.9,2 2,2zM10,19h10c1.1,0 2,-0.9 2,-2v-5L10,12v7zM3,7v4h19L22,7c0,-1.1 -0.9,-2 -2,-2L5,5c-1.1,0 -2,0.9 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_day.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_day.xml
index ac25376..6164e41 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_day.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_day.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,18H4c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v0C21,18.45 20.55,18 20,18zM19,8H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4C21,8.9 20.1,8 19,8zM20,4H4C3.45,4 3,4.45 3,5v0c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v0C21,4.45 20.55,4 20,4z"/>
+ android:pathData="M3,21h17c0.55,0 1,-0.45 1,-1v-1c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1v1c0,0.55 0.45,1 1,1zM20,8H3c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1zM2,4v1c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_headline.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_headline.xml
index 4fbd0bf..4395ffc 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_headline.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_headline.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,15h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1S4.45,15 5,15zM5,19h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1S4.45,19 5,19zM5,11h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1S4.45,11 5,11zM4,6c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6z"/>
+ android:pathData="M5,15h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM5,19h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM5,11h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM4,6c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,5c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_list.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_list.xml
index 00384aa..2ceb1b9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_list.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_list.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,14h2c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v2C3,13.55 3.45,14 4,14zM4,19h2c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v2C3,18.55 3.45,19 4,19zM4,9h2c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6v2C3,8.55 3.45,9 4,9zM9,14h10c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H9c-0.55,0 -1,0.45 -1,1v2C8,13.55 8.45,14 9,14zM9,19h10c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H9c-0.55,0 -1,0.45 -1,1v2C8,18.55 8.45,19 9,19zM8,6v2c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H9C8.45,5 8,5.45 8,6z"/>
+ android:pathData="M4,14h2c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v2C3,13.55 3.45,14 4,14zM4,19h2c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v2C3,18.55 3.45,19 4,19zM4,9h2c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6v2C3,8.55 3.45,9 4,9zM9,14h11c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H9c-0.55,0 -1,0.45 -1,1v2C8,13.55 8.45,14 9,14zM9,19h11c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1H9c-0.55,0 -1,0.45 -1,1v2C8,18.55 8.45,19 9,19zM8,6v2c0,0.55 0.45,1 1,1h11c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H9C8.45,5 8,5.45 8,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_module.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_module.xml
index 8947621..dd00e5a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_module.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_module.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,11h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6v4C4,10.55 4.45,11 5,11zM5,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v4C4,17.55 4.45,18 5,18zM11,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4C10,17.55 10.45,18 11,18zM17,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4C16,17.55 16.45,18 17,18zM11,11h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4C10,10.55 10.45,11 11,11zM16,6v4c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-3C16.45,5 16,5.45 16,6z"/>
+ android:pathData="M14.67,6v4.5c0,0.55 -0.45,1 -1,1h-3.33c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1h3.33C14.22,5 14.67,5.45 14.67,6zM16.67,11.5H20c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-3.33c-0.55,0 -1,0.45 -1,1v4.5C15.67,11.05 16.11,11.5 16.67,11.5zM14.67,18v-4.5c0,-0.55 -0.45,-1 -1,-1h-3.33c-0.55,0 -1,0.45 -1,1V18c0,0.55 0.45,1 1,1h3.33C14.22,19 14.67,18.55 14.67,18zM15.67,13.5V18c0,0.55 0.45,1 1,1H20c0.55,0 1,-0.45 1,-1v-4.5c0,-0.55 -0.45,-1 -1,-1h-3.33C16.11,12.5 15.67,12.95 15.67,13.5zM7.33,12.5H4c-0.55,0 -1,0.45 -1,1V18c0,0.55 0.45,1 1,1h3.33c0.55,0 1,-0.45 1,-1v-4.5C8.33,12.95 7.89,12.5 7.33,12.5zM8.33,10.5V6c0,-0.55 -0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6v4.5c0,0.55 0.45,1 1,1h3.33C7.89,11.5 8.33,11.05 8.33,10.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_quilt.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_quilt.xml
index 8303cf8..3784d3f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_quilt.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_quilt.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4C10,17.55 10.45,18 11,18zM5,18h3c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6v11C4,17.55 4.45,18 5,18zM17,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4C16,17.55 16.45,18 17,18zM10,6v4c0,0.55 0.45,1 1,1h9c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1h-9C10.45,5 10,5.45 10,6z"/>
+ android:pathData="M21,6v4.5c0,0.55 -0.45,1 -1,1h-9.67c-0.55,0 -1,-0.45 -1,-1V6c0,-0.55 0.45,-1 1,-1H20C20.55,5 21,5.45 21,6zM14.67,18v-4.5c0,-0.55 -0.45,-1 -1,-1h-3.33c-0.55,0 -1,0.45 -1,1V18c0,0.55 0.45,1 1,1h3.33C14.22,19 14.67,18.55 14.67,18zM15.67,13.5V18c0,0.55 0.45,1 1,1H20c0.55,0 1,-0.45 1,-1v-4.5c0,-0.55 -0.45,-1 -1,-1h-3.33C16.11,12.5 15.67,12.95 15.67,13.5zM8.33,18V6c0,-0.55 -0.45,-1 -1,-1H4C3.45,5 3,5.45 3,6v12c0,0.55 0.45,1 1,1h3.33C7.89,19 8.33,18.55 8.33,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_stream.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_stream.xml
index 134519e..06bf209 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_stream.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_stream.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,18h15c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v4C4,17.55 4.45,18 5,18zM4,6v4c0,0.55 0.45,1 1,1h15c0.55,0 1,-0.45 1,-1V6c0,-0.55 -0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6z"/>
+ android:pathData="M3,17v-2c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2v2c0,1.1 -0.9,2 -2,2H5C3.9,19 3,18.1 3,17zM3,7v2c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H5C3.9,5 3,5.9 3,7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/view_week.xml b/compose/material/material/icons/generator/raw-icons/rounded/view_week.xml
index a44ee7b..2cc8d6e 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/view_week.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/view_week.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,5H3C2.45,5 2,5.45 2,6v12c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1V6C7,5.45 6.55,5 6,5zM20,5h-3c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1V6C21,5.45 20.55,5 20,5zM13,5h-3C9.45,5 9,5.45 9,6v12c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1V6C14,5.45 13.55,5 13,5z"/>
+ android:pathData="M5.33,20H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h1.33c1.1,0 2,0.9 2,2v12C7.33,19.1 6.44,20 5.33,20zM22,18V6c0,-1.1 -0.9,-2 -2,-2h-1.33c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2H20C21.11,20 22,19.1 22,18zM14.67,18V6c0,-1.1 -0.9,-2 -2,-2h-1.33c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h1.33C13.77,20 14.67,19.1 14.67,18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vignette.xml b/compose/material/material/icons/generator/raw-icons/rounded/vignette.xml
index e8ab566..fa65401 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/vignette.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vignette.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM12,16c-3.25,0 -6,-1.83 -6,-4s2.75,-4 6,-4s6,1.83 6,4S15.25,16 12,16z"/>
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM12,18c-4.42,0 -8,-2.69 -8,-6s3.58,-6 8,-6 8,2.69 8,6 -3.58,6 -8,6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/visibility.xml b/compose/material/material/icons/generator/raw-icons/rounded/visibility.xml
index 06decf9..13d5808 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/visibility.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/visibility.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4C7.31,4 3.26,6.74 1.35,10.7c-0.24,0.5 -0.24,1.1 0,1.6C3.26,16.26 7.31,19 12,19s8.74,-2.74 10.65,-6.7c0.24,-0.5 0.24,-1.1 0,-1.6C20.74,6.74 16.69,4 12,4zM12,16c-2.48,0 -4.5,-2.02 -4.5,-4.5S9.52,7 12,7s4.5,2.02 4.5,4.5S14.48,16 12,16z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,11.5m-2.7,0a2.7,2.7 0,1 1,5.4 0a2.7,2.7 0,1 1,-5.4 0"/>
+ android:pathData="M12,4C7,4 2.73,7.11 1,11.5 2.73,15.89 7,19 12,19s9.27,-3.11 11,-7.5C21.27,7.11 17,4 12,4zM12,16.5c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,8.5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/visibility_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/visibility_off.xml
index b8ebe62..ba18b4a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/visibility_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/visibility_off.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22.65,10.7C20.74,6.74 16.69,4 12,4c-1.53,0 -3,0.3 -4.34,0.83l2.55,2.55C10.76,7.14 11.36,7 12,7c2.48,0 4.5,2.02 4.5,4.5c0,0.64 -0.14,1.24 -0.38,1.79l3.17,3.17c1.41,-1.11 2.57,-2.53 3.35,-4.16C22.89,11.8 22.89,11.2 22.65,10.7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,8.8c-0.12,0 -0.23,0.02 -0.34,0.03l3,3c0.01,-0.11 0.03,-0.22 0.03,-0.34C14.7,10.01 13.49,8.8 12,8.8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0v0c-0.39,0.39 -0.39,1.02 0,1.41l2.06,2.06C3,8.02 2.04,9.28 1.35,10.7c-0.24,0.5 -0.24,1.1 0,1.6C3.26,16.26 7.31,19 12,19c1.26,0 2.47,-0.2 3.6,-0.57l3.47,3.47c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51zM12,16c-2.48,0 -4.5,-2.02 -4.5,-4.5c0,-0.36 0.05,-0.7 0.13,-1.04l1.78,1.78c0.26,0.89 0.95,1.58 1.84,1.84l1.78,1.78C12.7,15.95 12.36,16 12,16z"/>
+ android:pathData="M12,6.5c2.76,0 5,2.24 5,5 0,0.51 -0.1,1 -0.24,1.46l3.06,3.06c1.39,-1.23 2.49,-2.77 3.18,-4.53C21.27,7.11 17,4 12,4c-1.27,0 -2.49,0.2 -3.64,0.57l2.17,2.17c0.47,-0.14 0.96,-0.24 1.47,-0.24zM2.71,3.16c-0.39,0.39 -0.39,1.02 0,1.41l1.97,1.97C3.06,7.83 1.77,9.53 1,11.5 2.73,15.89 7,19 12,19c1.52,0 2.97,-0.3 4.31,-0.82l2.72,2.72c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.13,3.16c-0.39,-0.39 -1.03,-0.39 -1.42,0zM12,16.5c-2.76,0 -5,-2.24 -5,-5 0,-0.77 0.18,-1.5 0.49,-2.14l1.57,1.57c-0.03,0.18 -0.06,0.37 -0.06,0.57 0,1.66 1.34,3 3,3 0.2,0 0.38,-0.03 0.57,-0.07L14.14,16c-0.65,0.32 -1.37,0.5 -2.14,0.5zM14.97,11.17c-0.15,-1.4 -1.25,-2.49 -2.64,-2.64l2.64,2.64z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/voice_chat.xml b/compose/material/material/icons/generator/raw-icons/rounded/voice_chat.xml
index f23743f..d2593f8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/voice_chat.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/voice_chat.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2H4C2.9,2 2.01,2.9 2.01,4L2,19.58c0,0.89 1.08,1.34 1.71,0.71L6,18h14c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM16.15,12.15L15,11.01V13c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v1.99l1.15,-1.14C16.46,7.53 17,7.76 17,8.2v3.59C17,12.24 16.46,12.47 16.15,12.15z"/>
+ android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM16.38,12.7L14,10.8L14,13c0,0.55 -0.45,1 -1,1L7,14c-0.55,0 -1,-0.45 -1,-1L6,7c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v2.2l2.38,-1.9c0.65,-0.52 1.62,-0.06 1.62,0.78v3.84c0,0.84 -0.97,1.3 -1.62,0.78z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/voice_over_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/voice_over_off.xml
index c34e37d..6fa7bbf 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/voice_over_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/voice_over_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,9c0,-2.21 -1.79,-4 -4,-4C8.64,5 8.31,5.06 7.98,5.15l4.87,4.87C12.94,9.69 13,9.36 13,9zM15.69,11.55l0.13,0.13c0.55,0.55 1.48,0.43 1.85,-0.25c0.82,-1.49 0.81,-3.26 -0.02,-4.82c-0.37,-0.69 -1.31,-0.83 -1.86,-0.27l-0.1,0.1c-0.34,0.34 -0.42,0.85 -0.23,1.29c0.34,0.82 0.34,1.72 0,2.54C15.27,10.71 15.35,11.21 15.69,11.55zM20.93,3.01c-0.42,-0.56 -1.26,-0.61 -1.75,-0.11c-0.4,0.4 -0.46,1.02 -0.13,1.48c1.97,2.74 1.96,6.41 -0.03,9.25c-0.32,0.45 -0.25,1.07 0.14,1.46l0.03,0.03c0.49,0.49 1.32,0.45 1.74,-0.1C23.69,11.49 23.69,6.65 20.93,3.01zM3.51,3.51c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l3.05,3.05C5.06,8.31 5,8.64 5,9c0,2.21 1.79,4 4,4c0.36,0 0.69,-0.06 1.02,-0.15l1.36,1.36C10.63,14.08 9.84,14 9,14c-2.53,0 -4.71,0.7 -6.39,1.56C1.61,16.07 1,17.1 1,18.22V20c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-0.17l2.07,2.07c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51z"/>
+ android:pathData="M15.72,6.41c-0.35,0.35 -0.44,0.88 -0.25,1.35 0.3,0.75 0.32,1.58 0.05,2.34 -0.16,0.46 -0.06,0.98 0.29,1.32 0.6,0.6 1.66,0.47 2.02,-0.31 0.64,-1.39 0.6,-2.99 -0.12,-4.41 -0.4,-0.75 -1.41,-0.88 -1.99,-0.29zM19.18,2.89c-0.4,0.4 -0.46,1.02 -0.13,1.48 1.93,2.68 1.95,6.25 0.09,9.07 -0.31,0.46 -0.23,1.08 0.16,1.47 0.51,0.51 1.38,0.46 1.81,-0.13 2.57,-3.51 2.52,-8.2 -0.17,-11.77 -0.43,-0.56 -1.26,-0.62 -1.76,-0.12zM9.43,5.04l3.53,3.53c-0.2,-1.86 -1.67,-3.33 -3.53,-3.53zM3.71,3.56c-0.39,0.39 -0.39,1.02 0,1.41l1.91,1.91c-0.56,0.89 -0.79,2.01 -0.47,3.2 0.36,1.33 1.44,2.4 2.77,2.77 1.19,0.33 2.31,0.09 3.2,-0.47l4.4,4.4C13.74,15.6 10.78,15 9,15c-2.67,0 -8,1.34 -8,4v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1c0,-0.37 -0.11,-0.7 -0.29,-1.02l2.31,2.31c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/voicemail.xml b/compose/material/material/icons/generator/raw-icons/rounded/voicemail.xml
index 2fe1257..4947802 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/voicemail.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/voicemail.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17.5,7C15.01,7 13,9.01 13,11.5c0,0.93 0.28,1.78 0.76,2.5h-3.52c0.48,-0.72 0.76,-1.57 0.76,-2.5C11,9.01 8.99,7 6.5,7S2,9.01 2,11.5S4.01,16 6.5,16h11c2.49,0 4.5,-2.01 4.5,-4.5S19.99,7 17.5,7zM4,11.5C4,10.12 5.12,9 6.5,9S9,10.12 9,11.5S7.88,14 6.5,14S4,12.88 4,11.5zM17.5,14c-1.38,0 -2.5,-1.12 -2.5,-2.5S16.12,9 17.5,9s2.5,1.12 2.5,2.5S18.88,14 17.5,14z"/>
+ android:pathData="M18.5,6C15.46,6 13,8.46 13,11.5c0,1.33 0.47,2.55 1.26,3.5L9.74,15c0.79,-0.95 1.26,-2.17 1.26,-3.5C11,8.46 8.54,6 5.5,6S0,8.46 0,11.5 2.46,17 5.5,17h13c3.04,0 5.5,-2.46 5.5,-5.5S21.54,6 18.5,6zM5.5,15C3.57,15 2,13.43 2,11.5S3.57,8 5.5,8 9,9.57 9,11.5 7.43,15 5.5,15zM18.5,15c-1.93,0 -3.5,-1.57 -3.5,-3.5S16.57,8 18.5,8 22,9.57 22,11.5 20.43,15 18.5,15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/volume_down.xml b/compose/material/material/icons/generator/raw-icons/rounded/volume_down.xml
index 3c6a4de..fb6c283 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/volume_down.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/volume_down.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05C17.48,15.29 18.5,13.77 18.5,12zM5,10v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L9,9H6C5.45,9 5,9.45 5,10z"/>
+ android:pathData="M18.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM5,10v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L9,9H6c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/volume_mute.xml b/compose/material/material/icons/generator/raw-icons/rounded/volume_mute.xml
index c589f93..46a00ff 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/volume_mute.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/volume_mute.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,10v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L11,9H8C7.45,9 7,9.45 7,10z"/>
+ android:pathData="M7,10v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L11,9H8c-0.55,0 -1,0.45 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/volume_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/volume_off.xml
index 2eb493d..7ff837d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/volume_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/volume_off.xml
@@ -7,14 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.25,13.42C16.4,12.97 16.5,12.5 16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v3.2L16.25,13.42z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,12c0,1.21 -0.31,2.34 -0.85,3.32l1.46,1.46C20.48,15.39 21,13.76 21,12c0,-3.83 -2.4,-7.11 -5.78,-8.4C14.63,3.37 14,3.83 14,4.46v0.19c0,0.38 0.25,0.71 0.61,0.85C17.18,6.54 19,9.06 19,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51L2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41L6.17,9H4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71v-2.76l3.32,3.32c-0.23,0.13 -0.47,0.24 -0.71,0.35c-0.37,0.16 -0.6,0.52 -0.6,0.91v0c0,0.7 0.7,1.2 1.35,0.94c0.5,-0.2 0.99,-0.45 1.44,-0.73l2.28,2.28c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,9.17V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L9.41,6.59L12,9.17z"/>
+ android:pathData="M3.63,3.63c-0.39,0.39 -0.39,1.02 0,1.41L7.29,8.7 7,9L4,9c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71v-4.17l4.18,4.18c-0.49,0.37 -1.02,0.68 -1.6,0.91 -0.36,0.15 -0.58,0.53 -0.58,0.92 0,0.72 0.73,1.18 1.39,0.91 0.8,-0.33 1.55,-0.77 2.22,-1.31l1.34,1.34c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.05,3.63c-0.39,-0.39 -1.02,-0.39 -1.42,0zM19,12c0,0.82 -0.15,1.61 -0.41,2.34l1.53,1.53c0.56,-1.17 0.88,-2.48 0.88,-3.87 0,-3.83 -2.4,-7.11 -5.78,-8.4 -0.59,-0.23 -1.22,0.23 -1.22,0.86v0.19c0,0.38 0.25,0.71 0.61,0.85C17.18,6.54 19,9.06 19,12zM10.29,5.71l-0.17,0.17L12,7.76L12,6.41c0,-0.89 -1.08,-1.33 -1.71,-0.7zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v1.79l2.48,2.48c0.01,-0.08 0.02,-0.16 0.02,-0.24z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/volume_up.xml b/compose/material/material/icons/generator/raw-icons/rounded/volume_up.xml
index 8f11585..61f5856 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/volume_up.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/volume_up.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,10v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71V6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L7,9H4C3.45,9 3,9.45 3,10zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05C15.48,15.29 16.5,13.77 16.5,12zM14,4.45v0.2c0,0.38 0.25,0.71 0.6,0.85C17.18,6.53 19,9.06 19,12s-1.82,5.47 -4.4,6.5c-0.36,0.14 -0.6,0.47 -0.6,0.85v0.2c0,0.63 0.63,1.07 1.21,0.85C18.6,19.11 21,15.84 21,12s-2.4,-7.11 -5.79,-8.4C14.63,3.37 14,3.82 14,4.45z"/>
+ android:pathData="M3,10v4c0,0.55 0.45,1 1,1h3l3.29,3.29c0.63,0.63 1.71,0.18 1.71,-0.71L12,6.41c0,-0.89 -1.08,-1.34 -1.71,-0.71L7,9L4,9c-0.55,0 -1,0.45 -1,1zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,4.45v0.2c0,0.38 0.25,0.71 0.6,0.85C17.18,6.53 19,9.06 19,12s-1.82,5.47 -4.4,6.5c-0.36,0.14 -0.6,0.47 -0.6,0.85v0.2c0,0.63 0.63,1.07 1.21,0.85C18.6,19.11 21,15.84 21,12s-2.4,-7.11 -5.79,-8.4c-0.58,-0.23 -1.21,0.22 -1.21,0.85z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/vpn_key.xml b/compose/material/material/icons/generator/raw-icons/rounded/vpn_key.xml
index 0787f85..7c52a71 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/vpn_key.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/vpn_key.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12.65,10C11.7,7.31 8.9,5.5 5.77,6.12C3.48,6.58 1.62,8.41 1.14,10.7C0.32,14.57 3.26,18 7,18c2.61,0 4.83,-1.67 5.65,-4H17v2c0,1.1 0.9,2 2,2l0,0c1.1,0 2,-0.9 2,-2v-2l0,0c1.1,0 2,-0.9 2,-2l0,0c0,-1.1 -0.9,-2 -2,-2H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S8.1,14 7,14z"/>
+ android:pathData="M12.65,10C11.7,7.31 8.9,5.5 5.77,6.12c-2.29,0.46 -4.15,2.29 -4.63,4.58C0.32,14.57 3.26,18 7,18c2.61,0 4.83,-1.67 5.65,-4H17v2c0,1.1 0.9,2 2,2s2,-0.9 2,-2v-2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-8.35zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wallpaper.xml b/compose/material/material/icons/generator/raw-icons/rounded/wallpaper.xml
index bcfcd3d..07ff9cd 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wallpaper.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wallpaper.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,5h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C3.9,3 3,3.9 3,5v5c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,8.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,3h-5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h5v5c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V5C21,3.9 20.1,3 19,3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,13L4,13c-0.55,0 -1,0.45 -1,1v5c0,1.1 0.9,2 2,2h5c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5v-5C5,13.45 4.55,13 4,13z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,19h-5c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h5c1.1,0 2,-0.9 2,-2v-5c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1V19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8.6,13.53l-2,2.67C6.35,16.53 6.59,17 7,17h10c0.41,0 0.65,-0.47 0.4,-0.8l-2.75,-3.67c-0.2,-0.27 -0.6,-0.27 -0.8,0L11.25,16L9.4,13.53C9.2,13.27 8.8,13.27 8.6,13.53z"/>
+ android:pathData="M4,5c0,-0.55 0.45,-1 1,-1h5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,2c-1.1,0 -2,0.9 -2,2v6c0,0.55 0.45,1 1,1s1,-0.45 1,-1L4,5zM9.61,13.49l-2.96,3.7c-0.26,0.33 -0.03,0.81 0.39,0.81L17,18c0.41,0 0.65,-0.47 0.4,-0.8l-2,-2.67c-0.2,-0.27 -0.6,-0.27 -0.8,0l-1.63,2.18 -2.58,-3.22c-0.2,-0.25 -0.58,-0.25 -0.78,0zM17,8.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S14,7.67 14,8.5s0.67,1.5 1.5,1.5S17,9.33 17,8.5zM20,2h-6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h5c0.55,0 1,0.45 1,1v5c0,0.55 0.45,1 1,1s1,-0.45 1,-1L22,4c0,-1.1 -0.9,-2 -2,-2zM20,19c0,0.55 -0.45,1 -1,1h-5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h6c1.1,0 2,-0.9 2,-2v-6c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v5zM3,13c-0.55,0 -1,0.45 -1,1v6c0,1.1 0.9,2 2,2h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,20c-0.55,0 -1,-0.45 -1,-1v-5c0,-0.55 -0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/warning.xml b/compose/material/material/icons/generator/raw-icons/rounded/warning.xml
index 29a1243..506d058 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/warning.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/warning.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M2.73,21h18.53c0.77,0 1.25,-0.83 0.87,-1.5l-9.27,-16c-0.39,-0.67 -1.35,-0.67 -1.73,0l-9.27,16C1.48,20.17 1.96,21 2.73,21zM12,15c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3C13,14.55 12.55,15 12,15zM13,17c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1s0.45,-1 1,-1S13,16.45 13,17z"/>
+ android:pathData="M4.47,21h15.06c1.54,0 2.5,-1.67 1.73,-3L13.73,4.99c-0.77,-1.33 -2.69,-1.33 -3.46,0L2.74,18c-0.77,1.33 0.19,3 1.73,3zM12,14c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM13,18h-2v-2h2v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/warning_amber.xml b/compose/material/material/icons/generator/raw-icons/rounded/warning_amber.xml
index 0b27082..3a5a1ac 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/warning_amber.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/warning_amber.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.53,5l7.53,13.01H4L11.53,5M2.27,17.01c-0.77,1.33 0.19,3 1.73,3h15.06c1.54,0 2.5,-1.67 1.73,-3L13.26,4c-0.77,-1.33 -2.69,-1.33 -3.46,0L2.27,17.01z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10.53,10.01V13c0,0.55 0.45,1 1,1l0,0c0.55,0 1,-0.45 1,-1v-2.99c0,-0.55 -0.45,-1 -1,-1l0,0C10.98,9.01 10.53,9.46 10.53,10.01z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M11.53,16.01m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
+ android:pathData="M12,5.99L19.53,19L4.47,19L12,5.99M2.74,18c-0.77,1.33 0.19,3 1.73,3h15.06c1.54,0 2.5,-1.67 1.73,-3L13.73,4.99c-0.77,-1.33 -2.69,-1.33 -3.46,0L2.74,18zM11,11v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM11,16h2v2h-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/watch.xml b/compose/material/material/icons/generator/raw-icons/rounded/watch.xml
index 52d6de0..1fbd491 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/watch.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/watch.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M16.36,6.53l-0.93,-3.1C15.17,2.58 14.4,2 13.51,2h-3.02C9.6,2 8.83,2.58 8.57,3.43l-0.93,3.1C6.03,7.81 5,9.78 5,12s1.03,4.19 2.64,5.47l0.93,3.1C8.83,21.42 9.6,22 10.49,22h3.02c0.88,0 1.66,-0.58 1.92,-1.43l0.93,-3.1C17.97,16.19 19,14.22 19,12S17.97,7.81 16.36,6.53zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5s5,2.24 5,5S14.76,17 12,17z"/>
+ android:pathData="M20,12c0,-2.54 -1.19,-4.81 -3.04,-6.27l-0.68,-4.06C16.12,0.71 15.28,0 14.31,0H9.7c-0.98,0 -1.82,0.71 -1.98,1.67l-0.67,4.06C5.19,7.19 4,9.45 4,12s1.19,4.81 3.05,6.27l0.67,4.06c0.16,0.96 1,1.67 1.98,1.67h4.61c0.98,0 1.81,-0.71 1.97,-1.67l0.68,-4.06C18.81,16.81 20,14.54 20,12zM6,12c0,-3.31 2.69,-6 6,-6s6,2.69 6,6 -2.69,6 -6,6 -6,-2.69 -6,-6z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/watch_later.xml b/compose/material/material/icons/generator/raw-icons/rounded/watch_later.xml
index b82761b..96b73db 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/watch_later.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/watch_later.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM16,16c-0.39,0.39 -1.02,0.39 -1.41,0l-3.29,-3.29C11.11,12.52 11,12.27 11,12V8c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v3.59l3,3C16.39,14.98 16.39,15.61 16,16z"/>
+ android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM15.55,15.8l-4.08,-2.51c-0.3,-0.18 -0.48,-0.5 -0.48,-0.85V7.75C11,7.34 11.34,7 11.75,7s0.75,0.34 0.75,0.75v4.45l3.84,2.31c0.36,0.22 0.48,0.69 0.26,1.05C16.38,15.91 15.91,16.02 15.55,15.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/water_drop.xml b/compose/material/material/icons/generator/raw-icons/rounded/water_drop.xml
new file mode 100644
index 0000000..4411f51
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/water_drop.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.66,2.58c-0.38,-0.33 -0.95,-0.33 -1.33,0C6.45,6.88 4,10.62 4,13.8c0,4.98 3.8,8.2 8,8.2s8,-3.22 8,-8.2C20,10.62 17.55,6.88 12.66,2.58zM7.83,14c0.37,0 0.67,0.26 0.74,0.62c0.41,2.22 2.28,2.98 3.64,2.87c0.43,-0.02 0.79,0.32 0.79,0.75c0,0.4 -0.32,0.73 -0.72,0.75c-2.13,0.13 -4.62,-1.09 -5.19,-4.12C7.01,14.42 7.37,14 7.83,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/waves.xml b/compose/material/material/icons/generator/raw-icons/rounded/waves.xml
index e4ae0eb..b08f182 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/waves.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/waves.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M17,16.99c-2.55,0 -3.11,1.4 -5,1.4c-1.95,0 -2.41,-1.4 -5,-1.4c-2.21,0 -2.9,1.03 -4.26,1.32C2.32,18.4 2,18.75 2,19.18v0.2c0,0.56 0.51,0.96 1.06,0.86c1.69,-0.31 2.34,-1.31 3.94,-1.31c1.96,0 2.4,1.4 5,1.4c2.59,0 3.09,-1.4 5,-1.4c1.67,0 2.25,1.03 4.01,1.32c0.52,0.09 0.99,-0.35 0.99,-0.87v-0.21c0,-0.43 -0.32,-0.78 -0.74,-0.87C19.88,18.03 19.22,16.99 17,16.99zM17,12.54c-2.49,0 -3.16,1.4 -5,1.4c-1.95,0 -2.41,-1.4 -5,-1.4c-2.18,0 -2.92,1.04 -4.28,1.33C2.31,13.95 2,14.3 2,14.73v0.21c0,0.56 0.52,0.97 1.07,0.86c1.68,-0.31 2.32,-1.31 3.93,-1.31c1.95,0 2.41,1.4 5,1.4c2.56,0 3.06,-1.4 5,-1.4c1.67,0 2.25,1.03 4.01,1.32C21.53,15.9 22,15.47 22,14.94v-0.21c0,-0.43 -0.32,-0.78 -0.74,-0.87C19.88,13.58 19.22,12.54 17,12.54zM17,3.66c-2.54,0 -3.13,1.4 -5,1.4c-1.94,0 -2.44,-1.4 -5,-1.4c-2.21,0 -2.9,1.03 -4.26,1.32C2.32,5.07 2,5.42 2,5.85v0.18C2,6.59 2.52,7 3.07,6.9C4.74,6.58 5.43,5.59 7,5.59c1.96,0 2.4,1.4 5,1.4c2.55,0 3.12,-1.4 5,-1.4c1.67,0 2.25,1.03 4.01,1.32C21.53,7 22,6.57 22,6.04v-0.2c0,-0.43 -0.32,-0.78 -0.75,-0.87C19.86,4.68 19.2,3.66 17,3.66zM17,8.09c-2.54,0 -3.08,1.4 -5,1.4c-1.95,0 -2.41,-1.4 -5,-1.4c-2.2,0 -2.88,1.03 -4.26,1.32C2.32,9.5 2,9.85 2,10.28v0.2c0,0.56 0.52,0.97 1.07,0.86c1.67,-0.32 2.39,-1.3 3.93,-1.3c1.94,0 2.41,1.4 5,1.4c2.55,0 3.12,-1.4 5,-1.4c1.67,0 2.25,1.03 4.01,1.32c0.52,0.09 0.99,-0.35 0.99,-0.87v-0.21c0,-0.43 -0.32,-0.78 -0.74,-0.87C19.88,9.13 19.22,8.09 17,8.09z"/>
+ android:pathData="M17,16.99c-1.35,0 -2.2,0.42 -2.95,0.8 -0.65,0.33 -1.18,0.6 -2.05,0.6 -0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.38 -1.57,-0.8 -2.95,-0.8s-2.2,0.42 -2.95,0.8c-0.43,0.22 -0.81,0.41 -1.27,0.52 -0.45,0.1 -0.78,0.46 -0.78,0.91v0.1c0,0.6 0.56,1.03 1.14,0.91 0.74,-0.15 1.3,-0.43 1.81,-0.69 0.65,-0.33 1.17,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.42 2.95,-0.8c0.65,-0.33 1.18,-0.6 2.05,-0.6 0.9,0 1.4,0.25 2.05,0.6 0.52,0.26 1.08,0.55 1.83,0.7 0.58,0.11 1.12,-0.33 1.12,-0.91v-0.09c0,-0.46 -0.34,-0.82 -0.79,-0.92 -0.46,-0.1 -0.83,-0.29 -1.26,-0.52 -0.75,-0.39 -1.6,-0.81 -2.95,-0.81zM17,12.54c-1.35,0 -2.2,0.43 -2.95,0.8 -0.65,0.32 -1.18,0.6 -2.05,0.6 -0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.38 -1.57,-0.8 -2.95,-0.8s-2.2,0.43 -2.95,0.8c-0.43,0.21 -0.81,0.41 -1.28,0.52 -0.44,0.1 -0.77,0.46 -0.77,0.91v0.1c0,0.59 0.54,1.03 1.12,0.91 0.75,-0.15 1.31,-0.44 1.83,-0.69 0.65,-0.35 1.15,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.43 2.95,-0.8c0.65,-0.35 1.15,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.52,0.26 1.08,0.55 1.83,0.7 0.58,0.11 1.12,-0.33 1.12,-0.92v-0.09c0,-0.46 -0.34,-0.82 -0.79,-0.92 -0.46,-0.1 -0.83,-0.29 -1.26,-0.52 -0.75,-0.38 -1.6,-0.8 -2.95,-0.8zM19.95,4.46c-0.75,-0.38 -1.58,-0.8 -2.95,-0.8s-2.2,0.42 -2.95,0.8c-0.65,0.32 -1.18,0.6 -2.05,0.6 -0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.37 -1.57,-0.8 -2.95,-0.8s-2.2,0.42 -2.95,0.8c-0.43,0.22 -0.81,0.41 -1.27,0.52 -0.45,0.1 -0.78,0.46 -0.78,0.91v0.07c0,0.6 0.54,1.04 1.12,0.92 0.75,-0.15 1.31,-0.44 1.83,-0.69 0.65,-0.33 1.17,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.43 2.95,-0.8c0.65,-0.32 1.18,-0.6 2.05,-0.6 0.9,0 1.4,0.25 2.05,0.6 0.52,0.26 1.08,0.55 1.83,0.7 0.58,0.11 1.12,-0.33 1.12,-0.92v-0.09c0,-0.46 -0.34,-0.82 -0.79,-0.92 -0.46,-0.1 -0.83,-0.28 -1.26,-0.5zM17,8.09c-1.35,0 -2.2,0.43 -2.95,0.8 -0.65,0.35 -1.15,0.6 -2.05,0.6s-1.4,-0.25 -2.05,-0.6c-0.75,-0.38 -1.57,-0.8 -2.95,-0.8s-2.2,0.43 -2.95,0.8c-0.43,0.23 -0.8,0.42 -1.26,0.52 -0.45,0.1 -0.79,0.46 -0.79,0.92v0.09c0,0.59 0.54,1.03 1.12,0.91 0.75,-0.15 1.31,-0.44 1.83,-0.69 0.65,-0.32 1.18,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.43 2.95,-0.8c0.65,-0.32 1.18,-0.6 2.05,-0.6 0.9,0 1.4,0.25 2.05,0.6 0.52,0.26 1.08,0.55 1.83,0.7 0.58,0.11 1.12,-0.33 1.12,-0.91v-0.09c0,-0.46 -0.34,-0.82 -0.79,-0.92 -0.46,-0.1 -0.83,-0.29 -1.26,-0.52 -0.75,-0.39 -1.6,-0.81 -2.95,-0.81z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/waving_hand.xml b/compose/material/material/icons/generator/raw-icons/rounded/waving_hand.xml
new file mode 100644
index 0000000..b9363c2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/waving_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.07,9.8c-0.2,0.2 -0.2,0.51 0,0.71l0,0c1.07,1.07 1.16,2.75 0.28,3.92c-0.15,0.2 -0.12,0.47 0.05,0.65c0.22,0.22 0.57,0.19 0.76,-0.05c1.07,-1.43 1.06,-3.43 -0.04,-4.85l7.62,-7.62c0.49,-0.49 1.28,-0.49 1.77,0s0.49,1.28 0,1.77l-5.13,5.13c-0.2,0.2 -0.2,0.51 0,0.71s0.51,0.2 0.71,0l6.54,-6.54c0.49,-0.49 1.28,-0.49 1.77,0s0.49,1.28 0,1.77l-6.54,6.54c-0.2,0.2 -0.2,0.51 0,0.71s0.51,0.2 0.71,0l5.48,-5.48c0.49,-0.49 1.28,-0.49 1.77,0s0.49,1.28 0,1.77l-6.19,6.19c-0.2,0.2 -0.2,0.51 0,0.71c0.2,0.2 0.51,0.2 0.71,0l4.07,-4.07c0.49,-0.49 1.28,-0.49 1.77,0c0.49,0.49 0.49,1.28 0,1.77l-7.07,7.07c-3.22,3.22 -8.45,3.22 -11.67,0s-3.22,-8.45 0,-11.67l4.6,-4.6c0.49,-0.49 1.28,-0.49 1.77,0c0.49,0.49 0.49,1.28 0,1.77L6.07,9.8zM7,1.8c0,-0.41 -0.34,-0.75 -0.75,-0.75c-0.04,0 -0.07,0 -0.11,0.01c-2.63,0.38 -4.7,2.46 -5.08,5.08c0,0.03 -0.01,0.07 -0.01,0.11C1.05,6.66 1.39,7 1.8,7c0.38,0 0.69,-0.28 0.74,-0.64c0.28,-1.97 1.84,-3.53 3.81,-3.81C6.72,2.49 7,2.18 7,1.8zM17,22.2c0,0.41 0.34,0.75 0.75,0.75c0.04,0 0.07,0 0.11,-0.01c2.63,-0.38 4.7,-2.46 5.08,-5.08c0,-0.03 0.01,-0.07 0.01,-0.11c0,-0.41 -0.34,-0.75 -0.75,-0.75c-0.38,0 -0.69,0.28 -0.74,0.64c-0.28,1.97 -1.84,3.53 -3.81,3.81C17.28,21.51 17,21.82 17,22.2z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wb_auto.xml b/compose/material/material/icons/generator/raw-icons/rounded/wb_auto.xml
index 3aa85f2..dff90b8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wb_auto.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wb_auto.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8.14,9.3l-1.01,2.89l2.09,0l-1.02,-2.89z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22.42,8L22.42,8c-0.27,0 -0.51,0.19 -0.57,0.45l-1.1,4.65h-0.06l-1.33,-4.57C19.27,8.22 18.98,8 18.65,8c-0.32,0 -0.61,0.21 -0.7,0.52l-1.4,4.59H16.5l-1.1,-4.66C15.34,8.19 15.1,8 14.83,8c-0.32,0 -0.55,0.26 -0.57,0.55C13.06,6.43 10.79,5 8.17,5c-3.87,0 -7,3.13 -7,7s3.13,7 7,7c3.83,0 6.93,-3.08 6.99,-6.89l0.62,2.33c0.09,0.33 0.38,0.56 0.72,0.56c0.33,0 0.62,-0.22 0.72,-0.54l1.4,-4.7h0.06l1.32,4.69C20.1,14.78 20.39,15 20.73,15h0.02c0.34,0 0.64,-0.23 0.72,-0.56l1.51,-5.71C23.08,8.36 22.8,8 22.42,8zM10.62,15c-0.24,0 -0.45,-0.15 -0.53,-0.38l-0.49,-1.41H6.77l-0.5,1.42C6.18,14.85 5.97,15 5.73,15h0c-0.39,0 -0.67,-0.39 -0.53,-0.76l2.12,-5.65C7.46,8.23 7.8,8 8.17,8s0.71,0.23 0.85,0.59l2.12,5.65C11.28,14.61 11.01,15 10.62,15z"/>
+ android:pathData="M6.85,12.65h2.3L8,9zM22.72,7c-0.42,0 -0.77,0.3 -0.85,0.7l-1.07,5.59 -1.31,-5.51c-0.11,-0.46 -0.52,-0.78 -0.99,-0.78s-0.88,0.32 -0.98,0.78l-1.31,5.51 -1.07,-5.59c-0.08,-0.4 -0.44,-0.7 -0.85,-0.7 -0.01,0 -0.03,0.01 -0.04,0.01C12.78,5.18 10.53,4 8,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8c3.17,0 5.9,-1.85 7.2,-4.52 0.2,0.32 0.55,0.52 0.94,0.52 0.51,0 0.95,-0.35 1.07,-0.84L18.5,9.9l1.29,5.26c0.12,0.49 0.57,0.84 1.07,0.84 0.52,0 0.96,-0.36 1.08,-0.86l1.61,-7.08c0.13,-0.54 -0.28,-1.06 -0.83,-1.06zM10.93,16c-0.38,0 -0.72,-0.24 -0.84,-0.6L9.6,14L6.4,14l-0.49,1.4c-0.13,0.36 -0.46,0.6 -0.84,0.6 -0.62,0 -1.05,-0.61 -0.84,-1.19l2.44,-6.86C6.87,7.38 7.4,7 8,7s1.13,0.38 1.34,0.94l2.44,6.86c0.2,0.59 -0.23,1.2 -0.85,1.2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wb_cloudy.xml b/compose/material/material/icons/generator/raw-icons/rounded/wb_cloudy.xml
index fc838b5..d77abd6 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wb_cloudy.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wb_cloudy.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M19,11c0,-3.87 -3.13,-7 -7,-7C8.78,4 6.07,6.18 5.26,9.15C2.82,9.71 1,11.89 1,14.5C1,17.54 3.46,20 6.5,20c1.76,0 10.25,0 12,0l0,0c2.49,-0.01 4.5,-2.03 4.5,-4.52C23,13.15 21.25,11.26 19,11z"/>
+ android:pathData="M19.37,10.04C18.68,6.59 15.65,4 12.01,4c-2.89,0 -5.4,1.64 -6.65,4.04C2.35,8.36 0.01,10.91 0.01,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.64,-4.96z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wb_incandescent.xml b/compose/material/material/icons/generator/raw-icons/rounded/wb_incandescent.xml
index 0d9a3ee..b0155c7 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wb_incandescent.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wb_incandescent.xml
@@ -6,20 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,19L12,19c-0.56,0 -1,0.45 -1,1V21c0,0.55 0.45,1 1,1H12c0.55,0 1,-0.45 1,-1V20C13,19.45 12.55,19 12,19z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5.99,17.09L5.28,17.8c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41C7.02,16.71 6.38,16.71 5.99,17.09z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5,12c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1V12c0,0.55 0.45,1 1,1H4C4.55,13 5,12.55 5,12L5,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M21,11H20c-0.55,0 -1,0.45 -1,1V12c0,0.55 0.45,1 1,1H21c0.55,0 1,-0.45 1,-1V12C22,11.45 21.55,11 21,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.01,17.09c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l0.71,0.71c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L18.01,17.09z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,8.02V5c0,-1.1 -0.9,-2 -2,-2h-2C9.9,3 9,3.9 9,5v3.02c-1.43,1.08 -2.28,2.9 -1.91,4.91c0.36,1.95 1.9,3.55 3.84,3.95C14.16,17.56 17,15.11 17,12C17,10.37 16.21,8.94 15,8.02zM13,7.1C12.68,7.04 12.34,7 12,7s-0.68,0.04 -1,0.1V5h2V7.1z"/>
+ android:pathData="M4.25,19.79c0.39,0.39 1.02,0.39 1.41,0l0.39,-0.39c0.39,-0.39 0.38,-1.02 0,-1.4l-0.01,-0.01c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.39,0.39c-0.38,0.4 -0.38,1.02 0.01,1.41zM11.99,23L12,23c0.55,0 0.99,-0.44 0.99,-0.99v-0.96c0,-0.55 -0.44,-0.99 -0.99,-0.99h-0.01c-0.55,0 -0.99,0.44 -0.99,0.99v0.96c0,0.55 0.44,0.99 0.99,0.99zM3.01,11.05L1.99,11.05c-0.55,0 -0.99,0.44 -0.99,0.99v0.01c0,0.55 0.44,0.99 0.99,0.99L3,13.04c0.55,0 0.99,-0.44 0.99,-0.99v-0.01c0.01,-0.55 -0.43,-0.99 -0.98,-0.99zM15,6.86L15,3.05c0,-0.55 -0.45,-1 -1,-1h-4c-0.55,0 -1,0.45 -1,1v3.81c-2.04,1.18 -3.32,3.52 -2.93,6.13 0.4,2.61 2.56,4.7 5.18,5.02 3.64,0.44 6.75,-2.4 6.75,-5.95 0,-2.23 -1.21,-4.16 -3,-5.2zM20,12.04v0.01c0,0.55 0.44,0.99 0.99,0.99L22,13.04c0.55,0 0.99,-0.44 0.99,-0.99v-0.01c0,-0.55 -0.44,-0.99 -0.99,-0.99h-1.01c-0.55,0 -0.99,0.44 -0.99,0.99zM17.94,19.41l0.39,0.39c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41l-0.39,-0.39c-0.39,-0.39 -1.02,-0.38 -1.4,0 -0.4,0.4 -0.4,1.02 -0.01,1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wb_iridescent.xml b/compose/material/material/icons/generator/raw-icons/rounded/wb_iridescent.xml
index 2f4a536..031d905 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wb_iridescent.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wb_iridescent.xml
@@ -6,23 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,15h10c1.1,0 2,-0.9 2,-2v-2c0,-1.1 -0.9,-2 -2,-2H7c-1.1,0 -2,0.9 -2,2v2C5,14.1 5.9,15 7,15z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2L12,2c-0.56,0 -1,0.45 -1,1V4c0,0.55 0.45,1 1,1H12c0.55,0 1,-0.45 1,-1V3C13,2.45 12.55,2 12,2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.79,5.3L19.79,5.3c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.38,0.38c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0l0.38,-0.38C20.18,6.33 20.18,5.69 19.79,5.3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,22L12,22c0.56,0 1,-0.45 1,-1V20c0,-0.55 -0.45,-1 -1,-1H12c-0.55,0 -1,0.45 -1,1V21C11,21.55 11.45,22 12,22z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.99,18.41l0.38,0.39c0.39,0.39 1.02,0.39 1.41,0l0.01,-0.01c0.39,-0.39 0.39,-1.02 0,-1.41L19.4,17c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C17.6,17.4 17.6,18.03 17.99,18.41z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,5.69L5.61,5.31c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L4.59,7.1c0.39,0.39 1.02,0.39 1.41,0l0,0C6.38,6.71 6.38,6.07 6,5.69z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4.2,18.79L4.2,18.79c0.39,0.4 1.03,0.4 1.42,0L6,18.4c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L4.2,17.38C3.81,17.77 3.81,18.4 4.2,18.79z"/>
+ android:pathData="M6,15h12c0.55,0 1,-0.45 1,-1v-3.95c0,-0.55 -0.45,-1 -1,-1L6,9.05c-0.55,0 -1,0.45 -1,1L5,14c0,0.55 0.45,1 1,1zM11,2v1.05c0,0.55 0.45,0.95 1,0.95s1,-0.4 1,-0.95L13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1zM18.34,4.3l-0.38,0.38c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l0.38,-0.38c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0zM13,22v-0.96c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1L11,22c0,0.55 0.45,1 1,1s1,-0.45 1,-1zM19.74,18.39l-0.39,-0.39c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l0.38,0.39c0.39,0.39 1.02,0.39 1.41,0l0.01,-0.01c0.39,-0.38 0.39,-1.02 0,-1.4zM4.25,5.71l0.39,0.39c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41l-0.39,-0.39c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.38,0.39 -0.38,1.03 0,1.41zM5.67,19.79l0.38,-0.38c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0l-0.38,0.38c-0.39,0.39 -0.39,1.02 0,1.41 0.38,0.39 1.02,0.39 1.41,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wb_sunny.xml b/compose/material/material/icons/generator/raw-icons/rounded/wb_sunny.xml
index c6bb075..558f9ba 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wb_sunny.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wb_sunny.xml
@@ -6,29 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,1L12,1c-0.55,0 -1,0.45 -1,1v1c0,0.55 0.45,1 1,1h0c0.55,0 1,-0.45 1,-1V2C13,1.45 12.55,1 12,1z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,23L12,23c0.55,0 1,-0.45 1,-1v-1c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v1C11,22.55 11.45,23 12,23z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,12L20,12c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1h-1C20.45,11 20,11.45 20,12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,11H2c-0.55,0 -1,0.45 -1,1v0c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v0C4,11.45 3.55,11 3,11z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.78,4.22L19.78,4.22c-0.39,-0.39 -1.02,-0.39 -1.41,0L18,4.59C17.61,4.98 17.61,5.61 18,6l0,0c0.39,0.39 1.02,0.39 1.41,0l0.36,-0.36C20.17,5.25 20.17,4.61 19.78,4.22z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4.22,19.78L4.22,19.78c0.39,0.39 1.02,0.39 1.41,0L6,19.41c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.36,0.36C3.83,18.75 3.83,19.39 4.22,19.78z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,19.41l0.36,0.36c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L19.41,18c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0C17.61,18.39 17.61,19.02 18,19.41z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M6,4.59L5.64,4.22c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L4.59,6C4.98,6.39 5.61,6.39 6,6l0,0C6.39,5.61 6.39,4.98 6,4.59z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,12m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
+ android:pathData="M6.05,4.14l-0.39,-0.39c-0.39,-0.39 -1.02,-0.38 -1.4,0l-0.01,0.01c-0.39,0.39 -0.39,1.02 0,1.4l0.39,0.39c0.39,0.39 1.01,0.39 1.4,0l0.01,-0.01c0.39,-0.38 0.39,-1.02 0,-1.4zM3.01,10.5L1.99,10.5c-0.55,0 -0.99,0.44 -0.99,0.99v0.01c0,0.55 0.44,0.99 0.99,0.99L3,12.49c0.56,0.01 1,-0.43 1,-0.98v-0.01c0,-0.56 -0.44,-1 -0.99,-1zM12.01,0.55L12,0.55c-0.56,0 -1,0.44 -1,0.99v0.96c0,0.55 0.44,0.99 0.99,0.99L12,3.49c0.56,0.01 1,-0.43 1,-0.98v-0.97c0,-0.55 -0.44,-0.99 -0.99,-0.99zM19.75,3.76c-0.39,-0.39 -1.02,-0.39 -1.41,-0.01l-0.39,0.39c-0.39,0.39 -0.39,1.02 0,1.4l0.01,0.01c0.39,0.39 1.02,0.39 1.4,0l0.39,-0.39c0.39,-0.39 0.39,-1.01 0,-1.4zM17.94,18.86l0.39,0.39c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41l-0.39,-0.39c-0.39,-0.39 -1.02,-0.38 -1.4,0 -0.4,0.4 -0.4,1.02 -0.01,1.41zM20,11.49v0.01c0,0.55 0.44,0.99 0.99,0.99L22,12.49c0.55,0 0.99,-0.44 0.99,-0.99v-0.01c0,-0.55 -0.44,-0.99 -0.99,-0.99h-1.01c-0.55,0 -0.99,0.44 -0.99,0.99zM12,5.5c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6zM11.99,22.45L12,22.45c0.55,0 0.99,-0.44 0.99,-0.99v-0.96c0,-0.55 -0.44,-0.99 -0.99,-0.99h-0.01c-0.55,0 -0.99,0.44 -0.99,0.99v0.96c0,0.55 0.44,0.99 0.99,0.99zM4.25,19.24c0.39,0.39 1.02,0.39 1.41,0l0.39,-0.39c0.39,-0.39 0.38,-1.02 0,-1.4l-0.01,-0.01c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.39,0.39c-0.38,0.4 -0.38,1.02 0.01,1.41z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wc.xml b/compose/material/material/icons/generator/raw-icons/rounded/wc.xml
index d9aa0a9..ba98da1 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wc.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wc.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5.49,21v-6.5h-0.5c-0.55,0 -1,-0.45 -1,-1V9c0,-1.1 0.9,-2 2,-2h3c1.1,0 2,0.9 2,2v4.5c0,0.55 -0.45,1 -1,1h-0.5V21c0,0.55 -0.45,1 -1,1h-2C5.94,22 5.49,21.55 5.49,21zM17.99,21v-5h1.61c0.68,0 1.16,-0.67 0.95,-1.32l-2.1,-6.31C18.17,7.55 17.41,7 16.55,7h-0.12c-0.86,0 -1.63,0.55 -1.9,1.37l-2.1,6.31C12.21,15.33 12.69,16 13.38,16h1.61v5c0,0.55 0.45,1 1,1h1C17.54,22 17.99,21.55 17.99,21zM7.49,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2s-2,0.89 -2,2S6.38,6 7.49,6zM16.49,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2s-2,0.89 -2,2S15.38,6 16.49,6z"/>
+ android:pathData="M5.5,21v-6.5L5,14.5c-0.55,0 -1,-0.45 -1,-1L4,9c0,-1.1 0.9,-2 2,-2h3c1.1,0 2,0.9 2,2v4.5c0,0.55 -0.45,1 -1,1h-0.5L9.5,21c0,0.55 -0.45,1 -1,1h-2c-0.55,0 -1,-0.45 -1,-1zM18,21v-5h1.61c0.68,0 1.16,-0.67 0.95,-1.32l-2.1,-6.31C18.18,7.55 17.42,7 16.56,7h-0.12c-0.86,0 -1.63,0.55 -1.9,1.37l-2.1,6.31c-0.22,0.65 0.26,1.32 0.95,1.32L15,16v5c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1zM7.5,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2 -2,0.89 -2,2 0.89,2 2,2zM16.5,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2 -2,0.89 -2,2 0.89,2 2,2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/web.xml b/compose/material/material/icons/generator/raw-icons/rounded/web.xml
index 6c22821..7e38b59 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/web.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/web.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM4,9h10.5v3.5H4V9zM4,14.5h10.5V18H4V14.5zM20,18h-3.5V9H20V18z"/>
+ android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM4,9h10.5v3.5L4,12.5L4,9zM4,14.5h10.5L14.5,18L5,18c-0.55,0 -1,-0.45 -1,-1v-2.5zM19,18h-2.5L16.5,9L20,9v8c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/web_asset.xml b/compose/material/material/icons/generator/raw-icons/rounded/web_asset.xml
index bea348b..7e0637d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/web_asset.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/web_asset.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,4H4C2.89,4 2,4.9 2,6v12c0,1.1 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.11,4 20,4zM20,18H4V8h16V18z"/>
+ android:pathData="M19,4L5,4c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.89,-2 -2,-2zM18,18L6,18c-0.55,0 -1,-0.45 -1,-1L5,8h14v9c0,0.55 -0.45,1 -1,1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/weekend.xml b/compose/material/material/icons/generator/raw-icons/rounded/weekend.xml
index 70055a7..12888f9 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/weekend.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/weekend.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,10c-1.1,0 -2,0.9 -2,2v4H5v-4c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v5c0,1.65 1.35,3 3,3h16c1.65,0 3,-1.35 3,-3v-5C23,10.9 22.1,10 21,10zM7,12v2h10v-2c0,-1.86 1.28,-3.41 3,-3.86V7c0,-1.65 -1.35,-3 -3,-3H7C5.35,4 4,5.35 4,7v1.14C5.72,8.59 7,10.14 7,12z"/>
+ android:pathData="M21,10c-1.1,0 -2,0.9 -2,2v3L5,15v-3c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v5c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2v-5c0,-1.1 -0.9,-2 -2,-2zM18,5L6,5c-1.1,0 -2,0.9 -2,2v2.15c1.16,0.41 2,1.51 2,2.82L6,14h12v-2.03c0,-1.3 0.84,-2.4 2,-2.82L20,7c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/whatshot.xml b/compose/material/material/icons/generator/raw-icons/rounded/whatshot.xml
index 5d3d0de..32e5c98 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/whatshot.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/whatshot.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10.46,2.12c-4.06,0.61 -7.4,3.77 -8.24,7.8c-0.47,2.26 -0.15,4.41 0.7,6.26l4.37,-4.37c0.37,-0.37 0.95,-0.39 1.35,-0.06l2.3,1.92l3.35,-3.35l-0.59,-0.59C13.08,9.08 13.52,8 14.41,8H17c0.55,0 1,0.45 1,1v2.59c0,0.89 -1.08,1.34 -1.71,0.71l-0.59,-0.59l-4,4c-0.36,0.36 -0.95,0.39 -1.34,0.06l-2.31,-1.91l-4.08,4.08c2.08,2.8 5.57,4.49 9.43,3.96c4.52,-0.61 8.12,-4.37 8.56,-8.91C22.58,6.51 17,1.14 10.46,2.12z"/>
+ android:pathData="M17.09,4.56c-0.7,-1.03 -1.5,-1.99 -2.4,-2.85 -0.35,-0.34 -0.94,-0.02 -0.84,0.46 0.19,0.94 0.39,2.18 0.39,3.29 0,2.06 -1.35,3.73 -3.41,3.73 -1.54,0 -2.8,-0.93 -3.35,-2.26 -0.1,-0.2 -0.14,-0.32 -0.2,-0.54 -0.11,-0.42 -0.66,-0.55 -0.9,-0.18 -0.18,0.27 -0.35,0.54 -0.51,0.83C4.68,9.08 4,11.46 4,14c0,4.42 3.58,8 8,8s8,-3.58 8,-8c0,-3.49 -1.08,-6.73 -2.91,-9.44zM11.71,19c-1.78,0 -3.22,-1.4 -3.22,-3.14 0,-1.62 1.05,-2.76 2.81,-3.12 1.47,-0.3 2.98,-0.93 4.03,-1.92 0.28,-0.26 0.74,-0.14 0.82,0.23 0.23,1.02 0.35,2.08 0.35,3.15 0.01,2.65 -2.14,4.8 -4.79,4.8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/widgets.xml b/compose/material/material/icons/generator/raw-icons/rounded/widgets.xml
index 9ad36d8..1b7a115 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/widgets.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/widgets.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,14v6c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1h-6C13.45,13 13,13.45 13,14zM4,21h6c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v6C3,20.55 3.45,21 4,21zM3,4v6c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1H4C3.45,3 3,3.45 3,4zM15.95,2.4L11.7,6.64c-0.39,0.39 -0.39,1.02 0,1.41l4.25,4.25c0.39,0.39 1.02,0.39 1.41,0l4.25,-4.25c0.39,-0.39 0.39,-1.02 0,-1.41L17.37,2.4C16.98,2.01 16.34,2.01 15.95,2.4z"/>
+ android:pathData="M13,14v6c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1zM4,21h6c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1L4,13c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1zM3,4v6c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1L11,4c0,-0.55 -0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1zM15.95,2.4L11.7,6.64c-0.39,0.39 -0.39,1.02 0,1.41l4.25,4.25c0.39,0.39 1.02,0.39 1.41,0l4.25,-4.25c0.39,-0.39 0.39,-1.02 0,-1.41L17.37,2.4c-0.39,-0.39 -1.03,-0.39 -1.42,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wifi.xml b/compose/material/material/icons/generator/raw-icons/rounded/wifi.xml
index b290ee3..edd4e9d 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wifi.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wifi.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18.49,12.13C16.67,10.79 14.43,10 12,10c-2.43,0 -4.67,0.79 -6.49,2.13c-0.72,0.53 -0.76,1.6 -0.13,2.24c0.53,0.54 1.37,0.57 1.98,0.12C8.67,13.55 10.27,13 12,13c1.73,0 3.33,0.55 4.64,1.49c0.62,0.44 1.45,0.41 1.98,-0.12C19.26,13.73 19.22,12.66 18.49,12.13zM22.8,7.89C19.86,5.46 16.1,4 12,4S4.14,5.46 1.2,7.89C0.53,8.44 0.49,9.47 1.11,10.1l0,0c0.55,0.55 1.42,0.58 2.02,0.09C5.55,8.2 8.64,7 12,7s6.45,1.2 8.87,3.19c0.6,0.49 1.47,0.46 2.02,-0.09l0,0C23.51,9.47 23.47,8.44 22.8,7.89zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2S13.1,16 12,16z"/>
+ android:pathData="M2.06,10.06c0.51,0.51 1.32,0.56 1.87,0.1 4.67,-3.84 11.45,-3.84 16.13,-0.01 0.56,0.46 1.38,0.42 1.89,-0.09 0.59,-0.59 0.55,-1.57 -0.1,-2.1 -5.71,-4.67 -13.97,-4.67 -19.69,0 -0.65,0.52 -0.7,1.5 -0.1,2.1zM9.82,17.82l1.47,1.47c0.39,0.39 1.02,0.39 1.41,0l1.47,-1.47c0.47,-0.47 0.37,-1.28 -0.23,-1.59 -1.22,-0.63 -2.68,-0.63 -3.91,0 -0.57,0.31 -0.68,1.12 -0.21,1.59zM6.09,14.09c0.49,0.49 1.26,0.54 1.83,0.13 2.44,-1.73 5.72,-1.73 8.16,0 0.57,0.4 1.34,0.36 1.83,-0.13l0.01,-0.01c0.6,-0.6 0.56,-1.62 -0.13,-2.11 -3.44,-2.49 -8.13,-2.49 -11.58,0 -0.69,0.5 -0.73,1.51 -0.12,2.12z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wifi_calling.xml b/compose/material/material/icons/generator/raw-icons/rounded/wifi_calling.xml
index eb6ded0..8170698 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wifi_calling.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wifi_calling.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20.97,4.24C20.01,3.68 18.46,3 16.5,3c-1.95,0 -3.5,0.67 -4.45,1.23c-0.57,0.33 -0.67,1.11 -0.2,1.57l3.96,3.96c0.39,0.39 1.03,0.39 1.42,0c2.15,-2.15 3.31,-3.31 3.95,-3.95C21.64,5.34 21.53,4.57 20.97,4.24z"/>
+ android:pathData="M22,4.95C21.79,4.78 19.67,3 16.5,3c-3.18,0 -5.29,1.78 -5.5,1.95L16.5,12L22,4.95z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M15.63,14.4l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3L4,3C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.56,0.03 1.03,-0.44 1.03,-1l0,-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.67,-0.73C16.2,14.07 15.86,14.17 15.63,14.4z"/>
+ android:pathData="M19.2,15.28l-2.54,-0.29c-0.61,-0.07 -1.21,0.14 -1.64,0.57l-1.84,1.84c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l1.85,-1.85c0.43,-0.43 0.64,-1.04 0.57,-1.64L8.72,4.8C8.6,3.79 7.75,3.03 6.73,3.03H5c-1.13,0 -2.07,0.94 -2,2.07C3.53,13.64 10.36,20.47 18.9,21c1.13,0.07 2.07,-0.87 2.07,-2v-1.73C20.97,16.25 20.21,15.4 19.2,15.28z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wifi_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/wifi_off.xml
index add852b..2de664f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wifi_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wifi_off.xml
@@ -6,14 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22.8,7.89C19.86,5.46 16.1,4 12,4c-1.58,0 -3.1,0.22 -4.55,0.62l2.54,2.54C10.65,7.06 11.31,7 12,7c3.36,0 6.45,1.2 8.87,3.19c0.6,0.49 1.47,0.46 2.02,-0.09l0,0C23.51,9.47 23.47,8.44 22.8,7.89z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.62,14.37c0.63,-0.63 0.59,-1.71 -0.13,-2.24c-1.6,-1.18 -3.53,-1.93 -5.63,-2.09l4.76,4.76C17.99,14.78 18.34,14.65 18.62,14.37z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M2.1,3.51c-0.39,0.39 -0.39,1.02 0,1.41L3.47,6.3c-0.8,0.47 -1.56,1 -2.27,1.58C0.53,8.44 0.49,9.47 1.11,10.1l0,0c0.55,0.55 1.42,0.58 2.02,0.09c0.78,-0.65 1.65,-1.2 2.56,-1.67l2.26,2.26c-0.87,0.35 -1.7,0.8 -2.44,1.35c-0.72,0.53 -0.76,1.6 -0.13,2.24c0.53,0.54 1.37,0.57 1.98,0.12c0.88,-0.63 1.9,-1.07 3,-1.3l8.71,8.71c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L3.51,3.51C3.12,3.12 2.49,3.12 2.1,3.51z"/>
+ android:pathData="M20.06,10.14c0.56,0.46 1.38,0.42 1.89,-0.09 0.59,-0.59 0.55,-1.57 -0.1,-2.1 -3.59,-2.94 -8.2,-4.03 -12.55,-3.26l2.59,2.59c2.89,-0.03 5.8,0.92 8.17,2.86zM17.79,11.97c-0.78,-0.57 -1.63,-1 -2.52,-1.3l2.95,2.95c0.24,-0.58 0.1,-1.27 -0.43,-1.65zM13.95,16.23c-1.22,-0.63 -2.68,-0.63 -3.91,0 -0.59,0.31 -0.7,1.12 -0.23,1.59l1.47,1.47c0.39,0.39 1.02,0.39 1.41,0l1.47,-1.47c0.49,-0.47 0.39,-1.28 -0.21,-1.59zM19.68,17.9L4.12,2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L5.05,6.1c-1.01,0.5 -1.99,1.11 -2.89,1.85 -0.65,0.53 -0.69,1.51 -0.1,2.1 0.51,0.51 1.32,0.56 1.87,0.1 1,-0.82 2.1,-1.46 3.25,-1.93l2.23,2.23c-1.13,0.3 -2.21,0.8 -3.19,1.51 -0.69,0.5 -0.73,1.51 -0.13,2.11l0.01,0.01c0.49,0.49 1.26,0.54 1.83,0.13 1.19,-0.84 2.58,-1.26 3.97,-1.29l6.37,6.37c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.37 0.39,-1 0,-1.39z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wifi_tethering.xml b/compose/material/material/icons/generator/raw-icons/rounded/wifi_tethering.xml
index da589e4..779d64f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wifi_tethering.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wifi_tethering.xml
@@ -6,11 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.25,7.05c-2.62,0.32 -4.78,2.41 -5.18,5.02c-0.24,1.55 0.13,3 0.89,4.17c0.35,0.54 1.11,0.63 1.56,0.18l0.01,-0.01c0.34,-0.34 0.37,-0.87 0.11,-1.27c-0.57,-0.88 -0.8,-1.99 -0.49,-3.18c0.35,-1.37 1.47,-2.47 2.84,-2.82C13.63,8.47 16,10.46 16,13c0,0.8 -0.24,1.53 -0.65,2.15c-0.27,0.41 -0.25,0.95 0.1,1.3l0.01,0.01c0.43,0.43 1.16,0.4 1.51,-0.11C17.61,15.4 18,14.24 18,13C18,9.44 14.89,6.6 11.25,7.05z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5.66,19.27c0.35,-0.35 0.4,-0.92 0.09,-1.31c-1.33,-1.66 -2.01,-3.86 -1.64,-6.22c0.54,-3.5 3.46,-6.29 6.98,-6.68C15.91,4.51 20,8.28 20,13c0,1.9 -0.67,3.62 -1.77,4.99c-0.32,0.39 -0.28,0.96 0.08,1.32l0,0c0.42,0.42 1.12,0.39 1.49,-0.08C21.17,17.52 22,15.36 22,13c0,-5.91 -5.13,-10.62 -11.17,-9.93C6.21,3.59 2.48,7.4 2.05,12.03c-0.26,2.72 0.59,5.23 2.12,7.16C4.54,19.66 5.24,19.69 5.66,19.27L5.66,19.27z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,13m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ android:pathData="M12,11c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,13c0,-3.56 -3.11,-6.4 -6.75,-5.95 -2.62,0.32 -4.78,2.41 -5.18,5.02 -0.33,2.15 0.49,4.11 1.93,5.4 0.48,0.43 1.23,0.33 1.56,-0.23l0.01,-0.01c0.24,-0.42 0.14,-0.93 -0.22,-1.26 -1.03,-0.93 -1.59,-2.37 -1.22,-3.94 0.33,-1.42 1.48,-2.57 2.9,-2.91C13.65,8.49 16,10.47 16,13c0,1.18 -0.52,2.23 -1.33,2.96 -0.36,0.32 -0.47,0.84 -0.23,1.26l0.01,0.01c0.31,0.53 1.03,0.69 1.5,0.28C17.2,16.41 18,14.8 18,13zM10.83,3.07c-4.62,0.52 -8.35,4.33 -8.78,8.96 -0.35,3.7 1.32,7.02 4.02,9.01 0.48,0.35 1.16,0.2 1.46,-0.31 0.25,-0.43 0.14,-0.99 -0.26,-1.29 -2.28,-1.69 -3.65,-4.55 -3.16,-7.7 0.54,-3.5 3.46,-6.29 6.98,-6.68C15.91,4.51 20,8.28 20,13c0,2.65 -1.29,4.98 -3.27,6.44 -0.4,0.3 -0.51,0.85 -0.26,1.29 0.3,0.52 0.98,0.66 1.46,0.31C20.4,19.22 22,16.3 22,13c0,-5.91 -5.13,-10.62 -11.17,-9.93z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/work.xml b/compose/material/material/icons/generator/raw-icons/rounded/work.xml
index 7ae5f39..4cc0c1f 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/work.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/work.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM14,6h-4V4h4V6z"/>
+ android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/work_off.xml b/compose/material/material/icons/generator/raw-icons/rounded/work_off.xml
index 4f44223..bf2f8a8 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/work_off.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/work_off.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v1.17l13.98,13.98c0,-0.05 0.02,-0.1 0.02,-0.16V8C22,6.89 21.11,6 20,6zM14,6h-4V4h4V6zM2.81,2.81c-0.39,-0.39 -1.02,-0.39 -1.41,0C1,3.2 1,3.83 1.39,4.22L3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19c0,1.11 0.89,2 2,2h14.17l1.61,1.61c0.39,0.39 1.02,0.39 1.41,0s0.39,-1.02 0,-1.41L2.81,2.81z"/>
+ android:pathData="M4.11,2.54c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L4.74,6H4c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h15.74l1.29,1.29c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.11,2.54zM10,4h4v2h-3.6L22,17.6V8c0,-1.11 -0.89,-2 -2,-2h-4V4c0,-1.11 -0.89,-2 -2,-2h-4c-0.99,0 -1.8,0.7 -1.96,1.64L10,5.6V4z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/workspace_premium.xml b/compose/material/material/icons/generator/raw-icons/rounded/workspace_premium.xml
new file mode 100644
index 0000000..819afd2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/rounded/workspace_premium.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10.92,12.75L12,11.93l1.07,0.81c0.39,0.29 0.92,-0.08 0.78,-0.55l-0.42,-1.36l1.2,-0.95C15,9.6 14.79,9 14.31,9h-1.4l-0.43,-1.34c-0.15,-0.46 -0.8,-0.46 -0.95,0L11.09,9H9.68C9.21,9 9,9.6 9.37,9.89l1.19,0.95l-0.42,1.36C10,12.67 10.53,13.04 10.92,12.75zM6,21.61c0,0.68 0.67,1.16 1.32,0.95L12,21l4.68,1.56C17.33,22.78 18,22.3 18,21.61v-6.33c1.24,-1.41 2,-3.25 2,-5.28c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8c0,2.03 0.76,3.87 2,5.28V21.61zM12,4c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6S8.69,4 12,4z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/wrap_text.xml b/compose/material/material/icons/generator/raw-icons/rounded/wrap_text.xml
index 011553a..4d17718 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/wrap_text.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/wrap_text.xml
@@ -7,11 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,12.5h12.25c0.97,0 1.75,0.78 1.75,1.75v0c0,0.97 -0.78,1.75 -1.75,1.75H14v-0.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.79,1.79c-0.2,0.2 -0.2,0.51 0,0.71l1.79,1.79c0.31,0.31 0.85,0.09 0.85,-0.35V18h3.25c2.07,0 3.75,-1.68 3.75,-3.75v0c0,-2.07 -1.68,-3.75 -3.75,-3.75H5c-0.55,0 -1,0.45 -1,1v0C4,12.05 4.45,12.5 5,12.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,6L4,6c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5C4.45,5 4,5.45 4,6z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5,18h3c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v0C4,17.55 4.45,18 5,18z"/>
+ android:pathData="M5,7h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L5,5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM16.83,11L5,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12.13c1,0 1.93,0.67 2.09,1.66 0.21,1.25 -0.76,2.34 -1.97,2.34L15,17v-0.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-1.79,1.79c-0.2,0.2 -0.2,0.51 0,0.71l1.79,1.79c0.32,0.32 0.85,0.09 0.85,-0.35L15,19h2c2.34,0 4.21,-2.01 3.98,-4.39 -0.2,-2.08 -2.06,-3.61 -4.15,-3.61zM9,17L5,17c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h4c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/youtube_searched_for.xml b/compose/material/material/icons/generator/raw-icons/rounded/youtube_searched_for.xml
index ae81e3b..ad2c33c 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/youtube_searched_for.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/youtube_searched_for.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21.75,18.34l-5.01,-5.01c1.01,-1.39 1.5,-3.18 1.13,-5.1c-0.51,-2.69 -2.77,-4.81 -5.49,-5.17C8.58,2.55 5.3,5.36 5.03,9H3.21C2.76,9 2.54,9.54 2.85,9.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79C9.46,9.54 9.24,9 8.79,9H7.05c0.28,-2.46 2.52,-4.34 5.13,-3.95c1.81,0.27 3.33,1.67 3.71,3.46C16.52,11.42 14.3,14 11.5,14c-0.49,0 -0.96,-0.09 -1.4,-0.23c-0.35,-0.12 -0.74,-0.01 -1,0.25l0,0c-0.53,0.53 -0.32,1.43 0.38,1.66C10.12,15.89 10.8,16 11.5,16c1.43,0 2.75,-0.47 3.83,-1.26l5.01,5.01c0.39,0.39 1.02,0.39 1.41,0C22.14,19.36 22.14,18.73 21.75,18.34z"/>
+ android:pathData="M17.01,14h-0.8l-0.27,-0.27c1.15,-1.34 1.76,-3.14 1.51,-5.09C17.11,6 15.1,3.78 12.5,3.18 8.26,2.2 4.51,5.53 4.51,9.5h-2.1c-0.47,0 -0.68,0.59 -0.31,0.89l3.4,2.75c0.19,0.2 0.51,0.21 0.71,0.01l2.9,-2.79c0.32,-0.31 0.1,-0.86 -0.35,-0.86H6.51c0,-2.49 2,-4.48 4.46,-4.5 2.44,-0.02 4.54,2.05 4.54,4.49 0,2.48 -2.02,4.51 -4.5,4.51 -0.45,0 -0.89,-0.07 -1.3,-0.19 -0.34,-0.1 -0.71,0 -0.96,0.26 -0.53,0.53 -0.32,1.45 0.39,1.66 0.59,0.17 1.22,0.27 1.87,0.27 1.61,0 3.08,-0.59 4.22,-1.57l0.27,0.27v0.79l4.27,4.25c0.41,0.41 1.07,0.41 1.48,0 0.41,-0.41 0.41,-1.08 0,-1.49L17.01,14z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/zoom_in.xml b/compose/material/material/icons/generator/raw-icons/rounded/zoom_in.xml
index b1f9a7c..047cc2a 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/zoom_in.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/zoom_in.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11.5,8.5h-1v-1c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1h-1c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h1v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h1c0.55,0 1,-0.45 1,-1C12.5,8.95 12.05,8.5 11.5,8.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14.73,13.31c1.13,-1.55 1.63,-3.58 0.98,-5.74c-0.68,-2.23 -2.57,-3.98 -4.85,-4.44C6.21,2.2 2.2,6.22 3.14,10.86c0.46,2.29 2.21,4.18 4.44,4.85c2.16,0.65 4.19,0.15 5.74,-0.98l5.56,5.56c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L14.73,13.31zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14z"/>
+ android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.78,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.26,4.25c0.41,0.41 1.07,0.41 1.48,0l0.01,-0.01c0.41,-0.41 0.41,-1.07 0,-1.48L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14zM9.5,7c-0.28,0 -0.5,0.22 -0.5,0.5L9,9L7.5,9c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5L9,10v1.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5L10,10h1.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5L10,9L10,7.5c0,-0.28 -0.22,-0.5 -0.5,-0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/rounded/zoom_out.xml b/compose/material/material/icons/generator/raw-icons/rounded/zoom_out.xml
index d76df3a..523b959 100644
--- a/compose/material/material/icons/generator/raw-icons/rounded/zoom_out.xml
+++ b/compose/material/material/icons/generator/raw-icons/rounded/zoom_out.xml
@@ -6,8 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,8.5H8c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1C12,8.95 11.55,8.5 11,8.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14.73,13.31c1.13,-1.55 1.63,-3.58 0.98,-5.74c-0.68,-2.23 -2.57,-3.98 -4.85,-4.44C6.21,2.2 2.2,6.22 3.14,10.86c0.46,2.29 2.21,4.18 4.44,4.85c2.16,0.65 4.19,0.15 5.74,-0.98l5.56,5.56c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L14.73,13.31zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14z"/>
+ android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.79,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.26,4.25c0.41,0.41 1.07,0.41 1.48,0l0.01,-0.01c0.41,-0.41 0.41,-1.07 0,-1.48L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14zM7.5,9h4c0.28,0 0.5,0.22 0.5,0.5s-0.22,0.5 -0.5,0.5h-4c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/ads_click.xml b/compose/material/material/icons/generator/raw-icons/sharp/ads_click.xml
new file mode 100644
index 0000000..79f2284
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/ads_click.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.71,17.99C8.53,17.84 6,15.22 6,12c0,-3.31 2.69,-6 6,-6c3.22,0 5.84,2.53 5.99,5.71l-2.1,-0.63C15.48,9.31 13.89,8 12,8c-2.21,0 -4,1.79 -4,4c0,1.89 1.31,3.48 3.08,3.89L11.71,17.99zM22,12c0,0.3 -0.01,0.6 -0.04,0.9l-1.97,-0.59C20,12.21 20,12.1 20,12c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8s3.58,8 8,8c0.1,0 0.21,0 0.31,-0.01l0.59,1.97C12.6,21.99 12.3,22 12,22C6.48,22 2,17.52 2,12C2,6.48 6.48,2 12,2S22,6.48 22,12zM18.23,16.26L22,15l-10,-3l3,10l1.26,-3.77l4.27,4.27l1.98,-1.98L18.23,16.26z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/airline_stops.xml b/compose/material/material/icons/generator/raw-icons/sharp/airline_stops.xml
new file mode 100644
index 0000000..f3b3692
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/airline_stops.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.21,9.21C15.93,10.78 13.45,13.3 13,17h2v2H9v-2h2c-0.5,-4.5 -4.37,-8 -9,-8V7c4.39,0 8.22,2.55 10,6.3c1.13,-2.43 2.99,-4.25 4.78,-5.52L14,5h7v7L18.21,9.21z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/airlines.xml b/compose/material/material/icons/generator/raw-icons/sharp/airlines.xml
new file mode 100644
index 0000000..e578a22
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/airlines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,4L2,20h17l3,-16H13zM14.5,14c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C17,12.88 15.88,14 14.5,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/android.xml b/compose/material/material/icons/generator/raw-icons/sharp/android.xml
index bf91766..28c533f 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/android.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/android.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71s-0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
+ android:pathData="M17.6,9.48l1.84,-3.18c0.16,-0.31 0.04,-0.69 -0.26,-0.85c-0.29,-0.15 -0.65,-0.06 -0.83,0.22l-1.88,3.24c-2.86,-1.21 -6.08,-1.21 -8.94,0L5.65,5.67c-0.19,-0.29 -0.58,-0.38 -0.87,-0.2C4.5,5.65 4.41,6.01 4.56,6.3L6.4,9.48C3.3,11.25 1.28,14.44 1,18h22C22.72,14.44 20.7,11.25 17.6,9.48zM7,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25S8.25,13.31 8.25,14C8.25,14.69 7.69,15.25 7,15.25zM17,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25C18.25,14.69 17.69,15.25 17,15.25z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/apps_outage.xml b/compose/material/material/icons/generator/raw-icons/sharp/apps_outage.xml
new file mode 100644
index 0000000..bd84f8b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/apps_outage.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4,8h4V4H4V8zM10,20h4v-4h-4V20zM4,20h4v-4H4V20zM4,14h4v-4H4V14zM10,14h4v-4h-4V14zM16,20h4v-4h-4V20zM19,0c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S21.76,0 19,0zM19.5,8h-1V7h1V8zM19.5,6h-1V2h1V6zM16,14h4v-2.07C19.67,11.98 19.34,12 19,12c-1.07,0 -2.09,-0.24 -3,-0.68V14zM10,4v4h2.68C12.24,7.09 12,6.07 12,5c0,-0.34 0.02,-0.67 0.07,-1H10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/area_chart.xml b/compose/material/material/icons/generator/raw-icons/sharp/area_chart.xml
new file mode 100644
index 0000000..1572332
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/area_chart.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,13v7h18v-1.5l-9,-7L8,17L3,13zM3,7l4,3l5,-7l5,4h4v8.97l-9.4,-7.31l-3.98,5.48L3,10.44V7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/arrow_forward_ios.xml b/compose/material/material/icons/generator/raw-icons/sharp/arrow_forward_ios.xml
index f9d6a55..a71005d 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/arrow_forward_ios.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/arrow_forward_ios.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.49,20.13l1.77,1.77 9.9,-9.9 -9.9,-9.9 -1.77,1.77L14.62,12l-8.13,8.13z"/>
+ android:pathData="M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/back_hand.xml b/compose/material/material/icons/generator/raw-icons/sharp/back_hand.xml
new file mode 100644
index 0000000..9c4c5a0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/back_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M2.21,10.47L5,9.36L7.25,15H8V2h2.5v10h1V0H14v12h1V1.5h2.5V12h1V4.5H21V16c0,4.42 -3.58,8 -8,8c-3.26,0 -6.19,-1.99 -7.4,-5.02L2.21,10.47z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/browser_updated.xml b/compose/material/material/icons/generator/raw-icons/sharp/browser_updated.xml
new file mode 100644
index 0000000..da28d37
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/browser_updated.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,13v5h-5l1,1v2H6v-2l1,-1H2V3l10,0v2L4,5v11h16v-3H22zM15,15l-5,-5h4V3h2v7h4L15,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/checklist.xml b/compose/material/material/icons/generator/raw-icons/sharp/checklist.xml
new file mode 100644
index 0000000..64e7ee3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/checklist.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,7h-9v2h9V7zM22,15h-9v2h9V15zM5.54,11L2,7.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,11zM5.54,19L2,15.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/checklist_rtl.xml b/compose/material/material/icons/generator/raw-icons/sharp/checklist_rtl.xml
new file mode 100644
index 0000000..eb4422c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/checklist_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,7H2v2h9V7zM11,15H2v2h9V15zM16.34,11l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,5.34L16.34,11zM16.34,19l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,13.34L16.34,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/co2.xml b/compose/material/material/icons/generator/raw-icons/sharp/co2.xml
new file mode 100644
index 0000000..1492964
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/co2.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,9h-5v6h5V9zM13.5,13.5h-2v-3h2V13.5zM8,13v2H3V9h5v2H6.5v-0.5h-2v3h2V13H8zM18.5,15.5v1h3V18H17v-3.5h3v-1h-3V12h4.5v3.5H18.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/comments_disabled.xml b/compose/material/material/icons/generator/raw-icons/sharp/comments_disabled.xml
new file mode 100644
index 0000000..f3e6307
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/comments_disabled.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.83,14H18v-2h-3.17l-1,-1H18V9h-6.17l-1,-1H18V6H8.83l-4,-4H22v17.17L16.83,14zM2.1,2.1L0.69,3.51L2,4.83V18h13.17l5.31,5.31l1.41,-1.41L2.1,2.1zM6,9h0.17l2,2H6V9zM6,14v-2h3.17l2,2H6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/compost.xml b/compose/material/material/icons/generator/raw-icons/sharp/compost.xml
new file mode 100644
index 0000000..b06253a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/compost.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.87,11.81c-0.23,-0.38 -0.37,-0.83 -0.37,-1.31C12.5,9.12 13.62,8 15,8l1,0c1.51,0 2,-1 2,-1s0.55,6 -3,6c-0.49,0 -0.94,-0.14 -1.32,-0.38c-0.24,0.64 -0.59,1.76 -0.76,2.96c1.26,0.22 2.28,0.89 2.77,1.77c1.69,-1.17 2.81,-3.13 2.81,-5.35h3c0,5.24 -4.26,9.5 -9.5,9.5S2.5,17.24 2.5,12S6.76,2.5 12,2.5V0l4,4l-4,4V5.5c-3.58,0 -6.5,2.92 -6.5,6.5c0,2.21 1.11,4.17 2.81,5.35c0.51,-0.92 1.63,-1.62 2.98,-1.8c-0.09,-0.69 -0.26,-1.42 -0.49,-2.03C10.45,13.82 10,14 9.5,14c-1.1,0 -2,-0.9 -2,-2v-0.99c0,-0.56 -0.19,-1.09 -0.5,-1.51c0,0 4.45,-0.23 4.5,2.5c0,0.29 -0.06,0.56 -0.17,0.8C10.91,12.48 10.47,12.2 10,12c0.58,0.43 1.37,1.37 2,2.6c0.67,-1.62 1.68,-3.27 3,-4.6C14.24,10.52 13.53,11.12 12.87,11.81z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/connecting_airports.xml b/compose/material/material/icons/generator/raw-icons/sharp/connecting_airports.xml
new file mode 100644
index 0000000..12357c5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/connecting_airports.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.4,17l1.3,4.4h-1.1L13,17h-3c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h3l2.6,-4.4h1.1L15.4,15h2.85L19,14h1l-0.6,2l0.6,2h-1l-0.75,-1H15.4zM5.75,7L5,6H4l0.6,2L4,10h1l0.75,-1H8.6l-1.3,4.4h1.1L11,9h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L8.4,2.6H7.3L8.6,7H5.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/cruelty_free.xml b/compose/material/material/icons/generator/raw-icons/sharp/cruelty_free.xml
new file mode 100644
index 0000000..4fc1fef
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/cruelty_free.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.84,14.52c-0.26,-0.19 -0.62,-0.63 -0.79,-0.84C17.24,12.01 19,8.87 19,5c0,-1.95 -0.74,-3 -2,-3c-1.54,0 -3.96,2.06 -5,5.97C10.96,4.06 8.54,2 7,2C5.74,2 5,3.05 5,5c0,3.87 1.76,7.01 2.95,8.68c-0.17,0.21 -0.53,0.65 -0.79,0.84c-0.5,0.41 -1.66,1.37 -1.66,2.98c0,2.21 1.79,4 4,4c1.55,0 2.5,-0.56 2.5,-0.56s0.95,0.56 2.5,0.56c2.21,0 4,-1.79 4,-4C18.5,15.89 17.34,14.93 16.84,14.52zM9.35,12.2C8.34,10.7 7,8.12 7,5c0,-0.49 0.06,-0.8 0.12,-0.97c0.94,0.31 3.24,2.71 3.38,7.64C10.03,11.79 9.66,11.97 9.35,12.2zM10.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S11,15.59 11,16C11,16.41 10.78,16.75 10.5,16.75zM12,19.5c-0.55,0 -1,-0.72 -1,-1c0,-0.28 0.45,-0.5 1,-0.5s1,0.22 1,0.5C13,18.78 12.55,19.5 12,19.5zM13.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S14,15.59 14,16C14,16.41 13.78,16.75 13.5,16.75zM13.5,11.67c0.14,-4.93 2.44,-7.33 3.38,-7.64C16.94,4.2 17,4.51 17,5c0,3.12 -1.34,5.7 -2.35,7.2C14.34,11.97 13.97,11.79 13.5,11.67z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/data_exploration.xml b/compose/material/material/icons/generator/raw-icons/sharp/data_exploration.xml
new file mode 100644
index 0000000..c057089
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/data_exploration.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,1.33 0.26,2.61 0.74,3.77L8,10.5l3.3,2.78L14.58,10H13V8h5v5h-2v-1.58L11.41,16l-3.29,-2.79l-4.4,4.4C5.52,20.26 8.56,22 12,22h10V12C22,6.48 17.52,2 12,2zM19.5,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.05,20.5 19.5,20.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/disabled_visible.xml b/compose/material/material/icons/generator/raw-icons/sharp/disabled_visible.xml
new file mode 100644
index 0000000..dfeb407
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/disabled_visible.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21.99,12.34C22,12.23 22,12.11 22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12c0,5.17 3.93,9.43 8.96,9.95c-0.93,-0.73 -1.72,-1.64 -2.32,-2.68C5.9,18 4,15.22 4,12c0,-1.85 0.63,-3.55 1.69,-4.9l5.66,5.66c0.56,-0.4 1.17,-0.73 1.82,-1L7.1,5.69C8.45,4.63 10.15,4 12,4c4.24,0 7.7,3.29 7.98,7.45C20.69,11.67 21.37,11.97 21.99,12.34zM17,13c-3.18,0 -5.9,1.87 -7,4.5c1.1,2.63 3.82,4.5 7,4.5s5.9,-1.87 7,-4.5C22.9,14.87 20.18,13 17,13zM17,20c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C19.5,18.88 18.38,20 17,20zM18.5,17.5c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5S18.5,16.67 18.5,17.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/document_scanner.xml b/compose/material/material/icons/generator/raw-icons/sharp/document_scanner.xml
new file mode 100644
index 0000000..ad1fbfc
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/document_scanner.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,3H4v3H2V1h5V3zM22,6V1h-5v2h3v3H22zM7,21H4v-3H2v5h5V21zM20,18v3h-3v2h5v-5H20zM19,4v16H5V4H19zM15,8H9v2h6V8zM15,11H9v2h6V11zM15,14H9v2h6V14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/draw.xml b/compose/material/material/icons/generator/raw-icons/sharp/draw.xml
new file mode 100644
index 0000000..a9532dd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/draw.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.85,10.39l2.48,-2.48l-4.24,-4.24l-2.48,2.48L18.85,10.39zM13.19,7.56L4,16.76V21h4.24l9.19,-9.19L13.19,7.56zM19,17.5c0,2.19 -2.54,3.5 -5,3.5c-0.48,0 -1,-0.07 -1,-0.07c0,-0.34 0,-2.03 0,-2.03S13.46,19 14,19c1.54,0 3,-0.73 3,-1.5c0,-0.47 -0.48,-0.87 -1.23,-1.2l1.48,-1.48C18.32,15.45 19,16.29 19,17.5zM4.58,13.35C3.61,12.79 3,12.06 3,11c0,-1.8 1.89,-2.63 3.56,-3.36C7.59,7.18 9,6.56 9,6c0,-0.41 -0.78,-1 -2,-1C5.76,5 5,5.61 5,6H3c0,-1.65 1.7,-3 4,-3c2.24,0 4,1.32 4,3c0,1.87 -1.93,2.72 -3.64,3.47C6.42,9.88 5,10.5 5,11c0,0.31 0.43,0.6 1.07,0.86L4.58,13.35z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/drive_file_move_rtl.xml b/compose/material/material/icons/generator/raw-icons/sharp/drive_file_move_rtl.xml
new file mode 100644
index 0000000..68d55fa
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/drive_file_move_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,6H12l-2,-2H2v16h20V6zM12,17l-4,-4l4,-4v3h4v2h-4V17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/edit_calendar.xml b/compose/material/material/icons/generator/raw-icons/sharp/edit_calendar.xml
new file mode 100644
index 0000000..0007bf8
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/edit_calendar.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,22H3V4h3V2h2v2h8V2h2v2h3v8h-2v-2H5v10h7V22zM22.13,16.99l1.41,-1.41l-2.12,-2.12l-1.41,1.41L22.13,16.99zM21.42,17.7l-5.3,5.3H14v-2.12l5.3,-5.3L21.42,17.7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/edit_note.xml b/compose/material/material/icons/generator/raw-icons/sharp/edit_note.xml
new file mode 100644
index 0000000..37faa7f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/edit_note.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l1.41,-1.41l2.12,2.12l-1.41,1.41L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/emergency.xml b/compose/material/material/icons/generator/raw-icons/sharp/emergency.xml
new file mode 100644
index 0000000..0c5a61b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/emergency.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.79,9.23l-2,-3.46l-4.79,2.77l0,-5.54l-4,0l0,5.54l-4.79,-2.77l-2,3.46l4.79,2.77l-4.79,2.77l2,3.46l4.79,-2.77l0,5.54l4,0l0,-5.54l4.79,2.77l2,-3.46l-4.79,-2.77z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/expand_circle_down.xml b/compose/material/material/icons/generator/raw-icons/sharp/expand_circle_down.xml
new file mode 100644
index 0000000..0ce65fd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/expand_circle_down.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,15.5L7.5,11l1.42,-1.41L12,12.67l3.08,-3.08L16.5,11L12,15.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/fitbit.xml b/compose/material/material/icons/generator/raw-icons/sharp/fitbit.xml
new file mode 100644
index 0000000..da71490
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/fitbit.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.89,13.89c1.04,0 1.89,-0.85 1.89,-1.89s-0.85,-1.89 -1.89,-1.89C18.85,10.11 18,10.96 18,12S18.85,13.89 19.89,13.89zM15.65,13.68c0.93,0 1.68,-0.75 1.68,-1.68s-0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68S14.72,13.68 15.65,13.68zM15.65,9.42c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,8.67 14.72,9.42 15.65,9.42zM15.65,17.93c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,17.17 14.72,17.93 15.65,17.93zM11.41,13.47c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,13.47 11.41,13.47zM11.41,9.21c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,9.21 11.41,9.21zM11.41,17.73c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,17.07 10.59,17.73 11.41,17.73zM11.41,22c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,21.34 10.59,22 11.41,22zM11.41,4.94c0.81,0 1.47,-0.66 1.47,-1.47S12.22,2 11.41,2c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,4.94 11.41,4.94zM7.16,13.26c0.7,0 1.26,-0.57 1.26,-1.26s-0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26S6.46,13.26 7.16,13.26zM7.16,17.51c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,16.94 6.46,17.51 7.16,17.51zM7.16,9.02c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,8.45 6.46,9.02 7.16,9.02zM3.29,13.05c0.58,0 1.05,-0.47 1.05,-1.05s-0.47,-1.05 -1.05,-1.05c-0.58,0 -1.05,0.47 -1.05,1.05S2.71,13.05 3.29,13.05z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/flight_class.xml b/compose/material/material/icons/generator/raw-icons/sharp/flight_class.xml
new file mode 100644
index 0000000..1930b55
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/flight_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18,4h-6v9h6V4zM9.5,16H18v2H8L5,8V4h2v4L9.5,16zM8,19h10v2H8V19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/free_cancellation.xml b/compose/material/material/icons/generator/raw-icons/sharp/free_cancellation.xml
new file mode 100644
index 0000000..7630ee9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/free_cancellation.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.21,20H5V10h14v4.38l2,-2V4h-3V2h-2v2H8V2H6v2H3v18h10.21L11.21,20zM16.54,22.5L13,18.96l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L16.54,22.5zM10.41,14L12,15.59L10.59,17L9,15.41L7.41,17L6,15.59L7.59,14L6,12.41L7.41,11L9,12.59L10.59,11L12,12.41L10.41,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/front_hand.xml b/compose/material/material/icons/generator/raw-icons/sharp/front_hand.xml
new file mode 100644
index 0000000..204441a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/front_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.5,8v7H18c-1.65,0 -3,1.35 -3,3h-1c0,-2.04 1.53,-3.72 3.5,-3.97V2H15v9h-1V0h-2.5v11h-1V1.5H8V12H7V4.5H4.5v11.25c0,4.56 3.69,8.25 8.25,8.25S21,20.31 21,15.75V8H18.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/generating_tokens.xml b/compose/material/material/icons/generator/raw-icons/sharp/generating_tokens.xml
new file mode 100644
index 0000000..8f331f3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/generating_tokens.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8C17,7.58 13.42,4 9,4zM12,10.5h-2v5H8v-5H6V9h6V10.5zM20.25,3.75L23,5l-2.75,1.25L19,9l-1.25,-2.75L15,5l2.75,-1.25L19,1L20.25,3.75zM20.25,17.75L23,19l-2.75,1.25L19,23l-1.25,-2.75L15,19l2.75,-1.25L19,15L20.25,17.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/gif_box.xml b/compose/material/material/icons/generator/raw-icons/sharp/gif_box.xml
new file mode 100644
index 0000000..eed1049
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/gif_box.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,3H3v18h18V3zM9.5,13v-1h1v2h-3v-4h3v1h-2v2H9.5zM12.5,14h-1v-4h1V14zM16.5,11h-2v0.5H16v1h-1.5V14h-1v-4h3V11z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/group_add.xml b/compose/material/material/icons/generator/raw-icons/sharp/group_add.xml
index 4746025..2ab0b72 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/group_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/group_add.xml
@@ -6,5 +6,17 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,10L5,10L5,7L3,7v3L0,10v2h3v3h2v-3h3v-2zM18,11c1.66,0 2.99,-1.34 2.99,-3S19.66,5 18,5c-0.32,0 -0.63,0.05 -0.91,0.14 0.57,0.81 0.9,1.79 0.9,2.86s-0.34,2.04 -0.9,2.86c0.28,0.09 0.59,0.14 0.91,0.14zM13,11c1.66,0 2.99,-1.34 2.99,-3S14.66,5 13,5s-3,1.34 -3,3 1.34,3 3,3zM19.62,13.16c0.83,0.73 1.38,1.66 1.38,2.84v2h3v-2c0,-1.54 -2.37,-2.49 -4.38,-2.84zM13,13c-2,0 -6,1 -6,3v2h12v-2c0,-2 -4,-3 -6,-3z"/>
+ android:pathData="M22,9l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0l0,-2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4S4,5.79 4,8S5.79,12 8,12z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/group_off.xml b/compose/material/material/icons/generator/raw-icons/sharp/group_off.xml
new file mode 100644
index 0000000..6868f1d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/group_off.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.06,0 -0.12,0 -0.18,0l-0.77,-0.77C14.65,10.29 15,9.18 15,8zM22.83,20H23v-3c0,-2.18 -3.58,-3.47 -6.34,-3.87c1.1,0.75 1.95,1.71 2.23,2.94L22.83,20zM7.24,4.41C7.77,4.15 8.37,4 9,4c2.21,0 4,1.79 4,4c0,0.63 -0.15,1.23 -0.41,1.76L7.24,4.41zM9.17,12C9.11,12 9.06,12 9,12c-2.21,0 -4,-1.79 -4,-4c0,-0.06 0,-0.11 0,-0.17L0.69,3.51L2.1,2.1l19.8,19.8l-1.41,1.41L17,19.83V20H1v-3c0,-2.66 5.33,-4 8,-4c0.37,0 0.8,0.03 1.25,0.08L9.17,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/group_remove.xml b/compose/material/material/icons/generator/raw-icons/sharp/group_remove.xml
new file mode 100644
index 0000000..c71530e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/group_remove.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,9v2h-6V9H24zM8,4C5.79,4 4,5.79 4,8s1.79,4 4,4s4,-1.79 4,-4S10.21,4 8,4zM8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13zM12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05zM16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/hotel_class.xml b/compose/material/material/icons/generator/raw-icons/sharp/hotel_class.xml
new file mode 100644
index 0000000..b2aecb9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/hotel_class.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.58,10H1l6.17,4.41L4.83,22L11,17.31L17.18,22l-2.35,-7.59L21,10h-7.58L11,2L8.58,10zM21.36,22l-1.86,-6.01L23.68,13h-3.44l-3.08,2.2l1.46,4.72L21.36,22zM17,8l-1.82,-6l-1.04,3.45L14.91,8H17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/hub.xml b/compose/material/material/icons/generator/raw-icons/sharp/hub.xml
new file mode 100644
index 0000000..fedb1a7
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/hub.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.4,18.2C8.78,18.7 9,19.32 9,20c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3s1.34,-3 3,-3c0.44,0 0.85,0.09 1.23,0.26l1.41,-1.77c-0.92,-1.03 -1.29,-2.39 -1.09,-3.69l-2.03,-0.68C4.98,11.95 4.06,12.5 3,12.5c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3c0,0.07 0,0.14 -0.01,0.21l2.03,0.68c0.64,-1.21 1.82,-2.09 3.22,-2.32l0,-2.16C9.96,5.57 9,4.4 9,3c0,-1.66 1.34,-3 3,-3s3,1.34 3,3c0,1.4 -0.96,2.57 -2.25,2.91v2.16c1.4,0.23 2.58,1.11 3.22,2.32l2.03,-0.68C18,9.64 18,9.57 18,9.5c0,-1.66 1.34,-3 3,-3s3,1.34 3,3s-1.34,3 -3,3c-1.06,0 -1.98,-0.55 -2.52,-1.37l-2.03,0.68c0.2,1.29 -0.16,2.65 -1.09,3.69l1.41,1.77C17.15,17.09 17.56,17 18,17c1.66,0 3,1.34 3,3s-1.34,3 -3,3s-3,-1.34 -3,-3c0,-0.68 0.22,-1.3 0.6,-1.8l-1.41,-1.77c-1.35,0.75 -3.01,0.76 -4.37,0L8.4,18.2z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/incomplete_circle.xml b/compose/material/material/icons/generator/raw-icons/sharp/incomplete_circle.xml
new file mode 100644
index 0000000..e7e6e41
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/incomplete_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12c0,5.52 -4.48,10 -10,10S2,17.52 2,12c0,-2.76 1.12,-5.26 2.93,-7.07L12,12V2C17.52,2 22,6.48 22,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/interests.xml b/compose/material/material/icons/generator/raw-icons/sharp/interests.xml
new file mode 100644
index 0000000..ab45afd
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/interests.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.02,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.23,13 7.02,13zM13,13v8h8v-8H13zM7,2l-5,9h10L7,2zM19.25,2.5c-1.06,0 -1.81,0.56 -2.25,1.17c-0.44,-0.61 -1.19,-1.17 -2.25,-1.17C13.19,2.5 12,3.78 12,5.25c0,2 2.42,3.42 5,5.75c2.58,-2.33 5,-3.75 5,-5.75C22,3.78 20.81,2.5 19.25,2.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/interpreter_mode.xml b/compose/material/material/icons/generator/raw-icons/sharp/interpreter_mode.xml
new file mode 100644
index 0000000..f5c71e2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/interpreter_mode.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.5,16.5c-0.83,0 -1.5,-0.67 -1.5,-1.5v-2.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5V15C22,15.83 21.33,16.5 20.5,16.5zM20,20h1c0,0 0,-1.54 0,-1.54c1.69,-0.24 3,-1.7 3,-3.46h-1c0,1.38 -1.12,2.5 -2.5,2.5S18,16.38 18,15h-1c0,1.76 1.31,3.22 3,3.46C20,18.46 20,20 20,20zM9,12c-2.21,0 -4,-1.79 -4,-4c0,-2.21 1.79,-4 4,-4c0.47,0 0.92,0.08 1.34,0.23C9.5,5.26 9,6.57 9,8c0,1.43 0.5,2.74 1.34,3.77C9.92,11.92 9.47,12 9,12zM7.11,13.13C5.79,14.05 5,15.57 5,17.22V20H1v-2.78c0,-1.12 0.61,-2.15 1.61,-2.66C3.85,13.92 5.37,13.37 7.11,13.13zM11,8c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S11,10.21 11,8zM18.32,20c-1.67,-0.81 -2.82,-2.52 -2.82,-4.5c0,-0.89 0.23,-1.73 0.64,-2.45C15.77,13.02 15.39,13 15,13c-2.53,0 -4.71,0.7 -6.39,1.56C7.61,15.07 7,16.1 7,17.22V20L18.32,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/kebab_dining.xml b/compose/material/material/icons/generator/raw-icons/sharp/kebab_dining.xml
new file mode 100644
index 0000000..7c3b622
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/kebab_dining.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.75,8H11v5H7.75v1H8.5c1.38,0 2.5,1.12 2.5,2.5S9.88,19 8.5,19H7.75v4h-1.5v-4H5.5C4.12,19 3,17.88 3,16.5S4.12,14 5.5,14h0.75v-1H3V8h3.25V7H5.5C4.12,7 3,5.88 3,4.5S4.12,2 5.5,2h0.75V1h1.5v1H8.5C9.88,2 11,3.12 11,4.5S9.88,7 8.5,7H7.75V8zM17.75,7h0.75C19.88,7 21,5.88 21,4.5S19.88,2 18.5,2h-0.75V1h-1.5v1H15.5C14.12,2 13,3.12 13,4.5S14.12,7 15.5,7h0.75v1H13v5h3.25v1H15.5c-1.38,0 -2.5,1.12 -2.5,2.5s1.12,2.5 2.5,2.5h0.75v4h1.5v-4h0.75c1.38,0 2.5,-1.12 2.5,-2.5S19.88,14 18.5,14h-0.75v-1H21V8h-3.25V7z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/mode_of_travel.xml b/compose/material/material/icons/generator/raw-icons/sharp/mode_of_travel.xml
new file mode 100644
index 0000000..1cc03da
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/mode_of_travel.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.31,18.9c-0.96,1 -2.06,2.03 -3.31,3.1c-5.33,-4.55 -8,-8.48 -8,-11.8C4,5.22 7.8,2 12,2c4,0 7.64,2.92 7.97,7.5l3.53,0L19,14l-4.5,-4.5l3.47,0C17.65,6.24 15.13,4 12,4c-3.35,0 -6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14c0.64,-0.59 1.23,-1.16 1.77,-1.71c-0.17,-0.34 -0.27,-0.72 -0.27,-1.12c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S17.38,19 16,19C15.76,19 15.53,18.97 15.31,18.9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/new_label.xml b/compose/material/material/icons/generator/raw-icons/sharp/new_label.xml
new file mode 100644
index 0000000..6ef49f0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/new_label.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,12l-4.97,7H12l0,-2l0,-4H9v-3H3V5h13.03L21,12zM10,15H7v-3H5v3H2v2h3v3h2v-3h3V15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/palette.xml b/compose/material/material/icons/generator/raw-icons/sharp/palette.xml
index 4bf1550..0d97f03 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/palette.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/palette.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
+ android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10c1.38,0 2.5,-1.12 2.5,-2.5c0,-0.61 -0.23,-1.2 -0.64,-1.67c-0.08,-0.1 -0.13,-0.21 -0.13,-0.33c0,-0.28 0.22,-0.5 0.5,-0.5H16c3.31,0 6,-2.69 6,-6C22,6.04 17.51,2 12,2zM17.5,13c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C19,12.33 18.33,13 17.5,13zM14.5,9C13.67,9 13,8.33 13,7.5C13,6.67 13.67,6 14.5,6S16,6.67 16,7.5C16,8.33 15.33,9 14.5,9zM5,11.5C5,10.67 5.67,10 6.5,10S8,10.67 8,11.5C8,12.33 7.33,13 6.5,13S5,12.33 5,11.5zM11,7.5C11,8.33 10.33,9 9.5,9S8,8.33 8,7.5C8,6.67 8.67,6 9.5,6S11,6.67 11,7.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/personal_injury.xml b/compose/material/material/icons/generator/raw-icons/sharp/personal_injury.xml
new file mode 100644
index 0000000..22c5d7b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/personal_injury.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,6c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S8,8.21 8,6zM17,22h1c1.1,0 2,-0.9 2,-2l0,-4.78c0,-1.12 -0.61,-2.15 -1.61,-2.66c-0.43,-0.22 -0.9,-0.43 -1.39,-0.62L17,22zM12.34,17L15,11.33C14.07,11.12 13.07,11 12,11c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,13.07 4,14.1 4,15.22L4,22h2.34C6.12,21.55 6,21.04 6,20.5C6,18.57 7.57,17 9.5,17H12.34zM10,22l1.41,-3H9.5C8.67,19 8,19.67 8,20.5S8.67,22 9.5,22H10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/phone_locked.xml b/compose/material/material/icons/generator/raw-icons/sharp/phone_locked.xml
index f9ce3b2..a0424c6 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/phone_locked.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/phone_locked.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13.21,17.37c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l2.53,-2.53L8.54,3L3.03,3C2.45,13.18 10.82,21.55 21,20.97v-5.51l-5.27,-0.61 -2.52,2.52zM20,4v-0.36c0,-1.31 -0.94,-2.5 -2.24,-2.63C16.26,0.86 15,2.03 15,3.5L15,4h-1v6h7L21,4h-1zM19,4h-3v-0.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5L19,4z"/>
+ android:pathData="M20,5V4c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v1h-1v5h6V5H20zM19,5h-2V4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,15l-5,-1l-2.9,2.9c-2.5,-1.43 -4.57,-3.5 -6,-6L10,8L9,3L3,3c0,3.28 0.89,6.35 2.43,9c1.58,2.73 3.85,4.99 6.57,6.57c2.65,1.53 5.72,2.43 9,2.43L21,15z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/photo_album.xml b/compose/material/material/icons/generator/raw-icons/sharp/photo_album.xml
index d1d436a..0e4ceff 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/photo_album.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/photo_album.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,2L4,2v20h16L20,2zM6,4h5v8l-2.5,-1.5L6,12L6,4zM6,19l3,-3.86 2.14,2.58 3,-3.86L18,19L6,19z"/>
+ android:pathData="M20,2H4v20h16V2zM11,4h5v7l-2.5,-1.5L11,11V4zM7,18l2.38,-3.17L11,17l2.62,-3.5L17,18H7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/pin_end.xml b/compose/material/material/icons/generator/raw-icons/sharp/pin_end.xml
new file mode 100644
index 0000000..358beac
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/pin_end.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,12V6H4v12h10l0,2H2V4h20v8H20zM19,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c1.66,0 3,-1.34 3,-3S20.66,14 19,14zM14.66,8H9v5.66l2.12,-2.12l2.83,2.83l1.41,-1.41l-2.83,-2.83L14.66,8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/pin_invoke.xml b/compose/material/material/icons/generator/raw-icons/sharp/pin_invoke.xml
new file mode 100644
index 0000000..fedb137
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/pin_invoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12v8H2V4h12l0,2H4v12h16v-6H22zM22,7c0,-1.66 -1.34,-3 -3,-3c-1.66,0 -3,1.34 -3,3s1.34,3 3,3C20.66,10 22,8.66 22,7zM11.47,12.12l-2.83,2.83l1.41,1.41l2.83,-2.83L15,15.66V10H9.34L11.47,12.12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/playlist_add_check_circle.xml b/compose/material/material/icons/generator/raw-icons/sharp/playlist_add_check_circle.xml
new file mode 100644
index 0000000..1c67620
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/playlist_add_check_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM7,7h7v2H7V7zM7,10h7v2H7V10zM10,15H7v-2h3V15zM14.05,18.36l-2.83,-2.83l1.41,-1.41l1.41,1.41L17.59,12L19,13.41L14.05,18.36z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/playlist_add_circle.xml b/compose/material/material/icons/generator/raw-icons/sharp/playlist_add_circle.xml
new file mode 100644
index 0000000..c2a7236
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/playlist_add_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7,7h7v2H7V7zM10,15H7v-2h3V15zM7,12v-2h7v2H7zM19,15h-2v2h-2v-2h-2v-2h2v-2h2v2h2V15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/private_connectivity.xml b/compose/material/material/icons/generator/raw-icons/sharp/private_connectivity.xml
new file mode 100644
index 0000000..f17e1f7
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/private_connectivity.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.93,11c-0.49,-3.39 -3.4,-6 -6.93,-6s-6.44,2.61 -6.93,6H2v2h3.07c0.49,3.39 3.4,6 6.93,6s6.44,-2.61 6.93,-6H22v-2H18.93zM15,10.5v5H9v-5h1v-1c0,-1.21 1.08,-2.18 2.34,-1.97C13.32,7.69 14,8.61 14,9.61l0,0.89H15zM12.75,13c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75c0,-0.41 0.34,-0.75 0.75,-0.75S12.75,12.59 12.75,13zM13,9.5v1h-2v-1c0,-0.55 0.45,-1 1,-1S13,8.95 13,9.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/real_estate_agent.xml b/compose/material/material/icons/generator/raw-icons/sharp/real_estate_agent.xml
new file mode 100644
index 0000000..bcdf389
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/real_estate_agent.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M1,22h4V11H1V22zM14,1.5l-7,5V9h2l10,4v2h2V6.5L14,1.5zM13.5,10h-1V9h1V10zM13.5,8h-1V7h1V8zM15.5,10h-1V9h1V10zM15.5,8h-1V7h1V8zM22,19l-8,3l-7,-1.98V11h1.97L17,14l0,2h-4l-1.76,-0.68l-0.33,0.94L13,17h9V19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/recycling.xml b/compose/material/material/icons/generator/raw-icons/sharp/recycling.xml
new file mode 100644
index 0000000..bd30b8a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/recycling.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5.77,7.15L7.2,4.78l1.03,-1.71c0.39,-0.65 1.33,-0.65 1.72,0l1.48,2.46l-1.23,2.06L9.2,9.21L5.77,7.15zM21.72,12.97l-1.6,-2.66l-3.46,2L18.87,16H20c0.76,0 1.45,-0.43 1.79,-1.11C21.93,14.61 22,14.31 22,14C22,13.64 21.9,13.29 21.72,12.97zM16,21h1.5c0.76,0 1.45,-0.43 1.79,-1.11L20.74,17H16v-2l-4,4l4,4V21zM10,17H5.7l-0.84,1.41c-0.3,0.5 -0.32,1.12 -0.06,1.65l0,0C5.08,20.63 5.67,21 6.32,21H10V17zM6.12,14.35l1.73,1.04L6.48,9.9L1,11.27l1.7,1.02l-0.41,0.69c-0.35,0.59 -0.38,1.31 -0.07,1.92l1.63,3.26L6.12,14.35zM17.02,5.14l-1.3,-2.17C15.35,2.37 14.7,2 14,2h-3.53l3.12,5.2l-1.72,1.03l5.49,1.37l1.37,-5.49L17.02,5.14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/soup_kitchen.xml b/compose/material/material/icons/generator/raw-icons/sharp/soup_kitchen.xml
new file mode 100644
index 0000000..f131027
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/soup_kitchen.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.4,7C6.06,7.55 6,7.97 6,8.38C6,9.15 7,11 7,12c0,0.95 -0.4,1.5 -0.4,1.5H5.1c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62C4.5,7.97 4.56,7.55 4.9,7H6.4zM11.4,7C11.06,7.55 11,7.97 11,8.38C11,9.15 12,11 12,12c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H11.4zM8.15,7c-0.34,0.55 -0.4,0.97 -0.4,1.38c0,0.77 1,2.63 1,3.62c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H8.15zM21.47,6.5c0,0 0.13,-1.06 0.13,-1.5c0,-1.65 -1.35,-3 -3,-3c-1.54,0 -2.81,1.16 -2.98,2.65L14.53,15l-11.6,0c-0.02,3.87 3.09,7 6.82,7c3.48,0 6.34,-2.73 6.71,-6.23l1.15,-10.87C17.66,4.39 18.08,4 18.6,4c0.55,0 1,0.45 1,1c0,0.3 -0.1,1.25 -0.1,1.25L21.47,6.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/south_america.xml b/compose/material/material/icons/generator/raw-icons/sharp/south_america.xml
new file mode 100644
index 0000000..ca13a97
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/south_america.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM4,12c0,-1.95 0.7,-3.74 1.87,-5.13L9,10v1c0,1.1 0.9,2 2,2v5.59c0,0.27 0.11,0.52 0.29,0.71L12,20C7.58,20 4,16.42 4,12zM13,19.94V18l3.75,-5.62c0.16,-0.25 0.25,-0.54 0.25,-0.83V10.5c0,-0.55 -0.45,-1 -1,-1h-1.5l-1.4,-1.75C12.72,7.28 12.15,7 11.54,7H8V5.07C9.18,4.39 10.54,4 12,4c4.41,0 8,3.59 8,8C20,16.07 16.94,19.44 13,19.94z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/space_dashboard.xml b/compose/material/material/icons/generator/raw-icons/sharp/space_dashboard.xml
new file mode 100644
index 0000000..b5d3587
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/space_dashboard.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,21H3V3h8V21zM13,21h8v-9h-8V21zM21,10V3h-8v7H21z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/spoke.xml b/compose/material/material/icons/generator/raw-icons/sharp/spoke.xml
new file mode 100644
index 0000000..b271345
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/spoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,7c0,2.21 -1.79,4 -4,4S8,9.21 8,7s1.79,-4 4,-4S16,4.79 16,7zM7,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.21,13 7,13zM17,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S19.21,13 17,13z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/stop_circle.xml b/compose/material/material/icons/generator/raw-icons/sharp/stop_circle.xml
index e0cf569..a25ea07 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/stop_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/stop_circle.xml
@@ -6,6 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M8,16h8V8H8V16zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2L12,2z"
- android:fillType="evenOdd"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM16,16H8V8h8V16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/switch_access_shortcut.xml b/compose/material/material/icons/generator/raw-icons/sharp/switch_access_shortcut.xml
new file mode 100644
index 0000000..6c27e1c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/switch_access_shortcut.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-2.73 1.08,-5.27 2.75,-7.25L12,2h7v7l-2.82,-2.82C14.84,7.82 14,9.88 14,12c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/switch_access_shortcut_add.xml b/compose/material/material/icons/generator/raw-icons/sharp/switch_access_shortcut_add.xml
new file mode 100644
index 0000000..84b07f9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/switch_access_shortcut_add.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,14h-2v-2h-2v2h-2v2h2v2h2v-2h2V14zM7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-2.73 1.08,-5.27 2.75,-7.25L12,2h7v7l-2.82,-2.82C14.84,7.82 14,9.88 14,12c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/sync_alt.xml b/compose/material/material/icons/generator/raw-icons/sharp/sync_alt.xml
index f899b57..360b6a2 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/sync_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/sync_alt.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,8l-4,-4v3H3v2h15v3L22,8z"/>
+ android:pathData="M18,12l4,-4l-4,-4l0,3l-15,0l0,2l15,0z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M2,16l4,4v-3h15v-2H6v-3L2,16z"/>
+ android:pathData="M6,12l-4,4l4,4l0,-3l15,0l0,-2l-15,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/tips_and_updates.xml b/compose/material/material/icons/generator/raw-icons/sharp/tips_and_updates.xml
new file mode 100644
index 0000000..93d5882
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/tips_and_updates.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,19h8v-2H5V19zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/token.xml b/compose/material/material/icons/generator/raw-icons/sharp/token.xml
new file mode 100644
index 0000000..b43943e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/token.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.97,6.43L12,2L4.03,6.43L9.1,9.24C9.83,8.48 10.86,8 12,8s2.17,0.48 2.9,1.24L19.97,6.43zM10,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2s-0.9,2 -2,2S10,13.1 10,12zM11,21.44L3,17V8.14l5.13,2.85C8.04,11.31 8,11.65 8,12c0,1.86 1.27,3.43 3,3.87V21.44zM13,21.44v-5.57c1.73,-0.44 3,-2.01 3,-3.87c0,-0.35 -0.04,-0.69 -0.13,-1.01L21,8.14L21,17L13,21.44z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/vaccines.xml b/compose/material/material/icons/generator/raw-icons/sharp/vaccines.xml
new file mode 100644
index 0000000..caa2e8f
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/vaccines.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,5.5H8V4h1.5V2h-5v2H6v1.5H2v2c0,0 0.45,0 1,0V17h3v4l2,1.5V17h3V7.5c0.55,0 1,0 1,0V5.5zM9,9H6.5v1.5H9V12H6.5v1.5H9L9,15H5V7.5h4V9zM19.5,10.5V10h1V8h-7l-0.01,2h1.01v0.5c0,0.5 -1.5,1.16 -1.5,3V22h8v-8.5C21,11.66 19.5,11 19.5,10.5zM16.5,10.5V10h1v0.5c0,1.6 1.5,2 1.5,3V14h-4c0,-0.21 0,-0.39 0,-0.5C15,12.5 16.5,12.1 16.5,10.5zM15,20c0,0 0,-0.63 0,-1.5h4V20H15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_agenda.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_agenda.xml
index 6cfa764..86e4ae3 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_agenda.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_agenda.xml
@@ -6,5 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,13L2,13v8h19v-8zM21,3L2,3v8h19L21,3z"/>
+ android:pathData="M3,13h18v8h-18z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,3h18v8h-18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_array.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_array.xml
index b7a7cb9..0fa8195 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_array.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_array.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h3V5H4v13zM18,5v13h3V5h-3zM8,18h9V5H8v13z"/>
+ android:pathData="M21,5h-3v14h3V5zM17,5H7v14h10V5zM6,5H3v14h3V5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_carousel.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_carousel.xml
index c045023..838b749 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_carousel.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_carousel.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,19h10L17,4L7,4v15zM2,17h4L6,6L2,6v11zM18,6v11h4L22,6h-4z"/>
+ android:pathData="M2,7h4v10H2V7zM7,19h10V5H7V19zM18,7h4v10h-4V7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_column.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_column.xml
index 7d8a647..49d8ddc 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_column.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_column.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,18h5L15,5h-5v13zM4,18h5L9,5L4,5v13zM16,5v13h5L21,5h-5z"/>
+ android:pathData="M14.67,5v14H9.33V5H14.67zM15.67,19H21V5h-5.33V19zM8.33,19V5H3v14H8.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_list.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_list.xml
index 3e8c0d8..4510516 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_list.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_list.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M3,14h4v-4L3,10v4zM3,19h4v-4L3,15v4zM3,9h4L7,5L3,5v4zM8,14h12v-4L8,10v4zM8,19h12v-4L8,15v4zM8,5v4h12L20,5L8,5z"/>
+ android:pathData="M3,14h4v-4H3V14zM3,19h4v-4H3V19zM3,9h4V5H3V9zM8,14h13v-4H8V14zM8,19h13v-4H8V19zM8,5v4h13V5H8z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_module.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_module.xml
index 78298cd..56ca7a8 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_module.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_module.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,11h5L9,5L4,5v6zM4,18h5v-6L4,12v6zM10,18h5v-6h-5v6zM16,18h5v-6h-5v6zM10,11h5L15,5h-5v6zM16,5v6h5L21,5h-5z"/>
+ android:pathData="M14.67,5v6.5H9.33V5H14.67zM15.67,11.5H21V5h-5.33V11.5zM14.67,19v-6.5H9.33V19H14.67zM15.67,12.5V19H21v-6.5H15.67zM8.33,12.5H3V19h5.33V12.5zM8.33,11.5V5H3v6.5H8.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_quilt.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_quilt.xml
index f128c20..bf98fe5 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_quilt.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_quilt.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M10,18h5v-6h-5v6zM4,18h5L9,5L4,5v13zM16,18h5v-6h-5v6zM10,5v6h11L21,5L10,5z"/>
+ android:pathData="M21,5v6.5H9.33V5H21zM14.67,19v-6.5H9.33V19H14.67zM15.67,12.5V19H21v-6.5H15.67zM8.33,19V5H3v14H8.33z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_stream.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_stream.xml
index 3906c772..15d249d 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_stream.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_stream.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,18h17v-6H4v6zM4,5v6h17V5H4z"/>
+ android:pathData="M3,19v-6h18v6H3zM3,5v6h18V5H3z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/view_week.xml b/compose/material/material/icons/generator/raw-icons/sharp/view_week.xml
index bb4d081..fb6e2e5 100644
--- a/compose/material/material/icons/generator/raw-icons/sharp/view_week.xml
+++ b/compose/material/material/icons/generator/raw-icons/sharp/view_week.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M7,5L2,5v14h5L7,5zM21,5h-5v14h5L21,5zM14,5L9,5v14h5L14,5z"/>
+ android:pathData="M7.33,20H2V4h5.33V20zM22,20V4h-5.33v16H22zM14.67,20V4H9.33v16H14.67z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/water_drop.xml b/compose/material/material/icons/generator/raw-icons/sharp/water_drop.xml
new file mode 100644
index 0000000..cccbca8
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/water_drop.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2c-5.33,4.55 -8,8.48 -8,11.8c0,4.98 3.8,8.2 8,8.2s8,-3.22 8,-8.2C20,10.48 17.33,6.55 12,2zM13,18.91C12.68,18.97 12.35,19 12,19c-2.69,0 -4.88,-1.94 -5,-5h1.5c0.08,2.07 1.5,3.5 3.5,3.5c0.35,0 0.69,-0.04 1,-0.13V18.91z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/waving_hand.xml b/compose/material/material/icons/generator/raw-icons/sharp/waving_hand.xml
new file mode 100644
index 0000000..eec0230
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/waving_hand.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M23,17c0,3.31 -2.69,6 -6,6v-1.5c2.48,0 4.5,-2.02 4.5,-4.5H23zM1,7c0,-3.31 2.69,-6 6,-6v1.5C4.52,2.5 2.5,4.52 2.5,7H1zM8.9,3.43L3.42,8.91c-3.22,3.22 -3.22,8.44 0,11.67s8.44,3.22 11.67,0l7.95,-7.95l-1.77,-1.77l-5.3,5.3l-0.71,-0.71l7.42,-7.42l-1.77,-1.77l-6.72,6.72l-0.71,-0.71l7.78,-7.78L19.5,2.73l-7.78,7.78L11.02,9.8l6.36,-6.36l-1.77,-1.77l-8.51,8.51c1.22,1.57 1.11,3.84 -0.33,5.28l-0.71,-0.71c1.17,-1.17 1.17,-3.08 0,-4.24l-0.35,-0.35l4.95,-4.95L8.9,3.43z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/sharp/workspace_premium.xml b/compose/material/material/icons/generator/raw-icons/sharp/workspace_premium.xml
new file mode 100644
index 0000000..41420c0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/sharp/workspace_premium.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9.68,13.69L12,11.93l2.31,1.76l-0.88,-2.85L15.75,9h-2.84L12,6.19L11.09,9H8.25l2.31,1.84L9.68,13.69zM20,10c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8c0,2.03 0.76,3.87 2,5.28V23l6,-2l6,2v-7.72C19.24,13.87 20,12.03 20,10zM12,4c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6S8.69,4 12,4z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/ads_click.xml b/compose/material/material/icons/generator/raw-icons/twotone/ads_click.xml
new file mode 100644
index 0000000..79f2284
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/ads_click.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.71,17.99C8.53,17.84 6,15.22 6,12c0,-3.31 2.69,-6 6,-6c3.22,0 5.84,2.53 5.99,5.71l-2.1,-0.63C15.48,9.31 13.89,8 12,8c-2.21,0 -4,1.79 -4,4c0,1.89 1.31,3.48 3.08,3.89L11.71,17.99zM22,12c0,0.3 -0.01,0.6 -0.04,0.9l-1.97,-0.59C20,12.21 20,12.1 20,12c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8s3.58,8 8,8c0.1,0 0.21,0 0.31,-0.01l0.59,1.97C12.6,21.99 12.3,22 12,22C6.48,22 2,17.52 2,12C2,6.48 6.48,2 12,2S22,6.48 22,12zM18.23,16.26L22,15l-10,-3l3,10l1.26,-3.77l4.27,4.27l1.98,-1.98L18.23,16.26z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/airline_stops.xml b/compose/material/material/icons/generator/raw-icons/twotone/airline_stops.xml
new file mode 100644
index 0000000..f3b3692
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/airline_stops.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.21,9.21C15.93,10.78 13.45,13.3 13,17h2v2H9v-2h2c-0.5,-4.5 -4.37,-8 -9,-8V7c4.39,0 8.22,2.55 10,6.3c1.13,-2.43 2.99,-4.25 4.78,-5.52L14,5h7v7L18.21,9.21z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/airlines.xml b/compose/material/material/icons/generator/raw-icons/twotone/airlines.xml
new file mode 100644
index 0000000..28991ae
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/airlines.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.05,6L5.8,18h11.54l2.25,-12H14.05zM14.5,14c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C17,12.88 15.88,14 14.5,14z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.34,18H5.8l8.25,-12h5.54L17.34,18zM13,4L2,20h17l3,-16H13zM14.5,9c-1.38,0 -2.5,1.12 -2.5,2.5s1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5S15.88,9 14.5,9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/android.xml b/compose/material/material/icons/generator/raw-icons/twotone/android.xml
index bf91766..28c533f 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/android.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/android.xml
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71s-0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
+ android:pathData="M17.6,9.48l1.84,-3.18c0.16,-0.31 0.04,-0.69 -0.26,-0.85c-0.29,-0.15 -0.65,-0.06 -0.83,0.22l-1.88,3.24c-2.86,-1.21 -6.08,-1.21 -8.94,0L5.65,5.67c-0.19,-0.29 -0.58,-0.38 -0.87,-0.2C4.5,5.65 4.41,6.01 4.56,6.3L6.4,9.48C3.3,11.25 1.28,14.44 1,18h22C22.72,14.44 20.7,11.25 17.6,9.48zM7,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25S8.25,13.31 8.25,14C8.25,14.69 7.69,15.25 7,15.25zM17,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25C18.25,14.69 17.69,15.25 17,15.25z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/apps_outage.xml b/compose/material/material/icons/generator/raw-icons/twotone/apps_outage.xml
new file mode 100644
index 0000000..bd84f8b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/apps_outage.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4,8h4V4H4V8zM10,20h4v-4h-4V20zM4,20h4v-4H4V20zM4,14h4v-4H4V14zM10,14h4v-4h-4V14zM16,20h4v-4h-4V20zM19,0c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S21.76,0 19,0zM19.5,8h-1V7h1V8zM19.5,6h-1V2h1V6zM16,14h4v-2.07C19.67,11.98 19.34,12 19,12c-1.07,0 -2.09,-0.24 -3,-0.68V14zM10,4v4h2.68C12.24,7.09 12,6.07 12,5c0,-0.34 0.02,-0.67 0.07,-1H10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/area_chart.xml b/compose/material/material/icons/generator/raw-icons/twotone/area_chart.xml
new file mode 100644
index 0000000..a32e449
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/area_chart.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,16.95l-7,-5.45l-4,5.5l-3,-2.4l0,-3.6l2.44,1.83l4.96,-6.95l3.9,3.12l2.7,0z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17,7l-5,-4l-5,7L3,7v13h18V7H17zM19,16.95l-7,-5.45L8,17l-3,-2.4V11l2.44,1.83l4.96,-6.95L16.3,9H19V16.95z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/arrow_forward_ios.xml b/compose/material/material/icons/generator/raw-icons/twotone/arrow_forward_ios.xml
index f9d6a55..a71005d 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/arrow_forward_ios.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/arrow_forward_ios.xml
@@ -7,5 +7,5 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.49,20.13l1.77,1.77 9.9,-9.9 -9.9,-9.9 -1.77,1.77L14.62,12l-8.13,8.13z"/>
+ android:pathData="M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/back_hand.xml b/compose/material/material/icons/generator/raw-icons/twotone/back_hand.xml
new file mode 100644
index 0000000..08dfc43
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/back_hand.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,16c0,3.31 -2.69,6 -6,6h0c-2.61,0 -4.95,-1.59 -5.91,-4.01l-2.6,-6.54l0.53,0.14c0.46,0.12 0.83,0.46 1,0.9L7,15h2V4.5C9,4.22 9.22,4 9.5,4S10,4.22 10,4.5V12h2V2.5C12,2.22 12.22,2 12.5,2S13,2.22 13,2.5V12h2V4c0,-0.28 0.22,-0.5 0.5,-0.5S16,3.72 16,4v8h2V7c0,-0.28 0.22,-0.5 0.5,-0.5S19,6.72 19,7L19,16z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,7c0,-1.38 -1.12,-2.5 -2.5,-2.5c-0.17,0 -0.34,0.02 -0.5,0.05V4c0,-1.38 -1.12,-2.5 -2.5,-2.5c-0.23,0 -0.46,0.03 -0.67,0.09C14.46,0.66 13.56,0 12.5,0c-1.23,0 -2.25,0.89 -2.46,2.06C9.87,2.02 9.69,2 9.5,2C8.12,2 7,3.12 7,4.5v5.89c-0.34,-0.31 -0.76,-0.54 -1.22,-0.66L5.01,9.52c-0.83,-0.23 -1.7,0.09 -2.19,0.83c-0.38,0.57 -0.4,1.31 -0.15,1.95l2.56,6.43C6.49,21.91 9.57,24 13,24h0c4.42,0 8,-3.58 8,-8V7zM19,16c0,3.31 -2.69,6 -6,6h0c-2.61,0 -4.95,-1.59 -5.91,-4.01l-2.6,-6.54l0.53,0.14c0.46,0.12 0.83,0.46 1,0.9L7,15h2V4.5C9,4.22 9.22,4 9.5,4S10,4.22 10,4.5V12h2V2.5C12,2.22 12.22,2 12.5,2S13,2.22 13,2.5V12h2V4c0,-0.28 0.22,-0.5 0.5,-0.5S16,3.72 16,4v8h2V7c0,-0.28 0.22,-0.5 0.5,-0.5S19,6.72 19,7L19,16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/browser_updated.xml b/compose/material/material/icons/generator/raw-icons/twotone/browser_updated.xml
new file mode 100644
index 0000000..44147da
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/browser_updated.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,13v3c0,1.1 -0.9,2 -2,2h-3l1,1v2H6v-2l1,-1H4c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2l8,0v2L4,5v11h16v-3H22zM15,15l-5,-5h4V3h2v7h4L15,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/checklist.xml b/compose/material/material/icons/generator/raw-icons/twotone/checklist.xml
new file mode 100644
index 0000000..64e7ee3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/checklist.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,7h-9v2h9V7zM22,15h-9v2h9V15zM5.54,11L2,7.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,11zM5.54,19L2,15.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L5.54,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/checklist_rtl.xml b/compose/material/material/icons/generator/raw-icons/twotone/checklist_rtl.xml
new file mode 100644
index 0000000..eb4422c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/checklist_rtl.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,7H2v2h9V7zM11,15H2v2h9V15zM16.34,11l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,5.34L16.34,11zM16.34,19l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L22,13.34L16.34,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/co2.xml b/compose/material/material/icons/generator/raw-icons/twotone/co2.xml
new file mode 100644
index 0000000..28a144a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/co2.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,9h-3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-4C15,9.45 14.55,9 14,9zM13.5,13.5h-2v-3h2V13.5zM8,13v1c0,0.55 -0.45,1 -1,1H4c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v1H6.5v-0.5h-2v3h2V13H8zM20.5,15.5h-2v1h3V18H17v-2.5c0,-0.55 0.45,-1 1,-1h2v-1h-3V12h3.5c0.55,0 1,0.45 1,1v1.5C21.5,15.05 21.05,15.5 20.5,15.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/comments_disabled.xml b/compose/material/material/icons/generator/raw-icons/twotone/comments_disabled.xml
new file mode 100644
index 0000000..971fa9a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/comments_disabled.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.83,4H20v12h-1.17l-2,-2H18v-2h-3.17l-1,-1H18V9h-6.17l-1,-1H18V6H8.83L6.83,4zM13.17,16l-2,-2H6v-2h3.17l-1,-1H6V9h0.17L4,6.83V16H13.17z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.83,16H20V4H6.83l-2,-2H20c1.1,0 2,0.9 2,2l0,15.17L18.83,16zM18,6H8.83l2,2H18V6zM18,9h-6.17l2,2H18V9zM18,14v-2h-3.17l2,2H18zM21.9,21.9l-1.41,1.41L15.17,18H4c-1.1,0 -2,-0.9 -2,-2V4.83L0.69,3.51L2.1,2.1L21.9,21.9zM13.17,16l-2,-2H6v-2h3.17l-1,-1H6V9h0.17L4,6.83V16H13.17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/compost.xml b/compose/material/material/icons/generator/raw-icons/twotone/compost.xml
new file mode 100644
index 0000000..b06253a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/compost.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.87,11.81c-0.23,-0.38 -0.37,-0.83 -0.37,-1.31C12.5,9.12 13.62,8 15,8l1,0c1.51,0 2,-1 2,-1s0.55,6 -3,6c-0.49,0 -0.94,-0.14 -1.32,-0.38c-0.24,0.64 -0.59,1.76 -0.76,2.96c1.26,0.22 2.28,0.89 2.77,1.77c1.69,-1.17 2.81,-3.13 2.81,-5.35h3c0,5.24 -4.26,9.5 -9.5,9.5S2.5,17.24 2.5,12S6.76,2.5 12,2.5V0l4,4l-4,4V5.5c-3.58,0 -6.5,2.92 -6.5,6.5c0,2.21 1.11,4.17 2.81,5.35c0.51,-0.92 1.63,-1.62 2.98,-1.8c-0.09,-0.69 -0.26,-1.42 -0.49,-2.03C10.45,13.82 10,14 9.5,14c-1.1,0 -2,-0.9 -2,-2v-0.99c0,-0.56 -0.19,-1.09 -0.5,-1.51c0,0 4.45,-0.23 4.5,2.5c0,0.29 -0.06,0.56 -0.17,0.8C10.91,12.48 10.47,12.2 10,12c0.58,0.43 1.37,1.37 2,2.6c0.67,-1.62 1.68,-3.27 3,-4.6C14.24,10.52 13.53,11.12 12.87,11.81z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/connecting_airports.xml b/compose/material/material/icons/generator/raw-icons/twotone/connecting_airports.xml
new file mode 100644
index 0000000..12357c5
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/connecting_airports.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.4,17l1.3,4.4h-1.1L13,17h-3c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1h3l2.6,-4.4h1.1L15.4,15h2.85L19,14h1l-0.6,2l0.6,2h-1l-0.75,-1H15.4zM5.75,7L5,6H4l0.6,2L4,10h1l0.75,-1H8.6l-1.3,4.4h1.1L11,9h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L8.4,2.6H7.3L8.6,7H5.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/cruelty_free.xml b/compose/material/material/icons/generator/raw-icons/twotone/cruelty_free.xml
new file mode 100644
index 0000000..5f02d64
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/cruelty_free.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.88,4.03C16.94,4.2 17,4.51 17,5c0,2.84 -1.11,5.24 -2.07,6.78c-0.38,-0.26 -0.83,-0.48 -1.4,-0.62C13.77,6.64 15.97,4.33 16.88,4.03zM7,5c0,-0.49 0.06,-0.8 0.12,-0.97c0.91,0.3 3.11,2.61 3.36,7.13c-0.58,0.14 -1.03,0.35 -1.4,0.62C8.11,10.24 7,7.84 7,5zM16,15.77c-0.44,-0.36 -0.61,-0.52 -1.3,-1.37C13.94,13.45 13.61,13 12,13s-1.94,0.45 -2.7,1.4c-0.69,0.85 -0.86,1.01 -1.3,1.37c-0.57,0.49 -1,1.03 -1,1.73C7,18.88 8.12,20 9.5,20c1,0 1.8,-0.33 2.22,-0.56C11.3,19.26 11,18.73 11,18.5c0,-0.28 0.45,-0.5 1,-0.5s1,0.22 1,0.5c0,0.23 -0.3,0.76 -0.72,0.94C12.7,19.67 13.5,20 14.5,20c1.38,0 2.5,-1.12 2.5,-2.5C17,16.8 16.57,16.26 16,15.77zM10.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S11,15.59 11,16C11,16.41 10.78,16.75 10.5,16.75zM13.5,16.75c-0.28,0 -0.5,-0.34 -0.5,-0.75c0,-0.41 0.22,-0.75 0.5,-0.75S14,15.59 14,16C14,16.41 13.78,16.75 13.5,16.75z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17,14c-0.24,-0.24 -0.44,-0.49 -0.65,-0.75C17.51,11.5 19,8.56 19,5c0,-1.95 -0.74,-3 -2,-3c-1.54,0 -3.96,2.06 -5,5.97C10.96,4.06 8.54,2 7,2C5.74,2 5,3.05 5,5c0,3.56 1.49,6.5 2.65,8.25C7.44,13.51 7.24,13.76 7,14c-0.25,0.25 -2,1.39 -2,3.5C5,19.98 7.02,22 9.5,22c1.5,0 2.5,-0.5 2.5,-0.5s1,0.5 2.5,0.5c2.48,0 4.5,-2.02 4.5,-4.5C19,15.39 17.25,14.25 17,14zM16.88,4.03C16.94,4.2 17,4.51 17,5c0,2.84 -1.11,5.24 -2.07,6.78c-0.38,-0.26 -0.83,-0.48 -1.4,-0.62C13.77,6.64 15.97,4.33 16.88,4.03zM7,5c0,-0.49 0.06,-0.8 0.12,-0.97c0.91,0.3 3.11,2.61 3.36,7.13c-0.58,0.14 -1.03,0.35 -1.4,0.62C8.11,10.24 7,7.84 7,5zM14.5,20c-1,0 -1.8,-0.33 -2.22,-0.56C12.7,19.26 13,18.73 13,18.5c0,-0.28 -0.45,-0.5 -1,-0.5s-1,0.22 -1,0.5c0,0.23 0.3,0.76 0.72,0.94C11.3,19.67 10.5,20 9.5,20C8.12,20 7,18.88 7,17.5c0,-0.7 0.43,-1.24 1,-1.73c0.44,-0.36 0.61,-0.52 1.3,-1.37c0.76,-0.95 1.09,-1.4 2.7,-1.4s1.94,0.45 2.7,1.4c0.69,0.85 0.86,1.01 1.3,1.37c0.57,0.49 1,1.03 1,1.73C17,18.88 15.88,20 14.5,20zM14,16c0,0.41 -0.22,0.75 -0.5,0.75S13,16.41 13,16c0,-0.41 0.22,-0.75 0.5,-0.75S14,15.59 14,16zM11,16c0,0.41 -0.22,0.75 -0.5,0.75S10,16.41 10,16c0,-0.41 0.22,-0.75 0.5,-0.75S11,15.59 11,16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/data_exploration.xml b/compose/material/material/icons/generator/raw-icons/twotone/data_exploration.xml
new file mode 100644
index 0000000..013f2c8
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/data_exploration.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,20c-2.89,0 -5.43,-1.54 -6.83,-3.84l2.95,-2.95L11.41,16L16,11.42V13h2V8h-5v2h1.58l-3.28,3.28L8,10.5l-3.69,3.7C4.11,13.5 4,12.76 4,12c0,-4.41 3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM19.5,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.05,20.5 19.5,20.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10h8c1.1,0 2,-0.9 2,-2v-8C22,6.48 17.52,2 12,2zM12,20c-2.89,0 -5.43,-1.54 -6.83,-3.84l2.95,-2.95L11.41,16L16,11.42V13h2V8h-5v2h1.58l-3.28,3.28L8,10.5l-3.69,3.7C4.11,13.5 4,12.76 4,12c0,-4.41 3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM19.5,20.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S20.05,20.5 19.5,20.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/disabled_visible.xml b/compose/material/material/icons/generator/raw-icons/twotone/disabled_visible.xml
new file mode 100644
index 0000000..7f21767
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/disabled_visible.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17,15c-1.95,0 -3.76,0.98 -4.75,2.5C13.24,19.02 15.05,20 17,20s3.76,-0.98 4.75,-2.5C20.76,15.98 18.95,15 17,15zM17,19c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C18.5,18.33 17.83,19 17,19z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17,15c1.95,0 3.76,0.98 4.75,2.5C20.76,19.02 18.95,20 17,20s-3.76,-0.98 -4.75,-2.5C13.24,15.98 15.05,15 17,15zM17,13c-3.18,0 -5.9,1.87 -7,4.5c1.1,2.63 3.82,4.5 7,4.5s5.9,-1.87 7,-4.5C22.9,14.87 20.18,13 17,13zM17,19c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.17,16 17,16s1.5,0.67 1.5,1.5S17.83,19 17,19zM21.99,12.34C22,12.23 22,12.11 22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12c0,5.17 3.93,9.43 8.96,9.95c-0.93,-0.73 -1.72,-1.64 -2.32,-2.68C5.9,18 4,15.22 4,12c0,-1.85 0.63,-3.55 1.69,-4.9l5.66,5.66c0.56,-0.4 1.17,-0.73 1.82,-1L7.1,5.69C8.45,4.63 10.15,4 12,4c4.24,0 7.7,3.29 7.98,7.45C20.69,11.67 21.37,11.97 21.99,12.34z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/document_scanner.xml b/compose/material/material/icons/generator/raw-icons/twotone/document_scanner.xml
new file mode 100644
index 0000000..a1fcfdf
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/document_scanner.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,6v12h10V6H7zM15,16H9v-2h6V16zM15,13H9v-2h6V13zM15,10H9V8h6V10z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,3H4v3H2V1h5V3zM22,6V1h-5v2h3v3H22zM7,21H4v-3H2v5h5V21zM20,18v3h-3v2h5v-5H20zM17,6H7v12h10V6zM19,18c0,1.1 -0.9,2 -2,2H7c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10c1.1,0 2,0.9 2,2V18zM15,8H9v2h6V8zM15,11H9v2h6V11zM15,14H9v2h6V14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/draw.xml b/compose/material/material/icons/generator/raw-icons/twotone/draw.xml
new file mode 100644
index 0000000..5a09a34
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/draw.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.61,11.81l-7.2,7.19l-1.41,0l0,-1.41l7.19,-7.2z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.85,10.39l1.06,-1.06c0.78,-0.78 0.78,-2.05 0,-2.83L18.5,5.09c-0.78,-0.78 -2.05,-0.78 -2.83,0l-1.06,1.06L18.85,10.39zM14.61,11.81L7.41,19H6v-1.41l7.19,-7.19L14.61,11.81zM13.19,7.56L4,16.76V21h4.24l9.19,-9.19L13.19,7.56L13.19,7.56zM19,17.5c0,2.19 -2.54,3.5 -5,3.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1c1.54,0 3,-0.73 3,-1.5c0,-0.47 -0.48,-0.87 -1.23,-1.2l1.48,-1.48C18.32,15.45 19,16.29 19,17.5zM4.58,13.35C3.61,12.79 3,12.06 3,11c0,-1.8 1.89,-2.63 3.56,-3.36C7.59,7.18 9,6.56 9,6c0,-0.41 -0.78,-1 -2,-1C5.74,5 5.2,5.61 5.17,5.64C4.82,6.05 4.19,6.1 3.77,5.76C3.36,5.42 3.28,4.81 3.62,4.38C3.73,4.24 4.76,3 7,3c2.24,0 4,1.32 4,3c0,1.87 -1.93,2.72 -3.64,3.47C6.42,9.88 5,10.5 5,11c0,0.31 0.43,0.6 1.07,0.86L4.58,13.35z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/drive_file_move_rtl.xml b/compose/material/material/icons/generator/raw-icons/twotone/drive_file_move_rtl.xml
new file mode 100644
index 0000000..219e4f7
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/drive_file_move_rtl.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.17,8l-2,-2H4v12h16V8H11.17zM16,14h-4v3l-4,-4l4,-4v3h4V14z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,6h-8l-2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM20,18H4V6h5.17l2,2H20V18zM12,17l-4,-4l4,-4v3h4v2h-4V17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/edit_calendar.xml b/compose/material/material/icons/generator/raw-icons/twotone/edit_calendar.xml
new file mode 100644
index 0000000..bf8fb8d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/edit_calendar.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,6h14v2h-14z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,10h14v2h2V6c0,-1.1 -0.9,-2 -2,-2h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h7v-2H5V10zM5,6h14v2H5V6zM22.84,16.28l-0.71,0.71l-2.12,-2.12l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71C23.23,15.26 23.23,15.89 22.84,16.28zM19.3,15.58l2.12,2.12l-5.3,5.3H14v-2.12L19.3,15.58z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/edit_note.xml b/compose/material/material/icons/generator/raw-icons/twotone/edit_note.xml
new file mode 100644
index 0000000..1641196
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/edit_note.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/emergency.xml b/compose/material/material/icons/generator/raw-icons/twotone/emergency.xml
new file mode 100644
index 0000000..00a78ed
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/emergency.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.43,16.87l-4.68,-2.7C13.42,13.97 13,14.21 13,14.6V20h-2v-5.4c0,-0.38 -0.42,-0.63 -0.75,-0.43l-4.68,2.7l-1,-1.73l4.68,-2.7c0.33,-0.19 0.33,-0.67 0,-0.87l-4.68,-2.7l1,-1.73l4.68,2.7C10.58,10.03 11,9.79 11,9.4V4h2v5.4c0,0.38 0.42,0.63 0.75,0.43l4.68,-2.7l1,1.73l-4.68,2.7c-0.33,0.19 -0.33,0.67 0,0.87l4.68,2.7L18.43,16.87z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21.29,13.9L18,12l3.29,-1.9c0.48,-0.28 0.64,-0.89 0.37,-1.37l-2,-3.46c-0.28,-0.48 -0.89,-0.64 -1.37,-0.37L15,6.8V3c0,-0.55 -0.45,-1 -1,-1h-4C9.45,2 9,2.45 9,3v3.8L5.71,4.9C5.23,4.63 4.62,4.79 4.34,5.27l-2,3.46C2.06,9.21 2.23,9.82 2.71,10.1L6,12l-3.29,1.9c-0.48,0.28 -0.64,0.89 -0.37,1.37l2,3.46c0.28,0.48 0.89,0.64 1.37,0.37L9,17.2V21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-3.8l3.29,1.9c0.48,0.28 1.09,0.11 1.37,-0.37l2,-3.46C21.94,14.79 21.77,14.18 21.29,13.9zM18.43,16.87l-4.68,-2.7C13.42,13.97 13,14.21 13,14.6V20h-2v-5.4c0,-0.38 -0.42,-0.63 -0.75,-0.43l-4.68,2.7l-1,-1.73l4.68,-2.7c0.33,-0.19 0.33,-0.67 0,-0.87l-4.68,-2.7l1,-1.73l4.68,2.7C10.58,10.03 11,9.79 11,9.4V4h2v5.4c0,0.38 0.42,0.63 0.75,0.43l4.68,-2.7l1,1.73l-4.68,2.7c-0.33,0.19 -0.33,0.67 0,0.87l4.68,2.7L18.43,16.87z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/expand_circle_down.xml b/compose/material/material/icons/generator/raw-icons/twotone/expand_circle_down.xml
new file mode 100644
index 0000000..b297e4ac
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/expand_circle_down.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8s8,-3.58 8,-8S16.42,4 12,4zM12,15.5L7.5,11l1.42,-1.41L12,12.67l3.08,-3.08L16.5,11L12,15.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.08,9.59L12,12.67L8.92,9.59L7.5,11l4.5,4.5l4.5,-4.5L15.08,9.59zM12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/fitbit.xml b/compose/material/material/icons/generator/raw-icons/twotone/fitbit.xml
new file mode 100644
index 0000000..da71490
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/fitbit.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.89,13.89c1.04,0 1.89,-0.85 1.89,-1.89s-0.85,-1.89 -1.89,-1.89C18.85,10.11 18,10.96 18,12S18.85,13.89 19.89,13.89zM15.65,13.68c0.93,0 1.68,-0.75 1.68,-1.68s-0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68S14.72,13.68 15.65,13.68zM15.65,9.42c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,8.67 14.72,9.42 15.65,9.42zM15.65,17.93c0.93,0 1.68,-0.75 1.68,-1.68c0,-0.93 -0.75,-1.68 -1.68,-1.68c-0.93,0 -1.68,0.75 -1.68,1.68C13.97,17.17 14.72,17.93 15.65,17.93zM11.41,13.47c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,13.47 11.41,13.47zM11.41,9.21c0.81,0 1.47,-0.66 1.47,-1.47s-0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,9.21 11.41,9.21zM11.41,17.73c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,17.07 10.59,17.73 11.41,17.73zM11.41,22c0.81,0 1.47,-0.66 1.47,-1.47c0,-0.81 -0.66,-1.47 -1.47,-1.47c-0.81,0 -1.47,0.66 -1.47,1.47C9.93,21.34 10.59,22 11.41,22zM11.41,4.94c0.81,0 1.47,-0.66 1.47,-1.47S12.22,2 11.41,2c-0.81,0 -1.47,0.66 -1.47,1.47S10.59,4.94 11.41,4.94zM7.16,13.26c0.7,0 1.26,-0.57 1.26,-1.26s-0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26S6.46,13.26 7.16,13.26zM7.16,17.51c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,16.94 6.46,17.51 7.16,17.51zM7.16,9.02c0.7,0 1.26,-0.57 1.26,-1.26c0,-0.7 -0.57,-1.26 -1.26,-1.26c-0.7,0 -1.26,0.57 -1.26,1.26C5.9,8.45 6.46,9.02 7.16,9.02zM3.29,13.05c0.58,0 1.05,-0.47 1.05,-1.05s-0.47,-1.05 -1.05,-1.05c-0.58,0 -1.05,0.47 -1.05,1.05S2.71,13.05 3.29,13.05z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/flight_class.xml b/compose/material/material/icons/generator/raw-icons/twotone/flight_class.xml
new file mode 100644
index 0000000..64f287b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/flight_class.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,6h2v5h-2z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,4h-2c-1.1,0 -2,0.9 -2,2v5c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2V6C18,4.9 17.1,4 16,4zM16,11h-2V6h2V11zM9.5,16H18v2H9.49c-0.88,0 -1.66,-0.58 -1.92,-1.43L5,8V4h2v4L9.5,16zM8,19h10v2H8V19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/free_cancellation.xml b/compose/material/material/icons/generator/raw-icons/twotone/free_cancellation.xml
new file mode 100644
index 0000000..87fb577
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/free_cancellation.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,6h14v2h-14z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11.21,20H5V10h14v4.38l2,-2V6c0,-1.1 -0.9,-2 -2,-2h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h8.21L11.21,20zM5,6h14v2H5V6zM16.54,22.5L13,18.96l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L16.54,22.5zM10.41,14L12,15.59L10.59,17L9,15.41L7.41,17L6,15.59L7.59,14L6,12.41L7.41,11L9,12.59L10.59,11L12,12.41L10.41,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/front_hand.xml b/compose/material/material/icons/generator/raw-icons/twotone/front_hand.xml
new file mode 100644
index 0000000..4059b2e
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/front_hand.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,15.5c0,3.59 -2.91,6.5 -6.5,6.5S6,19.09 6,15.5V7c0,-0.28 0.22,-0.5 0.5,-0.5S7,6.72 7,7v5h2V4c0,-0.28 0.22,-0.5 0.5,-0.5S10,3.72 10,4v7h2V2.5C12,2.22 12.22,2 12.5,2S13,2.22 13,2.5V11h2V4.5C15,4.22 15.22,4 15.5,4S16,4.22 16,4.5v8.92c-1.77,0.77 -3,2.53 -3,4.58h2c0,-1.66 1.34,-3 3,-3v-4.5c0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5V15.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.5,8c-0.17,0 -0.34,0.02 -0.5,0.05V4.5C18,3.12 16.88,2 15.5,2c-0.19,0 -0.37,0.02 -0.54,0.06C14.75,0.89 13.73,0 12.5,0c-1.06,0 -1.96,0.66 -2.33,1.59C9.96,1.53 9.73,1.5 9.5,1.5C8.12,1.5 7,2.62 7,4v0.55C6.84,4.52 6.67,4.5 6.5,4.5C5.12,4.5 4,5.62 4,7v8.5c0,4.69 3.81,8.5 8.5,8.5s8.5,-3.81 8.5,-8.5v-5C21,9.12 19.88,8 18.5,8zM19,15.5c0,3.59 -2.91,6.5 -6.5,6.5S6,19.09 6,15.5V7c0,-0.28 0.22,-0.5 0.5,-0.5S7,6.72 7,7v5h2V4c0,-0.28 0.22,-0.5 0.5,-0.5S10,3.72 10,4v7h2V2.5C12,2.22 12.22,2 12.5,2S13,2.22 13,2.5V11h2V4.5C15,4.22 15.22,4 15.5,4S16,4.22 16,4.5v8.92c-1.77,0.77 -3,2.53 -3,4.58h2c0,-1.66 1.34,-3 3,-3v-4.5c0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5V15.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/generating_tokens.xml b/compose/material/material/icons/generator/raw-icons/twotone/generating_tokens.xml
new file mode 100644
index 0000000..8532a52
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/generating_tokens.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6s6,-2.69 6,-6S12.31,6 9,6zM12,10.5h-2v5H8v-5H6V9h6V10.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8C17,7.58 13.42,4 9,4zM9,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6s6,2.69 6,6S12.31,18 9,18zM12,10.5h-2v5H8v-5H6V9h6V10.5zM20.25,3.75L23,5l-2.75,1.25L19,9l-1.25,-2.75L15,5l2.75,-1.25L19,1L20.25,3.75zM20.25,17.75L23,19l-2.75,1.25L19,23l-1.25,-2.75L15,19l2.75,-1.25L19,15L20.25,17.75z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/gif_box.xml b/compose/material/material/icons/generator/raw-icons/twotone/gif_box.xml
new file mode 100644
index 0000000..d9a05b1
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/gif_box.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,5v14h14V5H5zM9.5,13v-1h1v1c0,0.55 -0.45,1 -1,1h-1c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1h1c0.55,0 1,0.45 1,1h-2v2H9.5zM12.5,14h-1v-4h1V14zM16.5,11h-2v0.5H16v1h-1.5V14h-1v-4h3V11z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,19H5V5h14V19zM5,3C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2H5zM11.5,14h1v-4h-1V14zM13.5,14h1v-1.5H16v-1h-1.5V11h2v-1h-3V14zM9.5,12v1h-1v-2h2c0,-0.55 -0.45,-1 -1,-1h-1c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-1H9.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/group_add.xml b/compose/material/material/icons/generator/raw-icons/twotone/group_add.xml
index c809157..86e2800 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/group_add.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/group_add.xml
@@ -6,18 +6,27 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,15v-3h3v-2H5V7H3v3H0v2h3v3z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,8.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
+ android:pathData="M8,15c-2.7,0 -5.8,1.29 -6,2.01V18h12v-1C13.8,16.29 10.7,15 8,15z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M7.34,17h9.32c-0.84,-0.58 -2.87,-1.25 -4.66,-1.25s-3.82,0.67 -4.66,1.25z"
+ android:pathData="M8,8m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,12c1.93,0 3.5,-1.57 3.5,-3.5S13.93,5 12,5 8.5,6.57 8.5,8.5 10.07,12 12,12zM12,7c0.83,0 1.5,0.67 1.5,1.5S12.83,10 12,10s-1.5,-0.67 -1.5,-1.5S11.17,7 12,7zM12,13.75c-2.34,0 -7,1.17 -7,3.5L5,19h14v-1.75c0,-2.33 -4.66,-3.5 -7,-3.5zM7.34,17c0.84,-0.58 2.87,-1.25 4.66,-1.25s3.82,0.67 4.66,1.25L7.34,17zM17,12c1.93,0 3.5,-1.57 3.5,-3.5S18.93,5 17,5c-0.24,0 -0.48,0.02 -0.71,0.07 0.76,0.94 1.21,2.13 1.21,3.43 0,1.3 -0.47,2.48 -1.23,3.42 0.24,0.05 0.48,0.08 0.73,0.08zM19.32,14.02c1,0.81 1.68,1.87 1.68,3.23L21,19h3v-1.75c0,-1.69 -2.44,-2.76 -4.68,-3.23z"/>
+ android:pathData="M22,9l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0l0,-2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4S4,5.79 4,8S5.79,12 8,12zM8,6c1.1,0 2,0.9 2,2s-0.9,2 -2,2S6,9.1 6,8S6.9,6 8,6z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13zM14,18H2v-0.99C2.2,16.29 5.3,15 8,15s5.8,1.29 6,2V18z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/group_off.xml b/compose/material/material/icons/generator/raw-icons/twotone/group_off.xml
new file mode 100644
index 0000000..325da07
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/group_off.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10.99,8.16C11,8.11 11,8.06 11,8c0,-1.1 -0.9,-2 -2,-2C8.94,6 8.89,6 8.84,6.01L10.99,8.16zM9,15c-2.7,0 -5.8,1.29 -6,2.01V18h12v-0.17l-2.11,-2.11C11.76,15.31 10.33,15 9,15z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,8c0,-1.42 -0.5,-2.73 -1.33,-3.76C14.09,4.1 14.53,4 15,4c2.21,0 4,1.79 4,4s-1.79,4 -4,4c-0.06,0 -0.12,0 -0.18,0l-0.77,-0.77C14.65,10.29 15,9.18 15,8zM22.83,20H23v-3c0,-2.18 -3.58,-3.47 -6.34,-3.87c1.1,0.75 1.95,1.71 2.23,2.94L22.83,20zM9,6C8.94,6 8.89,6 8.84,6.01l-1.6,-1.6C7.77,4.15 8.37,4 9,4c2.21,0 4,1.79 4,4c0,0.63 -0.15,1.23 -0.41,1.76l-1.6,-1.6C11,8.11 11,8.06 11,8C11,6.9 10.1,6 9,6zM9.17,12C9.11,12 9.06,12 9,12c-2.21,0 -4,-1.79 -4,-4c0,-0.06 0,-0.11 0,-0.17L0.69,3.51L2.1,2.1l19.8,19.8l-1.41,1.41L17,19.83V20H1v-3c0,-2.66 5.33,-4 8,-4c0.37,0 0.8,0.03 1.25,0.08L9.17,12zM9,15c-2.7,0 -5.8,1.29 -6,2.01V18h12v-0.17l-2.11,-2.11C11.76,15.31 10.33,15 9,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/group_remove.xml b/compose/material/material/icons/generator/raw-icons/twotone/group_remove.xml
new file mode 100644
index 0000000..cbfb9c2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/group_remove.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,10c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S9.1,10 8,10zM14,18H2v-0.99C2.2,16.29 5.3,15 8,15s5.8,1.29 6,2V18z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,9v2h-6V9H24zM8,4C5.79,4 4,5.79 4,8s1.79,4 4,4s4,-1.79 4,-4S10.21,4 8,4zM8,10c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S9.1,10 8,10zM8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13zM14,18H2v-0.99C2.2,16.29 5.3,15 8,15s5.8,1.29 6,2V18zM12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05zM16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/hotel_class.xml b/compose/material/material/icons/generator/raw-icons/twotone/hotel_class.xml
new file mode 100644
index 0000000..561af9c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/hotel_class.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,8.89l0.94,3.11l2.82,0l-2.27,1.62l0.93,3.01l-2.42,-1.84l-2.42,1.84l0.93,-3.01l-2.27,-1.62l2.82,0z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,8.89L11.94,12h2.82l-2.27,1.62l0.93,3.01L11,14.79l-2.42,1.84l0.93,-3.01L7.24,12h2.82L11,8.89zM8.58,10H1l6.17,4.41L4.83,22L11,17.31L17.18,22l-2.35,-7.59L21,10h-7.58L11,2L8.58,10zM21.36,22l-1.86,-6.01L23.68,13h-3.44l-3.08,2.2l1.46,4.72L21.36,22zM17,8l-1.82,-6l-1.04,3.45L14.91,8H17z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/hub.xml b/compose/material/material/icons/generator/raw-icons/twotone/hub.xml
new file mode 100644
index 0000000..0bb1aed
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/hub.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,10.5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C4,10.05 3.55,10.5 3,10.5zM6,21c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C7,20.55 6.55,21 6,21zM11,3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1c0,0.55 -0.45,1 -1,1S11,3.55 11,3zM12,15c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C14.5,13.88 13.38,15 12,15zM18,19c0.55,0 1,0.45 1,1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1C17,19.45 17.45,19 18,19zM21,10.5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C22,10.05 21.55,10.5 21,10.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,6.5c-1.66,0 -3,1.34 -3,3c0,0.07 0,0.14 0.01,0.21l-2.03,0.68c-0.64,-1.21 -1.82,-2.09 -3.22,-2.32V5.91C14.04,5.57 15,4.4 15,3c0,-1.66 -1.34,-3 -3,-3S9,1.34 9,3c0,1.4 0.96,2.57 2.25,2.91v2.16c-1.4,0.23 -2.58,1.11 -3.22,2.32L5.99,9.71C6,9.64 6,9.57 6,9.5c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3s1.34,3 3,3c1.06,0 1.98,-0.55 2.52,-1.37l2.03,0.68c-0.2,1.29 0.17,2.66 1.09,3.69l-1.41,1.77C6.85,17.09 6.44,17 6,17c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3c0,-0.68 -0.22,-1.3 -0.6,-1.8l1.41,-1.77c1.36,0.76 3.02,0.75 4.37,0l1.41,1.77C15.22,18.7 15,19.32 15,20c0,1.66 1.34,3 3,3s3,-1.34 3,-3s-1.34,-3 -3,-3c-0.44,0 -0.85,0.09 -1.23,0.26l-1.41,-1.77c0.93,-1.04 1.29,-2.4 1.09,-3.69l2.03,-0.68c0.53,0.82 1.46,1.37 2.52,1.37c1.66,0 3,-1.34 3,-3S22.66,6.5 21,6.5zM3,10.5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C4,10.05 3.55,10.5 3,10.5zM6,21c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C7,20.55 6.55,21 6,21zM11,3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1c0,0.55 -0.45,1 -1,1S11,3.55 11,3zM12,15c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C14.5,13.88 13.38,15 12,15zM18,19c0.55,0 1,0.45 1,1c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1C17,19.45 17.45,19 18,19zM21,10.5c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C22,10.05 21.55,10.5 21,10.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/incomplete_circle.xml b/compose/material/material/icons/generator/raw-icons/twotone/incomplete_circle.xml
new file mode 100644
index 0000000..e7e6e41
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/incomplete_circle.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12c0,5.52 -4.48,10 -10,10S2,17.52 2,12c0,-2.76 1.12,-5.26 2.93,-7.07L12,12V2C17.52,2 22,6.48 22,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/interests.xml b/compose/material/material/icons/generator/raw-icons/twotone/interests.xml
new file mode 100644
index 0000000..c3bc050
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/interests.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.02,19c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S8.12,19 7.02,19zM19,19h-4v-4h4V19zM7,6.12L8.6,9H5.4L7,6.12zM17,8.35c-1.45,-1.22 -3,-2.4 -3,-3.1c0,-0.43 0.35,-0.75 0.75,-0.75c0.31,0 0.52,0.17 0.73,0.37L17,6.3l1.52,-1.43c0.21,-0.2 0.42,-0.37 0.73,-0.37c0.4,0 0.75,0.32 0.75,0.75C20,5.95 18.45,7.13 17,8.35z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.02,13c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S9.23,13 7.02,13zM7.02,19c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S8.12,19 7.02,19zM13,13v8h8v-8H13zM19,19h-4v-4h4V19zM7,2l-5,9h10L7,2zM7,6.12L8.6,9H5.4L7,6.12zM19.25,2.5c-1.06,0 -1.81,0.56 -2.25,1.17c-0.44,-0.61 -1.19,-1.17 -2.25,-1.17C13.19,2.5 12,3.78 12,5.25c0,2 2.42,3.42 5,5.75c2.58,-2.33 5,-3.75 5,-5.75C22,3.78 20.81,2.5 19.25,2.5zM17,8.35c-1.45,-1.22 -3,-2.4 -3,-3.1c0,-0.43 0.35,-0.75 0.75,-0.75c0.31,0 0.52,0.17 0.73,0.37L17,6.3l1.52,-1.43c0.21,-0.2 0.42,-0.37 0.73,-0.37c0.4,0 0.75,0.32 0.75,0.75C20,5.95 18.45,7.13 17,8.35z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/interpreter_mode.xml b/compose/material/material/icons/generator/raw-icons/twotone/interpreter_mode.xml
new file mode 100644
index 0000000..a7a8ab3
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/interpreter_mode.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.52,15.01C15.35,15 15.18,15 15,15c-2.37,0 -4.29,0.73 -5.48,1.34C9.2,16.5 9,16.84 9,17.22V18l7.17,0C15.74,17.26 15.4,16.24 15.52,15.01zM13,8c0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2S13,6.9 13,8z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.5,16.5c-0.83,0 -1.5,-0.67 -1.5,-1.5v-2.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5V15C22,15.83 21.33,16.5 20.5,16.5zM20,20h1c0,0 0,-1.54 0,-1.54c1.69,-0.24 3,-1.7 3,-3.46h-1c0,1.38 -1.12,2.5 -2.5,2.5S18,16.38 18,15h-1c0,1.76 1.31,3.22 3,3.46C20,18.46 20,20 20,20zM9,12c-2.21,0 -4,-1.79 -4,-4c0,-2.21 1.79,-4 4,-4c0.47,0 0.92,0.08 1.34,0.23C9.5,5.26 9,6.57 9,8c0,1.43 0.5,2.74 1.34,3.77C9.92,11.92 9.47,12 9,12zM7.11,13.13C5.79,14.05 5,15.57 5,17.22V20H1v-2.78c0,-1.12 0.61,-2.15 1.61,-2.66C3.85,13.92 5.37,13.37 7.11,13.13zM11,8c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.21 -1.79,4 -4,4S11,10.21 11,8zM13,8c0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2S13,6.9 13,8zM15,15c-2.37,0 -4.29,0.73 -5.48,1.34C9.2,16.5 9,16.84 9,17.22V18l7.17,0c0.5,0.86 1.25,1.56 2.15,2L7,20v-2.78c0,-1.12 0.61,-2.15 1.61,-2.66C10.29,13.7 12.47,13 15,13c0.39,0 0.77,0.02 1.14,0.05c-0.33,0.59 -0.55,1.26 -0.62,1.96C15.35,15 15.18,15 15,15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/kebab_dining.xml b/compose/material/material/icons/generator/raw-icons/twotone/kebab_dining.xml
new file mode 100644
index 0000000..0cc0993d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/kebab_dining.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.5,5C15.22,5 15,4.78 15,4.5S15.22,4 15.5,4h3C18.78,4 19,4.22 19,4.5S18.78,5 18.5,5H15.5zM18.5,16c0.28,0 0.5,0.22 0.5,0.5S18.78,17 18.5,17h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5H18.5zM19,10v1h-4v-1H19zM5.5,5C5.22,5 5,4.78 5,4.5S5.22,4 5.5,4h3C8.78,4 9,4.22 9,4.5S8.78,5 8.5,5H5.5zM8.5,16C8.78,16 9,16.22 9,16.5S8.78,17 8.5,17h-3C5.22,17 5,16.78 5,16.5S5.22,16 5.5,16H8.5zM9,10v1H5v-1H9z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.75,7h0.75C19.88,7 21,5.88 21,4.5C21,3.12 19.88,2 18.5,2h-0.75V1h-1.5v1H15.5C14.12,2 13,3.12 13,4.5C13,5.88 14.12,7 15.5,7h0.75v1H13v5h3.25v1H15.5c-1.38,0 -2.5,1.12 -2.5,2.5c0,1.38 1.12,2.5 2.5,2.5h0.75v4h1.5v-4h0.75c1.38,0 2.5,-1.12 2.5,-2.5c0,-1.38 -1.12,-2.5 -2.5,-2.5h-0.75v-1H21V8h-3.25V7zM15.5,5C15.22,5 15,4.78 15,4.5S15.22,4 15.5,4h3C18.78,4 19,4.22 19,4.5S18.78,5 18.5,5H15.5zM18.5,16c0.28,0 0.5,0.22 0.5,0.5S18.78,17 18.5,17h-3c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5H18.5zM19,10v1h-4v-1H19zM7.75,7H8.5C9.88,7 11,5.88 11,4.5C11,3.12 9.88,2 8.5,2H7.75V1h-1.5v1H5.5C4.12,2 3,3.12 3,4.5C3,5.88 4.12,7 5.5,7h0.75v1H3v5h3.25v1H5.5C4.12,14 3,15.12 3,16.5C3,17.88 4.12,19 5.5,19h0.75v4h1.5v-4H8.5c1.38,0 2.5,-1.12 2.5,-2.5c0,-1.38 -1.12,-2.5 -2.5,-2.5H7.75v-1H11V8H7.75V7zM5.5,5C5.22,5 5,4.78 5,4.5S5.22,4 5.5,4h3C8.78,4 9,4.22 9,4.5S8.78,5 8.5,5H5.5zM8.5,16C8.78,16 9,16.22 9,16.5S8.78,17 8.5,17h-3C5.22,17 5,16.78 5,16.5S5.22,16 5.5,16H8.5zM9,10v1H5v-1H9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/mode_of_travel.xml b/compose/material/material/icons/generator/raw-icons/twotone/mode_of_travel.xml
new file mode 100644
index 0000000..1cc03da
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/mode_of_travel.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.31,18.9c-0.96,1 -2.06,2.03 -3.31,3.1c-5.33,-4.55 -8,-8.48 -8,-11.8C4,5.22 7.8,2 12,2c4,0 7.64,2.92 7.97,7.5l3.53,0L19,14l-4.5,-4.5l3.47,0C17.65,6.24 15.13,4 12,4c-3.35,0 -6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14c0.64,-0.59 1.23,-1.16 1.77,-1.71c-0.17,-0.34 -0.27,-0.72 -0.27,-1.12c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S17.38,19 16,19C15.76,19 15.53,18.97 15.31,18.9z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/new_label.xml b/compose/material/material/icons/generator/raw-icons/twotone/new_label.xml
new file mode 100644
index 0000000..80672d2
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/new_label.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,17l0,-4l-3,0l0,-3l-4,0l0,-3l10,0l3.55,5l-3.55,5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,12l-4.37,6.16C16.26,18.68 15.65,19 15,19h-3l0,-2h3l3.55,-5L15,7H5v3H3V7c0,-1.1 0.9,-2 2,-2h10c0.65,0 1.26,0.31 1.63,0.84L21,12zM10,15H7v-3H5v3H2v2h3v3h2v-3h3V15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/palette.xml b/compose/material/material/icons/generator/raw-icons/twotone/palette.xml
index c12a68f..9f0bfa2 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/palette.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/palette.xml
@@ -6,12 +6,12 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5 0,-0.16 -0.08,-0.28 -0.14,-0.35 -0.41,-0.46 -0.63,-1.05 -0.63,-1.65 0,-1.38 1.12,-2.5 2.5,-2.5L16,15c2.21,0 4,-1.79 4,-4 0,-3.86 -3.59,-7 -8,-7zM6.5,13c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,10 6.5,10s1.5,0.67 1.5,1.5S7.33,13 6.5,13zM9.5,9C8.67,9 8,8.33 8,7.5S8.67,6 9.5,6s1.5,0.67 1.5,1.5S10.33,9 9.5,9zM14.5,9c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,6 14.5,6s1.5,0.67 1.5,1.5S15.33,9 14.5,9zM19,11.5c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5 0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5z"
+ android:pathData="M12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5c0,-0.16 -0.08,-0.28 -0.14,-0.35c-0.41,-0.46 -0.63,-1.05 -0.63,-1.65c0,-1.38 1.12,-2.5 2.5,-2.5H16c2.21,0 4,-1.79 4,-4C20,7.14 16.41,4 12,4zM6.5,13C5.67,13 5,12.33 5,11.5S5.67,10 6.5,10S8,10.67 8,11.5S7.33,13 6.5,13zM9.5,9C8.67,9 8,8.33 8,7.5S8.67,6 9.5,6S11,6.67 11,7.5S10.33,9 9.5,9zM14.5,9C13.67,9 13,8.33 13,7.5S13.67,6 14.5,6S16,6.67 16,7.5S15.33,9 14.5,9zM19,11.5c0,0.83 -0.67,1.5 -1.5,1.5S16,12.33 16,11.5s0.67,-1.5 1.5,-1.5S19,10.67 19,11.5z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10c1.38,0 2.5,-1.12 2.5,-2.5 0,-0.61 -0.23,-1.21 -0.64,-1.67 -0.08,-0.09 -0.13,-0.21 -0.13,-0.33 0,-0.28 0.22,-0.5 0.5,-0.5L16,17c3.31,0 6,-2.69 6,-6 0,-4.96 -4.49,-9 -10,-9zM16,15h-1.77c-1.38,0 -2.5,1.12 -2.5,2.5 0,0.61 0.22,1.19 0.63,1.65 0.06,0.07 0.14,0.19 0.14,0.35 0,0.28 -0.22,0.5 -0.5,0.5 -4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.14 8,7c0,2.21 -1.79,4 -4,4z"/>
+ android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10c1.38,0 2.5,-1.12 2.5,-2.5c0,-0.61 -0.23,-1.21 -0.64,-1.67c-0.08,-0.09 -0.13,-0.21 -0.13,-0.33c0,-0.28 0.22,-0.5 0.5,-0.5H16c3.31,0 6,-2.69 6,-6C22,6.04 17.51,2 12,2zM16,15h-1.77c-1.38,0 -2.5,1.12 -2.5,2.5c0,0.61 0.22,1.19 0.63,1.65c0.06,0.07 0.14,0.19 0.14,0.35c0,0.28 -0.22,0.5 -0.5,0.5c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.14 8,7C20,13.21 18.21,15 16,15z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M6.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/personal_injury.xml b/compose/material/material/icons/generator/raw-icons/twotone/personal_injury.xml
new file mode 100644
index 0000000..274b2cc
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/personal_injury.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4c1.1,0 2,0.9 2,2c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2C10,4.9 10.9,4 12,4zM10.94,20H9.75C9.34,20 9,19.66 9,19.25c0,-0.41 0.34,-0.75 0.75,-0.75h1.89L10.94,20zM18,20h-4.85l2.94,-6.27c0.54,0.2 1.01,0.41 1.4,0.61C17.8,14.5 18,14.84 18,15.22V20zM9.75,22C8.23,22 7,20.77 7,19.25c0,-1.52 1.23,-2.75 2.75,-2.75h2.83l1.55,-3.3C13.47,13.07 12.76,13 12,13c-2.37,0 -4.29,0.73 -5.48,1.34C6.2,14.5 6,14.84 6,15.22V22H9.75z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,10c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S8,3.79 8,6C8,8.21 9.79,10 12,10zM12,4c1.1,0 2,0.9 2,2c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2C10,4.9 10.9,4 12,4zM18.39,12.56C16.71,11.7 14.53,11 12,11c-2.53,0 -4.71,0.7 -6.39,1.56C4.61,13.07 4,14.1 4,15.22V22h2v-6.78c0,-0.38 0.2,-0.72 0.52,-0.88C7.71,13.73 9.63,13 12,13c0.76,0 1.47,0.07 2.13,0.2l-1.55,3.3H9.75C8.23,16.5 7,17.73 7,19.25C7,20.77 8.23,22 9.75,22h2.18H18c1.1,0 2,-0.9 2,-2v-4.78C20,14.1 19.39,13.07 18.39,12.56zM10.94,20H9.75C9.34,20 9,19.66 9,19.25c0,-0.41 0.34,-0.75 0.75,-0.75h1.89L10.94,20zM18,20h-4.85l2.94,-6.27c0.54,0.2 1.01,0.41 1.4,0.61C17.8,14.5 18,14.84 18,15.22V20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/phone_locked.xml b/compose/material/material/icons/generator/raw-icons/twotone/phone_locked.xml
index 9cb4710..c57aeec 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/phone_locked.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/phone_locked.xml
@@ -6,10 +6,18 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6.54,5h-1.5c0.09,1.32 0.34,2.58 0.75,3.79l1.2,-1.21c-0.24,-0.83 -0.39,-1.7 -0.45,-2.58zM15.2,18.21c1.21,0.41 2.48,0.67 3.8,0.76v-1.5c-0.88,-0.07 -1.75,-0.22 -2.6,-0.45l-1.2,1.19z"
+ android:pathData="M20,5V4c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2v1h-1v5h6V5H20zM19,5h-2V4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,17.83c1.29,0.54 2.63,0.89 4,1.07v-2.23l-2.35,-0.47L15,17.83z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M20,15.5c-1.25,0 -2.45,-0.2 -3.57,-0.57 -0.1,-0.03 -0.21,-0.05 -0.31,-0.05 -0.26,0 -0.51,0.1 -0.71,0.29l-2.2,2.2c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l2.2,-2.21c0.28,-0.26 0.36,-0.65 0.25,-1C8.7,6.45 8.5,5.25 8.5,4c0,-0.55 -0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1 0,9.39 7.61,17 17,17 0.55,0 1,-0.45 1,-1v-3.5c0,-0.55 -0.45,-1 -1,-1zM5.03,5h1.5c0.07,0.88 0.22,1.75 0.45,2.58l-1.2,1.21c-0.4,-1.21 -0.66,-2.47 -0.75,-3.79zM19,18.97c-1.32,-0.09 -2.6,-0.35 -3.8,-0.76l1.2,-1.2c0.85,0.24 1.72,0.39 2.6,0.45v1.51zM20,4v-0.5C20,2.12 18.88,1 17.5,1S15,2.12 15,3.5L15,4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1L21,5c0,-0.55 -0.45,-1 -1,-1zM19,4h-3v-0.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5L19,4z"/>
+ android:pathData="M7.33,5H5.1c0.18,1.37 0.53,2.7 1.07,4L7.8,7.35L7.33,5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.2,14.87l-3.67,-0.73c-0.5,-0.1 -0.83,0.2 -0.9,0.27l-2.52,2.5c-2.5,-1.43 -4.57,-3.5 -6,-6l2.5,-2.52c0.23,-0.24 0.33,-0.57 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03C3.17,6.92 4.05,9.63 5.43,12c1.58,2.73 3.85,4.99 6.57,6.57c2.37,1.37 5.08,2.26 7.97,2.43c0.55,0.03 1.03,-0.43 1.03,-1v-4.15C21,15.37 20.66,14.96 20.2,14.87zM5.1,5h2.23L7.8,7.35L6.17,9C5.63,7.7 5.27,6.37 5.1,5zM19,18.9c-1.37,-0.18 -2.7,-0.53 -4,-1.07l1.65,-1.63L19,16.67V18.9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/photo_album.xml b/compose/material/material/icons/generator/raw-icons/twotone/photo_album.xml
index 2e323cf..852c5dc 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/photo_album.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/photo_album.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M13,13l-3,-2.25L7,13L7,4L6,4v16h12L18,4h-5v9zM17,19L7,19l2.5,-3.19 1.78,2.15 2.5,-3.22L17,19z"
+ android:pathData="M16,4v7l-2.5,-1.5L11,11V4H6v16h12V4H16zM7,18l2.38,-3.17L11,17l2.62,-3.5L17,18H7z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M18,2L6,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM9,4h2v5l-1,-0.75L9,9L9,4zM18,20L6,20L6,4h1v9l3,-2.25L13,13L13,4h5v16zM9.5,15.81L7,19h10l-3.22,-4.26 -2.5,3.22z"/>
+ android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM18,20H6V4h5v7l2.5,-1.5L16,11V4h2V20zM13.62,13.5L17,18H7l2.38,-3.17L11,17L13.62,13.5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/pin_end.xml b/compose/material/material/icons/generator/raw-icons/twotone/pin_end.xml
new file mode 100644
index 0000000..070e4b9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/pin_end.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,12V6H4v12h10l0,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h16c1.1,0 2,0.9 2,2v6H20zM19,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c1.66,0 3,-1.34 3,-3S20.66,14 19,14zM14.66,8H9v5.66l2.12,-2.12l2.83,2.83l1.41,-1.41l-2.83,-2.83L14.66,8z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/pin_invoke.xml b/compose/material/material/icons/generator/raw-icons/twotone/pin_invoke.xml
new file mode 100644
index 0000000..6e78fb0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/pin_invoke.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,12v6c0,1.1 -0.9,2 -2,2H4c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h10l0,2H4v12h16v-6H22zM22,7c0,-1.66 -1.34,-3 -3,-3c-1.66,0 -3,1.34 -3,3s1.34,3 3,3C20.66,10 22,8.66 22,7zM11.47,12.12l-2.83,2.83l1.41,1.41l2.83,-2.83L15,15.66V10H9.34L11.47,12.12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/playlist_add_check_circle.xml b/compose/material/material/icons/generator/raw-icons/twotone/playlist_add_check_circle.xml
new file mode 100644
index 0000000..722d033
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/playlist_add_check_circle.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c4.41,0 8,-3.59 8,-8S16.41,4 12,4zM7,7h7v2H7V7zM7,10h7v2H7V10zM10,15H7v-2h3V15zM14.05,18.36l-2.83,-2.83l1.41,-1.41l1.41,1.41L17.59,12L19,13.41L14.05,18.36z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4c4.41,0 8,3.59 8,8s-3.59,8 -8,8s-8,-3.59 -8,-8S7.59,4 12,4zM12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM14,10H7v2h7V10zM14,7H7v2h7V7zM7,15h3v-2H7V15zM19,13.41L17.59,12l-3.54,3.54l-1.41,-1.41l-1.41,1.41l2.83,2.83L19,13.41z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/playlist_add_circle.xml b/compose/material/material/icons/generator/raw-icons/twotone/playlist_add_circle.xml
new file mode 100644
index 0000000..d3745da
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/playlist_add_circle.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8s8,-3.59 8,-8S16.41,4 12,4zM7,7h7v2H7V7zM10,15H7v-2h3V15zM7,12v-2h7v2H7zM17,15v2h-2v-2h-2v-2h2v-2h2v2h2v2H17z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20zM14,10H7v2h7V10zM14,7H7v2h7V7zM7,15h3v-2H7V15zM19,13v2h-2v2h-2v-2h-2v-2h2v-2h2v2H19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/private_connectivity.xml b/compose/material/material/icons/generator/raw-icons/twotone/private_connectivity.xml
new file mode 100644
index 0000000..7801637
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/private_connectivity.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S14.76,7 12,7zM15,14.5c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1v-1c0,-1.21 1.08,-2.18 2.34,-1.97C13.32,7.69 14,8.61 14,9.61v0.89c0.55,0 1,0.45 1,1V14.5zM12.75,13c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75c0,-0.41 0.34,-0.75 0.75,-0.75S12.75,12.59 12.75,13zM13,9.5v1h-2v-1c0,-0.55 0.45,-1 1,-1S13,8.95 13,9.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,7c2.76,0 5,2.24 5,5s-2.24,5 -5,5s-5,-2.24 -5,-5S9.24,7 12,7zM5.07,13c0.49,3.39 3.4,6 6.93,6c3.53,0 6.44,-2.61 6.93,-6L22,13v-2l-3.07,0c-0.49,-3.39 -3.4,-6 -6.93,-6l0,0c-3.53,0 -6.44,2.61 -6.93,6c0,0 -3.07,0 -3.07,0v2L5.07,13zM14,10.5V9.61c0,-1 -0.68,-1.92 -1.66,-2.08C11.08,7.32 10,8.29 10,9.5v1c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-3C15,10.95 14.55,10.5 14,10.5zM12,13.75c-0.41,0 -0.75,-0.34 -0.75,-0.75c0,-0.41 0.34,-0.75 0.75,-0.75s0.75,0.34 0.75,0.75C12.75,13.41 12.41,13.75 12,13.75zM13,10.5h-2v-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V10.5z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/real_estate_agent.xml b/compose/material/material/icons/generator/raw-icons/twotone/real_estate_agent.xml
new file mode 100644
index 0000000..71775f0
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/real_estate_agent.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10.5,9.44l5.32,1.99c1.24,0.46 2.21,1.41 2.74,2.57L19,14V7.5L14,4L9,7.5V9h0.33L10.5,9.44zM14.5,7h1v1h-1V7zM14.5,9h1v1h-1V9zM12.5,7h1v1h-1V7zM12.5,9h1v1h-1V9zM3,13h2v7H3V13zM19.9,18.57l-5.93,1.84L7,18.48V13h1.61l5.82,2.17C14.77,15.3 15,15.63 15,16c0,0 -1.99,-0.05 -2.3,-0.15l-2.38,-0.79l-0.63,1.9l2.38,0.79c0.51,0.17 1.04,0.26 1.58,0.26H19C19.39,18.01 19.74,18.24 19.9,18.57z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.5,7h-1v1h1V7zM13.5,7h-1v1h1V7zM15.5,9h-1v1h1V9zM13.5,9h-1v1h1V9zM21,6.5V14h-2V7.5L14,4L9,7.5V9H7V6.5l7,-5L21,6.5zM19,16h-2c0,-1.2 -0.75,-2.28 -1.87,-2.7L8.97,11H1v11h6v-1.44l7,1.94l8,-2.5v-1C22,17.34 20.66,16 19,16zM3,20v-7h2v7H3zM13.97,20.41L7,18.48V13h1.61l5.82,2.17C14.77,15.3 15,15.63 15,16c0,0 -1.99,-0.05 -2.3,-0.15l-2.38,-0.79l-0.63,1.9l2.38,0.79c0.51,0.17 1.04,0.26 1.58,0.26H19c0.39,0 0.74,0.23 0.9,0.56L13.97,20.41z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/recycling.xml b/compose/material/material/icons/generator/raw-icons/twotone/recycling.xml
new file mode 100644
index 0000000..bd30b8a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/recycling.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5.77,7.15L7.2,4.78l1.03,-1.71c0.39,-0.65 1.33,-0.65 1.72,0l1.48,2.46l-1.23,2.06L9.2,9.21L5.77,7.15zM21.72,12.97l-1.6,-2.66l-3.46,2L18.87,16H20c0.76,0 1.45,-0.43 1.79,-1.11C21.93,14.61 22,14.31 22,14C22,13.64 21.9,13.29 21.72,12.97zM16,21h1.5c0.76,0 1.45,-0.43 1.79,-1.11L20.74,17H16v-2l-4,4l4,4V21zM10,17H5.7l-0.84,1.41c-0.3,0.5 -0.32,1.12 -0.06,1.65l0,0C5.08,20.63 5.67,21 6.32,21H10V17zM6.12,14.35l1.73,1.04L6.48,9.9L1,11.27l1.7,1.02l-0.41,0.69c-0.35,0.59 -0.38,1.31 -0.07,1.92l1.63,3.26L6.12,14.35zM17.02,5.14l-1.3,-2.17C15.35,2.37 14.7,2 14,2h-3.53l3.12,5.2l-1.72,1.03l5.49,1.37l1.37,-5.49L17.02,5.14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/soup_kitchen.xml b/compose/material/material/icons/generator/raw-icons/twotone/soup_kitchen.xml
new file mode 100644
index 0000000..6ef3e48
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/soup_kitchen.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.12,17c-0.73,1.78 -2.43,3 -4.37,3c-1.94,0 -3.67,-1.23 -4.43,-3h8.78"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.4,7C6.06,7.55 6,7.97 6,8.38C6,9.15 7,11 7,12c0,0.95 -0.4,1.5 -0.4,1.5H5.1c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62C4.5,7.97 4.56,7.55 4.9,7H6.4zM11.4,7C11.06,7.55 11,7.97 11,8.38C11,9.15 12,11 12,12c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H11.4zM8.15,7c-0.34,0.55 -0.4,0.97 -0.4,1.38c0,0.77 1,2.63 1,3.62c0,0.95 -0.4,1.5 -0.4,1.5h1.5c0,0 0.4,-0.55 0.4,-1.5c0,-1 -1,-2.85 -1,-3.62c0,-0.41 0.06,-0.83 0.4,-1.38H8.15zM18.6,2c-1.54,0 -2.81,1.16 -2.98,2.65L14.53,15H4.01c-0.6,0 -1.09,0.53 -1,1.13C3.53,19.46 6.39,22 9.75,22c3.48,0 6.34,-2.73 6.71,-6.23l1.15,-10.87C17.66,4.39 18.08,4 18.6,4c0.55,0 1,0.45 1,1c0,0.3 -0.1,1.25 -0.1,1.25l1.97,0.25c0,0 0.13,-1.06 0.13,-1.5C21.6,3.35 20.25,2 18.6,2zM9.75,20c-1.94,0 -3.67,-1.23 -4.43,-3h8.78h0.01C13.39,18.78 11.69,20 9.75,20z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/south_america.xml b/compose/material/material/icons/generator/raw-icons/twotone/south_america.xml
new file mode 100644
index 0000000..9f8f6a8
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/south_america.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M4,12c0,-1.95 0.7,-3.74 1.87,-5.13L9,10v1c0,1.1 0.9,2 2,2v5.59c0,0.27 0.11,0.52 0.29,0.71L12,20C7.58,20 4,16.42 4,12zM13,19.94V18l3.75,-5.62c0.16,-0.25 0.25,-0.54 0.25,-0.83V10.5c0,-0.55 -0.45,-1 -1,-1h-1.5l-1.4,-1.75C12.72,7.28 12.15,7 11.54,7H8V5.07C9.18,4.39 10.54,4 12,4c4.41,0 8,3.59 8,8C20,16.07 16.94,19.44 13,19.94z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM4,12c0,-1.95 0.7,-3.74 1.87,-5.13L9,10v1c0,1.1 0.9,2 2,2v5.59c0,0.27 0.11,0.52 0.29,0.71L12,20C7.58,20 4,16.42 4,12zM13,19.94V18l3.75,-5.62c0.16,-0.25 0.25,-0.54 0.25,-0.83V10.5c0,-0.55 -0.45,-1 -1,-1h-1.5l-1.4,-1.75C12.72,7.28 12.15,7 11.54,7H8V5.07C9.18,4.39 10.54,4 12,4c4.41,0 8,3.59 8,8C20,16.07 16.94,19.44 13,19.94z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/space_dashboard.xml b/compose/material/material/icons/generator/raw-icons/twotone/space_dashboard.xml
new file mode 100644
index 0000000..1baeea4
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/space_dashboard.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,19V5h6v14H5zM19,19h-6v-7h6V19zM19,10h-6V5h6V10z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM5,19V5h6v14H5zM19,19h-6v-7h6V19zM19,10h-6V5h6V10z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/spoke.xml b/compose/material/material/icons/generator/raw-icons/twotone/spoke.xml
new file mode 100644
index 0000000..8cd536a
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/spoke.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,9c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C14,8.1 13.1,9 12,9zM7,19c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C9,18.1 8.1,19 7,19zM17,19c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C19,18.1 18.1,19 17,19z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,7c0,-2.21 -1.79,-4 -4,-4S8,4.79 8,7c0,2.21 1.79,4 4,4S16,9.21 16,7zM12,9c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C14,8.1 13.1,9 12,9zM7,13c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C11,14.79 9.21,13 7,13zM7,19c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C9,18.1 8.1,19 7,19zM17,13c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C21,14.79 19.21,13 17,13zM17,19c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C19,18.1 18.1,19 17,19z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/stop_circle.xml b/compose/material/material/icons/generator/raw-icons/twotone/stop_circle.xml
index b1801d5..ed6354d 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/stop_circle.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/stop_circle.xml
@@ -6,13 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,4c-4.41,0 -8,3.59 -8,8c0,4.41 3.59,8 8,8c4.41,0 8,-3.59 8,-8C20,7.59 16.41,4 12,4zM16,16H8V8h8V16z"
+ android:pathData="M12,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8s8,-3.58 8,-8S16.42,4 12,4zM16,16H8V8h8V16z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M8,8h8v8h-8z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8s8,3.58 8,8S16.42,20 12,20zM16,16H8V8h8V16z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/switch_access_shortcut.xml b/compose/material/material/icons/generator/raw-icons/twotone/switch_access_shortcut.xml
new file mode 100644
index 0000000..6c27e1c
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/switch_access_shortcut.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-2.73 1.08,-5.27 2.75,-7.25L12,2h7v7l-2.82,-2.82C14.84,7.82 14,9.88 14,12c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/switch_access_shortcut_add.xml b/compose/material/material/icons/generator/raw-icons/twotone/switch_access_shortcut_add.xml
new file mode 100644
index 0000000..84b07f9
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/switch_access_shortcut_add.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,14h-2v-2h-2v2h-2v2h2v2h2v-2h2V14zM7.06,8.94L5,8l2.06,-0.94L8,5l0.94,2.06L11,8L8.94,8.94L8,11L7.06,8.94zM8,21l0.94,-2.06L11,18l-2.06,-0.94L8,15l-0.94,2.06L5,18l2.06,0.94L8,21zM4.37,12.37L3,13l1.37,0.63L5,15l0.63,-1.37L7,13l-1.37,-0.63L5,11L4.37,12.37zM12,12c0,-2.73 1.08,-5.27 2.75,-7.25L12,2h7v7l-2.82,-2.82C14.84,7.82 14,9.88 14,12c0,3.32 2.1,6.36 5,7.82L19,22C14.91,20.41 12,16.35 12,12z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/sync_alt.xml b/compose/material/material/icons/generator/raw-icons/twotone/sync_alt.xml
index f899b57..360b6a2 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/sync_alt.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/sync_alt.xml
@@ -6,8 +6,8 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M22,8l-4,-4v3H3v2h15v3L22,8z"/>
+ android:pathData="M18,12l4,-4l-4,-4l0,3l-15,0l0,2l15,0z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M2,16l4,4v-3h15v-2H6v-3L2,16z"/>
+ android:pathData="M6,12l-4,4l4,4l0,-3l15,0l0,-2l-15,0z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/tips_and_updates.xml b/compose/material/material/icons/generator/raw-icons/twotone/tips_and_updates.xml
new file mode 100644
index 0000000..0223a6d
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/tips_and_updates.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.5,9.5C14.5,6.47 12.03,4 9,4S3.5,6.47 3.5,9.5c0,2.47 1.49,3.89 2.35,4.5h6.3C13.01,13.39 14.5,11.97 14.5,9.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,19h8v-2H5V19zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM14.5,9.5C14.5,6.47 12.03,4 9,4S3.5,6.47 3.5,9.5c0,2.47 1.49,3.89 2.35,4.5h6.3C13.01,13.39 14.5,11.97 14.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/token.xml b/compose/material/material/icons/generator/raw-icons/twotone/token.xml
new file mode 100644
index 0000000..08315df
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/token.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4.29l5.91,3.28L14.9,9.24C14.17,8.48 13.14,8 12,8S9.83,8.48 9.1,9.24L6.09,7.57L12,4.29zM11,19.16l-6,-3.33V9.26l3.13,1.74C8.04,11.31 8,11.65 8,12c0,1.86 1.27,3.43 3,3.87V19.16zM10,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2s-0.9,2 -2,2S10,13.1 10,12zM13,19.16v-3.28c1.73,-0.44 3,-2.01 3,-3.87c0,-0.35 -0.04,-0.69 -0.13,-1.01L19,9.26l0,6.57L13,19.16z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,7l-9,-5L3,7v10l9,5l9,-5L21,7zM12,4.29l5.91,3.28L14.9,9.24C14.17,8.48 13.14,8 12,8S9.83,8.48 9.1,9.24L6.09,7.57L12,4.29zM11,19.16l-6,-3.33V9.26l3.13,1.74C8.04,11.31 8,11.65 8,12c0,1.86 1.27,3.43 3,3.87V19.16zM10,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2s-0.9,2 -2,2S10,13.1 10,12zM13,19.16v-3.28c1.73,-0.44 3,-2.01 3,-3.87c0,-0.35 -0.04,-0.69 -0.13,-1.01L19,9.26l0,6.57L13,19.16z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/vaccines.xml b/compose/material/material/icons/generator/raw-icons/twotone/vaccines.xml
new file mode 100644
index 0000000..3d1c3c6b
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/vaccines.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,17h-4v-1.5h4V17zM9,7.5H5V15h4l0,-1.5H7.25c-0.41,0 -0.75,-0.34 -0.75,-0.75C6.5,12.34 6.84,12 7.25,12H9v-1.5H7.25c-0.41,0 -0.75,-0.34 -0.75,-0.75C6.5,9.34 6.84,9 7.25,9H9V7.5z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,5.5H8V4h0.5c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1H6v1.5H3c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1V15c0,1.1 0.9,2 2,2h1v4l2,1.5V17h1c1.1,0 2,-0.9 2,-2V7.5c0.55,0 1,-0.45 1,-1C12,5.95 11.55,5.5 11,5.5zM9,9H7.25C6.84,9 6.5,9.34 6.5,9.75c0,0.41 0.34,0.75 0.75,0.75H9V12H7.25c-0.41,0 -0.75,0.34 -0.75,0.75c0,0.41 0.34,0.75 0.75,0.75H9L9,15H5V7.5h4V9zM19.5,10.5V10c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1h-5c-0.55,0 -1,0.45 -1,1c0,0.55 0.45,1 1,1v0.5c0,0.5 -1.5,1.16 -1.5,3V20c0,1.1 0.9,2 2,2h4c1.1,0 2,-0.9 2,-2v-6.5C21,11.66 19.5,11 19.5,10.5zM16.5,10.5V10h1v0.5c0,1.6 1.5,2 1.5,3V14h-4c0,-0.21 0,-0.39 0,-0.5C15,12.5 16.5,12.1 16.5,10.5zM19,15.5V17h-4c0,-0.51 0,-1.02 0,-1.5H19zM15,20c0,0 0,-0.63 0,-1.5h4V20H15z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_agenda.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_agenda.xml
index 15eb320..f52bb39 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_agenda.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_agenda.xml
@@ -6,10 +6,18 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,3L3,3c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1zM19,9L4,9L4,5h15v4zM20,13L3,13c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1zM19,19L4,19v-4h15v4z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,15h15v4H4zM4,5h15v4H4z"
+ android:pathData="M5,5h14v4h-14z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,15h14v4h-14z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,13H5c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4C21,13.9 20.1,13 19,13zM19,19H5v-4h14V19z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,9H5V5h14V9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_array.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_array.xml
index b5bbc67..f39b6dc 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_array.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_array.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M4,5h3v13L4,18zM18,5h3v13h-3zM8,18h9L17,5L8,5v13zM10,7h5v9h-5L10,7z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,7h5v9h-5z"
+ android:pathData="M9,7h6v10h-6z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,7v10H9V7H15zM21,5h-3v14h3V5zM17,5H7v14h10V5zM6,5H3v14h3V5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_carousel.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_carousel.xml
index d3077aa..638b433 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_carousel.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_carousel.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M18,6h4v11h-4zM7,19h10V4H7v15zM9,6h6v11H9V6zM2,6h4v11H2z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M9,6h6v11H9z"
+ android:pathData="M9,7h6v10h-6z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M2,7h4v10H2V7zM7,19h10V5H7V19zM9,7h6v10H9V7zM18,7h4v10h-4V7z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_column.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_column.xml
index 051e4fa..295c856 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_column.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_column.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,7h3v9L6,16zM11,7h3v9h-3zM16,7h3v9h-3z"
+ android:pathData="M8.33,17H5V7h3.33V17zM13.67,17h-3.33V7h3.33V17zM19,17h-3.33V7H19V17z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M4,5v13h17L21,5L4,5zM9,16L6,16L6,7h3v9zM14,16h-3L11,7h3v9zM19,16h-3L16,7h3v9z"/>
+ android:pathData="M3,5v14h18V5H3zM8.33,17H5V7h3.33V17zM13.67,17h-3.33V7h3.33V17zM19,17h-3.33V7H19V17z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_list.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_list.xml
index 4673ac7..d9cba55 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_list.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_list.xml
@@ -7,10 +7,10 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M5,11h2v2L5,13zM5,15h2v2L5,17zM5,7h2v2L5,9zM9,7h9v2L9,9zM9,15h9v2L9,17zM9,11h9v2L9,13z"
+ android:pathData="M7,7v2H5V7H7zM5,13v-2h2v2H5zM5,15h2v2H5V15zM19,17H9v-2h10V17zM19,13H9v-2h10V13zM19,9H9V7h10V9z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M3,5v14h17L20,5L3,5zM7,17L5,17v-2h2v2zM7,13L5,13v-2h2v2zM7,9L5,9L5,7h2v2zM18,17L9,17v-2h9v2zM18,13L9,13v-2h9v2zM18,9L9,9L9,7h9v2z"/>
+ android:pathData="M3,5v14h18V5H3zM7,7v2H5V7H7zM5,13v-2h2v2H5zM5,15h2v2H5V15zM19,17H9v-2h10V17zM19,13H9v-2h10V13zM19,9H9V7h10V9z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_module.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_module.xml
index 519ba2a..e6f7a3b 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_module.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_module.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M11,12.5h3L14,16h-3zM11,7h3v3.5h-3zM6,12.5h3L9,16L6,16zM6,7h3v3.5L6,10.5zM16,7h3v3.5h-3zM16,12.5h3L19,16h-3z"
+ android:pathData="M19,11h-3.33V7H19V11zM13.67,11h-3.33V7h3.33V11zM8.33,7v4H5V7H8.33zM5,17v-4h3.33v4H5zM10.33,17v-4h3.33v4H10.33zM15.67,17v-4H19v4H15.67z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M4,5v13h17L21,5L4,5zM9,16L6,16v-3.5h3L9,16zM9,10.5L6,10.5L6,7h3v3.5zM14,16h-3v-3.5h3L14,16zM14,10.5h-3L11,7h3v3.5zM19,16h-3v-3.5h3L19,16zM19,10.5h-3L16,7h3v3.5z"/>
+ android:pathData="M3,5v14h18V5H3zM19,11h-3.33V7H19V11zM13.67,11h-3.33V7h3.33V11zM8.33,7v4H5V7H8.33zM5,17v-4h3.33v4H5zM10.33,17v-4h3.33v4H10.33zM15.67,17v-4H19v4H15.67z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_quilt.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_quilt.xml
index 521f8f9..3afb8ac 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_quilt.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_quilt.xml
@@ -7,10 +7,10 @@
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
- android:pathData="M16,12.5h3L19,16h-3zM6,7h3v9L6,16zM11,12.5h3L14,16h-3zM11,7h8v3.5h-8z"
+ android:pathData="M8.33,17H5V7h3.33V17zM13.67,17h-3.33v-4h3.33V17zM19,17h-3.33v-4H19V17zM19,11h-8.67V7H19V11z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M4,5v13h17L21,5L4,5zM9,16L6,16L6,7h3v9zM14,16h-3v-3.5h3L14,16zM19,16h-3v-3.5h3L19,16zM19,10.5h-8L11,7h8v3.5z"/>
+ android:pathData="M3,5v14h18V5H3zM8.33,17H5V7h3.33V17zM13.67,17h-3.33v-4h3.33V17zM19,17h-3.33v-4H19V17zM19,11h-8.67V7H19V11z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_stream.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_stream.xml
index 9bfef71..6a63e8e 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_stream.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_stream.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M6,13h13v3L6,16zM6,8h13v3L6,11z"
+ android:pathData="M19,17H5v-4h14V17zM5,11V7h14v4H5z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M4,6v12h17L21,6L4,6zM19,16L6,16v-3h13v3zM19,11L6,11L6,8h13v3z"/>
+ android:pathData="M3,7v10c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V7c0,-1.1 -0.9,-2 -2,-2H5C3.9,5 3,5.9 3,7zM19,17H5v-4h14V17zM5,11V7h14v4H5z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/view_week.xml b/compose/material/material/icons/generator/raw-icons/twotone/view_week.xml
index ddbb12d..6922e89 100644
--- a/compose/material/material/icons/generator/raw-icons/twotone/view_week.xml
+++ b/compose/material/material/icons/generator/raw-icons/twotone/view_week.xml
@@ -6,10 +6,10 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M21,4L3,4c-0.55,0 -1,0.45 -1,1v14c0,0.55 0.45,1 1,1h18c0.55,0 1,-0.45 1,-1L22,5c0,-0.55 -0.45,-1 -1,-1zM8,18L4,18L4,6h4v12zM14,18h-4L10,6h4v12zM20,18h-4L16,6h4v12z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,6h4v12h-4zM16,6h4v12h-4zM4,6h4v12L4,18z"
+ android:pathData="M8,18H4V6h4V18zM14,18h-4V6h4V18zM20,18h-4V6h4V18z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,4H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.1,4 20,4zM8,18H4V6h4V18zM14,18h-4V6h4V18zM20,18h-4V6h4V18z"/>
</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/water_drop.xml b/compose/material/material/icons/generator/raw-icons/twotone/water_drop.xml
new file mode 100644
index 0000000..e16cd02
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/water_drop.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4.67c-4.05,3.7 -6,6.79 -6,9.14c0,3.63 2.65,6.2 6,6.2s6,-2.57 6,-6.2C18,11.46 16.05,8.36 12,4.67zM12.28,18.99c-2.13,0.13 -4.62,-1.09 -5.19,-4.12C7.01,14.42 7.37,14 7.83,14c0.37,0 0.67,0.26 0.74,0.62c0.41,2.23 2.28,2.98 3.64,2.87c0.43,-0.02 0.79,0.32 0.79,0.75C13,18.64 12.68,18.97 12.28,18.99z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2c-5.33,4.55 -8,8.48 -8,11.8c0,4.98 3.8,8.2 8,8.2s8,-3.22 8,-8.2C20,10.48 17.33,6.55 12,2zM12,20c-3.35,0 -6,-2.57 -6,-6.2c0,-2.34 1.95,-5.44 6,-9.14c4.05,3.7 6,6.79 6,9.14C18,17.43 15.35,20 12,20zM7.83,14c0.37,0 0.67,0.26 0.74,0.62c0.41,2.22 2.28,2.98 3.64,2.87c0.43,-0.02 0.79,0.32 0.79,0.75c0,0.4 -0.32,0.73 -0.72,0.75c-2.13,0.13 -4.62,-1.09 -5.19,-4.12C7.01,14.42 7.37,14 7.83,14z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/waving_hand.xml b/compose/material/material/icons/generator/raw-icons/twotone/waving_hand.xml
new file mode 100644
index 0000000..9a65143
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/waving_hand.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.44,6.37c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-3.18,3.18c1.17,1.17 1.17,3.07 0,4.24l1.41,1.41c1.45,-1.45 1.82,-3.57 1.12,-5.36l6.3,-6.3c0.2,-0.2 0.51,-0.2 0.71,0s0.2,0.51 0,0.71l-4.6,4.6l1.41,1.41l6.01,-6.01c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-6.01,6.01l1.41,1.41l4.95,-4.95c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-5.66,5.66l1.41,1.41l3.54,-3.54c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71L14.1,19.1c-2.54,2.54 -6.65,2.54 -9.19,0s-2.54,-6.65 0,-9.19L8.44,6.37z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7.03,4.95L3.49,8.49c-3.32,3.32 -3.32,8.7 0,12.02s8.7,3.32 12.02,0l6.01,-6.01c0.97,-0.97 0.97,-2.56 0,-3.54c-0.12,-0.12 -0.25,-0.23 -0.39,-0.32l0.39,-0.39c0.97,-0.97 0.97,-2.56 0,-3.54c-0.16,-0.16 -0.35,-0.3 -0.54,-0.41c0.4,-0.92 0.23,-2.02 -0.52,-2.77c-0.87,-0.87 -2.22,-0.96 -3.2,-0.28c-0.1,-0.15 -0.21,-0.29 -0.34,-0.42c-0.97,-0.97 -2.56,-0.97 -3.54,0l-2.51,2.51c-0.09,-0.14 -0.2,-0.27 -0.32,-0.39C9.58,3.98 8,3.98 7.03,4.95zM8.44,6.37c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-3.18,3.18c1.17,1.17 1.17,3.07 0,4.24l1.41,1.41c1.45,-1.45 1.82,-3.57 1.12,-5.36l6.3,-6.3c0.2,-0.2 0.51,-0.2 0.71,0s0.2,0.51 0,0.71l-4.6,4.6l1.41,1.41l6.01,-6.01c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-6.01,6.01l1.41,1.41l4.95,-4.95c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71l-5.66,5.66l1.41,1.41l3.54,-3.54c0.2,-0.2 0.51,-0.2 0.71,0c0.2,0.2 0.2,0.51 0,0.71L14.1,19.1c-2.54,2.54 -6.65,2.54 -9.19,0s-2.54,-6.65 0,-9.19L8.44,6.37zM23,17c0,3.31 -2.69,6 -6,6v-1.5c2.48,0 4.5,-2.02 4.5,-4.5H23zM1,7c0,-3.31 2.69,-6 6,-6v1.5C4.52,2.5 2.5,4.52 2.5,7H1z"/>
+</vector>
diff --git a/compose/material/material/icons/generator/raw-icons/twotone/workspace_premium.xml b/compose/material/material/icons/generator/raw-icons/twotone/workspace_premium.xml
new file mode 100644
index 0000000..c1ef189
--- /dev/null
+++ b/compose/material/material/icons/generator/raw-icons/twotone/workspace_premium.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4c-3.31,0 -6,2.69 -6,6s2.69,6 6,6s6,-2.69 6,-6S15.31,4 12,4zM14.31,13.69L12,11.93l-2.32,1.76l0.88,-2.85L8.25,9h2.84L12,6.19L12.91,9h2.84l-2.32,1.84L14.31,13.69zM12,19l-4,1.02v-3.1C9.18,17.6 10.54,18 12,18s2.82,-0.4 4,-1.08v3.1L12,19z"
+ android:strokeAlpha="0.3"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9.68,13.69L12,11.93l2.31,1.76l-0.88,-2.85L15.75,9h-2.84L12,6.19L11.09,9H8.25l2.31,1.84L9.68,13.69zM20,10c0,-4.42 -3.58,-8 -8,-8s-8,3.58 -8,8c0,2.03 0.76,3.87 2,5.28V23l6,-2l6,2v-7.72C19.24,13.87 20,12.03 20,10zM12,4c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6S8.69,4 12,4zM12,19l-4,1.02v-3.1C9.18,17.6 10.54,18 12,18s2.82,-0.4 4,-1.08v3.1L12,19z"/>
+</vector>
diff --git a/compose/material/material/integration-tests/material-catalog/src/main/AndroidManifest.xml b/compose/material/material/integration-tests/material-catalog/src/main/AndroidManifest.xml
index 3e1ea34..4034da7 100644
--- a/compose/material/material/integration-tests/material-catalog/src/main/AndroidManifest.xml
+++ b/compose/material/material/integration-tests/material-catalog/src/main/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:label="@string/compose_material_catalog"
android:icon="@mipmap/ic_launcher"
android:theme="@style/Theme.Catalog">
- <activity android:name=".CatalogActivity">
+ <activity android:name=".CatalogActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopAlertDialog.desktop.kt b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopAlertDialog.desktop.kt
index fecc83d..88357d1 100644
--- a/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopAlertDialog.desktop.kt
+++ b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopAlertDialog.desktop.kt
@@ -17,18 +17,24 @@
package androidx.compose.material
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.window.WindowDraggableArea
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.window.v1.Dialog
-import androidx.compose.ui.window.v1.DialogProperties
+import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.rememberDialogState
+import androidx.compose.ui.window.Dialog as CoreDialog
/**
- * Alert dialog is a [Dialog] which interrupts the user with urgent information, details or actions.
+ * Alert dialog is a Dialog which interrupts the user with urgent information, details or actions.
*
* The dialog will position its buttons based on the available space. By default it will try to
* place them horizontally next to each other and fallback to horizontal placement if not enough
@@ -38,8 +44,7 @@
* Sample of dialog:
* @sample androidx.compose.material.samples.AlertDialogSample
*
- * @param onDismissRequest Executes when the user tries to dismiss the Dialog by clicking outside
- * or pressing the back button. This is not called when the dismiss button is clicked.
+ * @param onDismissRequest Callback that will be called when the user closes the dialog.
* @param confirmButton A button which is meant to confirm a proposed action, thus resolving
* what triggered the dialog. The dialog does not set up any events for this button so they need
* to be set up by the caller.
@@ -54,9 +59,10 @@
* @param shape Defines the Dialog's shape
* @param backgroundColor The background color of the dialog.
* @param contentColor The preferred content color provided by this dialog to its children.
- * @param properties Typically platform specific properties to further configure the dialog.
+ * @param dialogProvider Defines how to create dialog in which will be placed AlertDialog's content.
*/
@Composable
+@ExperimentalMaterialApi
fun AlertDialog(
onDismissRequest: () -> Unit,
confirmButton: @Composable () -> Unit,
@@ -67,7 +73,7 @@
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
- properties: DialogProperties = DialogProperties()
+ dialogProvider: AlertDialogProvider = PopupAlertDialogProvider
) {
AlertDialog(
onDismissRequest = onDismissRequest,
@@ -89,19 +95,18 @@
shape = shape,
backgroundColor = backgroundColor,
contentColor = contentColor,
- properties = properties
+ dialogProvider = dialogProvider
)
}
/**
- * Alert dialog is a [Dialog] which interrupts the user with urgent information, details or actions.
+ * Alert dialog is a Dialog which interrupts the user with urgent information, details or actions.
*
* This function can be used to fully customize the button area, e.g. with:
*
* @sample androidx.compose.material.samples.CustomAlertDialogSample
*
- * @param onDismissRequest Executes when the user tries to dismiss the Dialog by clicking outside
- * or pressing the back button. This is not called when the dismiss button is clicked.
+ * @param onDismissRequest Callback that will be called when the user closes the dialog.
* @param buttons Function that emits the layout with the buttons.
* @param modifier Modifier to be applied to the layout of the dialog.
* @param title The title of the Dialog which should specify the purpose of the Dialog. The title
@@ -112,9 +117,10 @@
* @param shape Defines the Dialog's shape.
* @param backgroundColor The background color of the dialog.
* @param contentColor The preferred content color provided by this dialog to its children.
- * @param properties Typically platform specific properties to further configure the dialog.
+ * @param dialogProvider Defines how to create dialog in which will be placed AlertDialog's content.
*/
@Composable
+@ExperimentalMaterialApi
fun AlertDialog(
onDismissRequest: () -> Unit,
buttons: @Composable () -> Unit,
@@ -124,20 +130,84 @@
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
- properties: DialogProperties = DialogProperties()
+ dialogProvider: AlertDialogProvider = PopupAlertDialogProvider
) {
- Dialog(
- onDismissRequest = onDismissRequest,
- properties = properties
- ) {
- AlertDialogContent(
- buttons = buttons,
- modifier = modifier,
- title = title,
- text = text,
- shape = shape,
- backgroundColor = backgroundColor,
- contentColor = contentColor
- )
+ with(dialogProvider) {
+ AlertDialog(onDismissRequest = onDismissRequest) {
+ AlertDialogContent(
+ buttons = buttons,
+ modifier = modifier.width(IntrinsicSize.Min),
+ title = title,
+ text = text,
+ shape = shape,
+ backgroundColor = backgroundColor,
+ contentColor = contentColor
+ )
+ }
}
}
+
+/**
+ * Defines how to create dialog in which will be placed AlertDialog's content.
+ */
+@ExperimentalMaterialApi
+interface AlertDialogProvider {
+ /**
+ * Dialog which will be used to place AlertDialog's [content].
+ *
+ * @param onDismissRequest Callback that will be called when the user closes the dialog
+ * @param content Content of the dialog
+ */
+ @Composable
+ fun AlertDialog(
+ onDismissRequest: () -> Unit,
+ content: @Composable () -> Unit
+ )
+}
+
+// TODO(https://github.com/JetBrains/compose-jb/issues/933): is it right to use Popup to show a
+// dialog?
+/**
+ * Shows Alert dialog as popup in the middle of the window.
+ */
+@ExperimentalMaterialApi
+object PopupAlertDialogProvider : AlertDialogProvider {
+ @Composable
+ override fun AlertDialog(
+ onDismissRequest: () -> Unit,
+ content: @Composable () -> Unit
+ ) {
+ Popup(
+ alignment = Alignment.Center,
+ focusable = true,
+ onDismissRequest = onDismissRequest,
+ ) {
+ Surface(elevation = 24.dp) {
+ content()
+ }
+ }
+ }
+}
+
+/**
+ * Shows Alert dialog as undecorated draggable window.
+ */
+@ExperimentalMaterialApi
+object UndecoratedWindowAlertDialogProvider : AlertDialogProvider {
+ @Composable
+ override fun AlertDialog(
+ onDismissRequest: () -> Unit,
+ content: @Composable () -> Unit
+ ) {
+ CoreDialog(
+ onCloseRequest = onDismissRequest,
+ state = rememberDialogState(width = Dp.Unspecified, height = Dp.Unspecified),
+ undecorated = true,
+ resizable = false
+ ) {
+ WindowDraggableArea {
+ content()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/v1/DesktopAlertDialogDeprecated.desktop.kt b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/v1/DesktopAlertDialogDeprecated.desktop.kt
new file mode 100644
index 0000000..2ca03cd
--- /dev/null
+++ b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/v1/DesktopAlertDialogDeprecated.desktop.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("DEPRECATION")
+
+package androidx.compose.material.v1
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.AlertDialogContent
+import androidx.compose.material.AlertDialogFlowRow
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.contentColorFor
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.v1.Dialog
+import androidx.compose.ui.window.v1.DialogProperties
+
+/**
+ * Alert dialog is a [Dialog] which interrupts the user with urgent information, details or actions.
+ *
+ * The dialog will position its buttons based on the available space. By default it will try to
+ * place them horizontally next to each other and fallback to horizontal placement if not enough
+ * space is available. There is also another version of this composable that has a slot for buttons
+ * to provide custom buttons layout.
+ *
+ * Sample of dialog:
+ * @sample androidx.compose.material.samples.AlertDialogSample
+ *
+ * @param onDismissRequest Executes when the user tries to dismiss the Dialog by clicking outside
+ * or pressing the back button. This is not called when the dismiss button is clicked.
+ * @param confirmButton A button which is meant to confirm a proposed action, thus resolving
+ * what triggered the dialog. The dialog does not set up any events for this button so they need
+ * to be set up by the caller.
+ * @param modifier Modifier to be applied to the layout of the dialog.
+ * @param dismissButton A button which is meant to dismiss the dialog. The dialog does not set up
+ * any events for this button so they need to be set up by the caller.
+ * @param title The title of the Dialog which should specify the purpose of the Dialog. The title
+ * is not mandatory, because there may be sufficient information inside the [text]. Provided text
+ * style will be [Typography.subtitle1].
+ * @param text The text which presents the details regarding the Dialog's purpose. Provided text
+ * style will be [Typography.body2].
+ * @param shape Defines the Dialog's shape
+ * @param backgroundColor The background color of the dialog.
+ * @param contentColor The preferred content color provided by this dialog to its children.
+ * @param properties Typically platform specific properties to further configure the dialog.
+ */
+@Deprecated(
+ "Use another variant of AlertDialog for the new Composable Window API (https://github" +
+ ".com/JetBrains/compose-jb/tree/master/tutorials/Window_API_new)"
+)
+@Composable
+fun AlertDialog(
+ onDismissRequest: () -> Unit,
+ confirmButton: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ dismissButton: @Composable (() -> Unit)? = null,
+ title: @Composable (() -> Unit)? = null,
+ text: @Composable (() -> Unit)? = null,
+ shape: Shape = MaterialTheme.shapes.medium,
+ backgroundColor: Color = MaterialTheme.colors.surface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ properties: DialogProperties = DialogProperties()
+) {
+ AlertDialog(
+ onDismissRequest = onDismissRequest,
+ buttons = {
+ // TODO: move the modifiers to FlowRow when it supports a modifier parameter
+ Box(Modifier.fillMaxWidth().padding(all = 8.dp)) {
+ AlertDialogFlowRow(
+ mainAxisSpacing = 8.dp,
+ crossAxisSpacing = 12.dp
+ ) {
+ dismissButton?.invoke()
+ confirmButton()
+ }
+ }
+ },
+ modifier = modifier,
+ title = title,
+ text = text,
+ shape = shape,
+ backgroundColor = backgroundColor,
+ contentColor = contentColor,
+ properties = properties
+ )
+}
+
+/**
+ * Alert dialog is a [Dialog] which interrupts the user with urgent information, details or actions.
+ *
+ * This function can be used to fully customize the button area, e.g. with:
+ *
+ * @sample androidx.compose.material.samples.CustomAlertDialogSample
+ *
+ * @param onDismissRequest Executes when the user tries to dismiss the Dialog by clicking outside
+ * or pressing the back button. This is not called when the dismiss button is clicked.
+ * @param buttons Function that emits the layout with the buttons.
+ * @param modifier Modifier to be applied to the layout of the dialog.
+ * @param title The title of the Dialog which should specify the purpose of the Dialog. The title
+ * is not mandatory, because there may be sufficient information inside the [text]. Provided text
+ * style will be [Typography.subtitle1].
+ * @param text The text which presents the details regarding the Dialog's purpose. Provided text
+ * style will be [Typography.body2].
+ * @param shape Defines the Dialog's shape.
+ * @param backgroundColor The background color of the dialog.
+ * @param contentColor The preferred content color provided by this dialog to its children.
+ * @param properties Typically platform specific properties to further configure the dialog.
+ */
+@Deprecated(
+ "Use another variant of AlertDialog for the new Composable Window API (https://github" +
+ ".com/JetBrains/compose-jb/tree/master/tutorials/Window_API_new)"
+)
+@Composable
+fun AlertDialog(
+ onDismissRequest: () -> Unit,
+ buttons: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ title: (@Composable () -> Unit)? = null,
+ text: @Composable (() -> Unit)? = null,
+ shape: Shape = MaterialTheme.shapes.medium,
+ backgroundColor: Color = MaterialTheme.colors.surface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ properties: DialogProperties = DialogProperties()
+) {
+ Dialog(
+ onDismissRequest = onDismissRequest,
+ properties = properties
+ ) {
+ AlertDialogContent(
+ buttons = buttons,
+ modifier = modifier,
+ title = title,
+ text = text,
+ shape = shape,
+ backgroundColor = backgroundColor,
+ contentColor = contentColor
+ )
+ }
+}
diff --git a/compose/runtime/.idea/codeStyles/Project.xml b/compose/runtime/.idea/codeStyles/Project.xml
new file mode 120000
index 0000000..32e9847
--- /dev/null
+++ b/compose/runtime/.idea/codeStyles/Project.xml
@@ -0,0 +1 @@
+../../../../.idea/codeStyles/Project.xml
\ No newline at end of file
diff --git a/compose/runtime/.idea/codeStyles/codeStyleConfig.xml b/compose/runtime/.idea/codeStyles/codeStyleConfig.xml
new file mode 120000
index 0000000..873592ff
--- /dev/null
+++ b/compose/runtime/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1 @@
+../../../../.idea/codeStyles/codeStyleConfig.xml
\ No newline at end of file
diff --git a/compose/runtime/.idea/copyright/AndroidCopyright.xml b/compose/runtime/.idea/copyright/AndroidCopyright.xml
new file mode 120000
index 0000000..f9a587a
--- /dev/null
+++ b/compose/runtime/.idea/copyright/AndroidCopyright.xml
@@ -0,0 +1 @@
+../../../../.idea/copyright/AndroidCopyright.xml
\ No newline at end of file
diff --git a/compose/runtime/.idea/copyright/profiles_settings.xml b/compose/runtime/.idea/copyright/profiles_settings.xml
new file mode 120000
index 0000000..0b054ba
--- /dev/null
+++ b/compose/runtime/.idea/copyright/profiles_settings.xml
@@ -0,0 +1 @@
+../../../../.idea/copyright/profiles_settings.xml
\ No newline at end of file
diff --git a/compose/runtime/.idea/inspectionProfiles/Project_Default.xml b/compose/runtime/.idea/inspectionProfiles/Project_Default.xml
new file mode 120000
index 0000000..b8d649c
--- /dev/null
+++ b/compose/runtime/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1 @@
+../../../../.idea/inspectionProfiles/Project_Default.xml
\ No newline at end of file
diff --git a/compose/runtime/.idea/scopes/Ignore_API_Files.xml b/compose/runtime/.idea/scopes/Ignore_API_Files.xml
new file mode 120000
index 0000000..009eced
--- /dev/null
+++ b/compose/runtime/.idea/scopes/Ignore_API_Files.xml
@@ -0,0 +1 @@
+../../../../.idea/scopes/Ignore_API_Files.xml
\ No newline at end of file
diff --git a/compose/runtime/.idea/scopes/buildSrc.xml b/compose/runtime/.idea/scopes/buildSrc.xml
new file mode 120000
index 0000000..a4d6cbd
--- /dev/null
+++ b/compose/runtime/.idea/scopes/buildSrc.xml
@@ -0,0 +1 @@
+../../../../.idea/scopes/buildSrc.xml
\ No newline at end of file
diff --git a/compose/runtime/gradle b/compose/runtime/gradle
new file mode 120000
index 0000000..27b2e9c
--- /dev/null
+++ b/compose/runtime/gradle
@@ -0,0 +1 @@
+../../playground-common/gradle
\ No newline at end of file
diff --git a/compose/runtime/gradle.properties b/compose/runtime/gradle.properties
new file mode 120000
index 0000000..bbd5978
--- /dev/null
+++ b/compose/runtime/gradle.properties
@@ -0,0 +1 @@
+../../playground-common/androidx-shared.properties
\ No newline at end of file
diff --git a/compose/runtime/gradlew b/compose/runtime/gradlew
new file mode 120000
index 0000000..d9f055c
--- /dev/null
+++ b/compose/runtime/gradlew
@@ -0,0 +1 @@
+../../playground-common/gradlew
\ No newline at end of file
diff --git a/compose/runtime/gradlew.bat b/compose/runtime/gradlew.bat
new file mode 120000
index 0000000..c35bc92
--- /dev/null
+++ b/compose/runtime/gradlew.bat
@@ -0,0 +1 @@
+../../playground-common/gradlew.bat
\ No newline at end of file
diff --git a/compose/runtime/runtime-lint/build.gradle b/compose/runtime/runtime-lint/build.gradle
index bd68015..0e2bd51 100644
--- a/compose/runtime/runtime-lint/build.gradle
+++ b/compose/runtime/runtime-lint/build.gradle
@@ -29,9 +29,9 @@
dependencies {
compileOnly(libs.androidLintMinComposeApi)
compileOnly(libs.kotlinStdlib)
- bundleInside(project(":compose:lint:common"))
+ bundleInside(projectOrArtifact(":compose:lint:common"))
- testImplementation(project(":compose:lint:common-test"))
+ testImplementation(projectOrArtifact(":compose:lint:common-test"))
testImplementation(libs.kotlinStdlib)
testImplementation(libs.androidLint)
testImplementation(libs.androidLintTests)
diff --git a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableCoroutineCreationDetectorTest.kt b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableCoroutineCreationDetectorTest.kt
index 710a310..b428009 100644
--- a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableCoroutineCreationDetectorTest.kt
+++ b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableCoroutineCreationDetectorTest.kt
@@ -24,7 +24,6 @@
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -44,6 +43,7 @@
private val coroutineBuildersStub: TestFile = compiledStub(
filename = "Builders.common.kt",
filepath = "kotlinx/coroutines",
+ checksum = 0xdb1ff08e,
"""
package kotlinx.coroutines
@@ -58,6 +58,12 @@
) {}
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlk5iXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbqpeWny/EFpJaXOJdwqXOJZSdX5KTmQdSVpRfWpKZl1osJOhUmpmT
+ klpUHA/Um5uf512ixKDFAADN8kOtaQAAAA==
+ """,
+ """
kotlinx/coroutines/Builders_commonKt.class:
H4sIAAAAAAAAAK1TXU8TQRQ9M/1aliJlBWyrYpUqX8IW4lsJCRJJGhGNRV54
MNPtWrbdzpr9aOCN+FP8BfJGfDAE3/xRxrvbLoKagNF9uHvu3XPPnJm5++37
@@ -89,16 +95,9 @@
Yd1NivxdUh75NnlOb6NS90iF5JmbwJNL+BfV8v1FMQjygGzrVwGWCAX4WP6z
+RZVu2f5M/jJJVofsXJRJTg2K3sHD6sfim6AAGunqEW4FuE6Wdxw5mZEkM4p
WEFnvU3rBYICGwW8n1uFkiGNAgAA
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlk5iXUpSfmVKhl5yfW5BfnKpX
- VJpXkpmbqpeWny/EFpJaXOJdwqXOJZSdX5KTmQdSVpRfWpKZl1osJOhUmpmT
- klpUHA/Um5uf512ixKDFAADN8kOtaQAAAA==
"""
)
- @Ignore // b/193270279
@Test
fun errors() {
lint().files(
@@ -206,7 +205,6 @@
)
}
- @Ignore // b/193270279
@Test
fun noErrors() {
lint().files(
diff --git a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableFlowOperatorDetectorTest.kt b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableFlowOperatorDetectorTest.kt
index 83bafd2..248ba1a 100644
--- a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableFlowOperatorDetectorTest.kt
+++ b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/ComposableFlowOperatorDetectorTest.kt
@@ -24,7 +24,6 @@
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -47,6 +46,7 @@
private val flowStub: TestFile = compiledStub(
filename = "Flow.kt",
filepath = "kotlinx/coroutines/flow",
+ checksum = 0x8d13620c,
"""
package kotlinx.coroutines.flow
@@ -59,6 +59,12 @@
fun <T> Flow<T>.drop(count: Int): Flow<T> = this
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlk5iXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbqpeWny/EFpJaXOJdwqXIJZ6dX5KTmQdSVpRfWpKZl1qsl5aTXy7E
+ 5gYkvUuUGLQYABYJSb1jAAAA
+ """,
+ """
kotlinx/coroutines/flow/Flow.class:
H4sIAAAAAAAAAH1QPU8CQRSctwgH59fhJybGaGcsPCRWakxsSEgwJkJsqBZY
yMKxm3B7SHm/y8Jc7Y8yvoNOE7eY2ZmdZPa9r++PTwC3OCacTq2LtFmGAzu3
@@ -107,16 +113,9 @@
pXoz4VKlgCiZOuCy9nJpBVpcenGAwd2koAqTSAwL3rlSMDssCOL8hFaN7IWE
60dx0Ad4SvJL8r9FR/P2MVJ13KujRCtW61jDeh3vYOMYTOA+rGPMC6wILAuU
BUw6XIG0wJZAXuCBwEOBdwXeE3g/3lL+AdkMm1BrBwAA
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlk5iXUpSfmVKhl5yfW5BfnKpX
- VJpXkpmbqpeWny/EFpJaXOJdwqXIJZ6dX5KTmQdSVpRfWpKZl1qsl5aTXy7E
- 5gYkvUuUGLQYABYJSb1jAAAA
"""
)
- @Ignore // b/193270279
@Test
fun errors() {
lint().files(
diff --git a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt
index 4ee844d..1f39ba8 100644
--- a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt
+++ b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt
@@ -22,7 +22,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -43,6 +42,7 @@
private val compositionLocalStub = compiledStub(
filename = "CompositionLocal.kt",
filepath = "androidx/compose/runtime",
+ checksum = 0x48f5c823,
"""
package androidx.compose.runtime
@@ -69,41 +69,10 @@
): ProvidableCompositionLocal<T> = StaticProvidableCompositionLocal(defaultFactory)
""",
"""
- androidx/compose/runtime/CompositionLocalKt.class:
- H4sIAAAAAAAAAJ1UW08TQRg9s72yFChFoRQvCFW5KFtuGmklMRhiQ7lEGozh
- abq7kOlll+xuG3gx/A3/hW8aTUyf/VHGb7YlarHUdJOd+WbmzDlnv/lmf/z8
- +h3AGp4zLHLLcGxhnGu6XTuzXVNz6pYnaqa25Y+FJ2yrYOu8uuNFwBjiZd7g
- WpVbp9p+qWzqNBtgSOgd6P0ThndzhYrtVYWllRs17aRu6XLZ1bbbUSY7X+gq
- f+DYDWHwUtXsNJJlOM8VNwqdRrKbvfRyi8VidrM/1Zy/lWG2YDunWtn0Sg4X
- RM4ty/Z4S2jP9vbqVWkwfROKIFKBYBtdjby+sHhN6N39RKAyhHPCEt4mueqd
- 6qMYYhhSMYhhhtU+MhBBnGHYME94veptc92znQuG6V7CDKnrxZFu0zCUezrP
- Xz/p/uomhhDCKhSMMyRdeRx6J0aW7Yuu3If+npsyNKkiJfM73Y3+6sNjSLa8
- 3GUYvcrArulxg3uccqbUGgG6o0w2IQZWkYFC8+dCRhmKjGUGo3kZV5uXqpJU
- VCWq+H3zMpWOUxNNBBPKGyXDZoJRgikr8agSD6TU1nSSZYKEC/0HTGqtMKz3
- eVlZkf4PV5/4Z12MdYKXKlQQwS3bMBlGCsIy9+q1kukUJbHkkJgj7gg5bk8O
- HIpTi3t1h+Kpty07eashXEHLr37fOrqSnasH3OE10zOdv2BDdMh6ZZeftQXU
- Q7vu6Oa2kIPJNsfRNX4s01kGIZ8gJmWhUb9Eo2cIgFEf+4bB9wufMdLE6Cd5
- ltCoDftrt5CRiBYOCYxRv+xjIlhpo6LUr9IboYRiAIgP0LbbFLdEFMiyGJoK
- fvhI9bKz8AUTLZU1aslB1Jcb9lEJIhwjwgQZTf7LaEoanfqH0WR/Ru/caPRe
- V6PjRDhBhOO0vO6DnhID8JLY7lOOp48RyONBHjPUYjaPNB7m8QiPj8FczGH+
- GGEXIRcLLhZdJFw8cZH8BUMfUaX/BgAA
- """,
- """
- androidx/compose/runtime/ProvidableCompositionLocal.class:
- H4sIAAAAAAAAAI1S308TQRD+9lracmIpRaHgLxAkAolXURNjK0YxDTUFURpe
- eNr2Ftz2umf29hp869/if+CTiQ+m8dE/yjjblogkBO5hZvabb76Z29nff378
- BPAUKwxPuPJ1KP0Trxl2PoeR8HSsjOwIb0+HXenzRiC2BhlpZKhqYZMHaTCG
- Srn+otbiXe4FXB177xst0TSlzdqFeudVyvV6abPEsHrlijSSDKmyVNJsMiw9
- rLVDE0jltbod7yhWTUuMvMooKpZWD0j9MlZ5fTCH5S7XQn3stYRpaC6Jw5UK
- DR/yd+MgsHdBA3+4tPHZvFRGaMUD76044nFgtohqdNw0od7hui00tZ5ACq6L
- MVxjSJpPMmJ4dvFFXrwYGi7rD9tUuO3whWHhsmEZpk4pO8JwnxtOmNPpJuiN
- MGvGGFiboBNpT0WK/McM7/q9vOsUHLff+99lVgr93loy0+/l2EYmn8w726zo
- vJklIJ/NJeZdCz3v9wqsmPz1NeXkxqziBjWpM6xf/QHRlPnTyc/+zvR54qO2
- oXvdCn3BMFmTSuzGnYbQdXuFVsNyDriW9jwCx/flseIm1hQvfxwOUFVdGUlK
- 73HNO4LW+vrfA2Fw98NYN0VF2vq5Uc3BsOIMMbkIhzZtP/pjWnwaCdyj0yvy
- Dvn02jr7jolvFDpYIOsO4AxRU1ikaGZIw3VkBzJpTCJHUvcHFRksWcxqj1OQ
- GMEJLA/8XTwg/5KyUzRF/hCJKqaruEEWN62ZqWIWhUOwCHOYP0QqQjbCrQi3
- I0xGuBMh/Rejxn6KQAQAAA==
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcclkZiXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbKiTkDBbILMnMz/PJT07M8S7hUuOSwaVeLy0/X4gtJLW4xLtEiUGL
+ AQBypVQ1cAAAAA==
""",
"""
androidx/compose/runtime/CompositionLocal.class:
@@ -124,20 +93,24 @@
JVwjixllrpdwAzd3wEJin9tBMsRIiFsh5kOMhlgIVeb2T+jXEMfzBAAA
""",
"""
- androidx/compose/runtime/StaticProvidableCompositionLocal.class:
- H4sIAAAAAAAAAJ1SXW8SQRQ9s3x2bSmlVmn9qhYT2yYurZqoIIk2aUpCKxHC
- C0/D7hQHll2zO0vqG7/Ff+CTiQ+G+OiPMt4BGqsJIek+3I8z55699878+v39
- B4DneMzwintO4EvnwrL9wSc/FFYQeUoOhNVQXEm7HvhD6fCOK44m51JJ36v5
- NndTYAz1cvN1rceH3HK517Xed3rCVqVKba7qfL1ys1mqlBieXaM2hThDsiw9
- qSoMO09qfV+50rN6w4F1Hnm2JobW8SwqlnZbDLuLWOX9SUeaW6j5QdfqCdUJ
- uCQO9zxfr0fzzyLX1T2VlpFEykQCJkNcfZQhQ2n+IhatlzaRccQ5j1x1zG3l
- B58ZthfNxbB2STkVijtcccKMwTBG9820STCwPkEXUmdFipwDhpPxKGcaecMc
- j/516fEoPx7txcln2WE6F88ZJ6xovNvIZbKxLVPnL4nCivGfX5JGNqH1DukX
- TYYX13kE1G3ucoKrY63/T3zaV7TlI98RDKs16YmzaNARQVOLag3NafFA6nwG
- LjVk1+MqCigufJi2UvWGMpR0XOcBHwglgrd/r5bBbPhRYItjqes3ZzWtacUV
- Ig5g0L3rj2bXzwAx3KesQrhBPrm3/w03vlJk4AFZc4JmqSaDbYpuTVlYxspE
- JUn4Kik9nFSk8Yh8SksvURCbwTHsTPw9FMi/oVMtuNZGrIpcFetkcVObjSr9
- 4HYbLEQem20kQ6yE2ApxJ0QmxN0QqT/sQJiNEwQAAA==
+ androidx/compose/runtime/CompositionLocalKt.class:
+ H4sIAAAAAAAAAJ1UW08TQRg9s72yFChFoRQvCFW5KFtuGmklMRhiQ7lEGozh
+ abq7kOlll+xuG3gx/A3/hW8aTUyf/VHGb7YlarHUdJOd+WbmzDlnv/lmf/z8
+ +h3AGp4zLHLLcGxhnGu6XTuzXVNz6pYnaqa25Y+FJ2yrYOu8uuNFwBjiZd7g
+ WpVbp9p+qWzqNBtgSOgd6P0ThndzhYrtVYWllRs17aRu6XLZ1bbbUSY7X+gq
+ f+DYDWHwUtXsNJJlOM8VNwqdRrKbvfRyi8VidrM/1Zy/lWG2YDunWtn0Sg4X
+ RM4ty/Z4S2jP9vbqVWkwfROKIFKBYBtdjby+sHhN6N39RKAyhHPCEt4mueqd
+ 6qMYYhhSMYhhhtU+MhBBnGHYME94veptc92znQuG6V7CDKnrxZFu0zCUezrP
+ Xz/p/uomhhDCKhSMMyRdeRx6J0aW7Yuu3If+npsyNKkiJfM73Y3+6sNjSLa8
+ 3GUYvcrArulxg3uccqbUGgG6o0w2IQZWkYFC8+dCRhmKjGUGo3kZV5uXqpJU
+ VCWq+H3zMpWOUxNNBBPKGyXDZoJRgikr8agSD6TU1nSSZYKEC/0HTGqtMKz3
+ eVlZkf4PV5/4Z12MdYKXKlQQwS3bMBlGCsIy9+q1kukUJbHkkJgj7gg5bk8O
+ HIpTi3t1h+Kpty07eashXEHLr37fOrqSnasH3OE10zOdv2BDdMh6ZZeftQXU
+ Q7vu6Oa2kIPJNsfRNX4s01kGIZ8gJmWhUb9Eo2cIgFEf+4bB9wufMdLE6Cd5
+ ltCoDftrt5CRiBYOCYxRv+xjIlhpo6LUr9IboYRiAIgP0LbbFLdEFMiyGJoK
+ fvhI9bKz8AUTLZU1aslB1Jcb9lEJIhwjwgQZTf7LaEoanfqH0WR/Ru/caPRe
+ V6PjRDhBhOO0vO6DnhID8JLY7lOOp48RyONBHjPUYjaPNB7m8QiPj8FczGH+
+ GGEXIRcLLhZdJFw8cZH8BUMfUaX/BgAA
""",
"""
androidx/compose/runtime/DynamicProvidableCompositionLocal.class:
@@ -156,14 +129,40 @@
Drh7BBajjMUjZGPMxFiKcS9GIcb9GLk/6rXJ3BUEAAA=
""",
"""
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcclkZiXUpSfmVKhl5yfW5BfnKpX
- VJpXkpmbKiTkDBbILMnMz/PJT07M8S7hUuOSwaVeLy0/X4gtJLW4xLtEiUGL
- AQBypVQ1cAAAAA==
+ androidx/compose/runtime/ProvidableCompositionLocal.class:
+ H4sIAAAAAAAAAI1S308TQRD+9lracmIpRaHgLxAkAolXURNjK0YxDTUFURpe
+ eNr2Ftz2umf29hp869/if+CTiQ+m8dE/yjjblogkBO5hZvabb76Z29nff378
+ BPAUKwxPuPJ1KP0Trxl2PoeR8HSsjOwIb0+HXenzRiC2BhlpZKhqYZMHaTCG
+ Srn+otbiXe4FXB177xst0TSlzdqFeudVyvV6abPEsHrlijSSDKmyVNJsMiw9
+ rLVDE0jltbod7yhWTUuMvMooKpZWD0j9MlZ5fTCH5S7XQn3stYRpaC6Jw5UK
+ DR/yd+MgsHdBA3+4tPHZvFRGaMUD76044nFgtohqdNw0od7hui00tZ5ACq6L
+ MVxjSJpPMmJ4dvFFXrwYGi7rD9tUuO3whWHhsmEZpk4pO8JwnxtOmNPpJuiN
+ MGvGGFiboBNpT0WK/McM7/q9vOsUHLff+99lVgr93loy0+/l2EYmn8w726zo
+ vJklIJ/NJeZdCz3v9wqsmPz1NeXkxqziBjWpM6xf/QHRlPnTyc/+zvR54qO2
+ oXvdCn3BMFmTSuzGnYbQdXuFVsNyDriW9jwCx/flseIm1hQvfxwOUFVdGUlK
+ 73HNO4LW+vrfA2Fw98NYN0VF2vq5Uc3BsOIMMbkIhzZtP/pjWnwaCdyj0yvy
+ Dvn02jr7jolvFDpYIOsO4AxRU1ikaGZIw3VkBzJpTCJHUvcHFRksWcxqj1OQ
+ GMEJLA/8XTwg/5KyUzRF/hCJKqaruEEWN62ZqWIWhUOwCHOYP0QqQjbCrQi3
+ I0xGuBMh/Rejxn6KQAQAAA==
+ """,
+ """
+ androidx/compose/runtime/StaticProvidableCompositionLocal.class:
+ H4sIAAAAAAAAAJ1SXW8SQRQ9s3x2bSmlVmn9qhYT2yYurZqoIIk2aUpCKxHC
+ C0/D7hQHll2zO0vqG7/Ff+CTiQ+G+OiPMt4BGqsJIek+3I8z55699878+v39
+ B4DneMzwintO4EvnwrL9wSc/FFYQeUoOhNVQXEm7HvhD6fCOK44m51JJ36v5
+ NndTYAz1cvN1rceH3HK517Xed3rCVqVKba7qfL1ys1mqlBieXaM2hThDsiw9
+ qSoMO09qfV+50rN6w4F1Hnm2JobW8SwqlnZbDLuLWOX9SUeaW6j5QdfqCdUJ
+ uCQO9zxfr0fzzyLX1T2VlpFEykQCJkNcfZQhQ2n+IhatlzaRccQ5j1x1zG3l
+ B58ZthfNxbB2STkVijtcccKMwTBG9820STCwPkEXUmdFipwDhpPxKGcaecMc
+ j/516fEoPx7txcln2WE6F88ZJ6xovNvIZbKxLVPnL4nCivGfX5JGNqH1DukX
+ TYYX13kE1G3ucoKrY63/T3zaV7TlI98RDKs16YmzaNARQVOLag3NafFA6nwG
+ LjVk1+MqCigufJi2UvWGMpR0XOcBHwglgrd/r5bBbPhRYItjqes3ZzWtacUV
+ Ig5g0L3rj2bXzwAx3KesQrhBPrm3/w03vlJk4AFZc4JmqSaDbYpuTVlYxspE
+ JUn4Kik9nFSk8Yh8SksvURCbwTHsTPw9FMi/oVMtuNZGrIpcFetkcVObjSr9
+ 4HYbLEQem20kQ6yE2ApxJ0QmxN0QqT/sQJiNEwQAAA==
"""
)
- @Ignore // b/193270279
@Test
fun noLocalPrefix() {
lint().files(
diff --git a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt
index e2b7f66..7d52bb5 100644
--- a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt
+++ b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt
@@ -22,7 +22,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -39,7 +38,6 @@
override fun getIssues(): MutableList<Issue> =
mutableListOf(RememberDetector.RememberReturnType)
- @Ignore // b/193270279
@Test
fun returnsUnit() {
lint().files(
@@ -123,6 +121,9 @@
Stubs.Composable,
Stubs.Remember
)
+ // TODO: incorrect missing import warning, because androidx.compose.runtime.remember
+ // resolves to multiple functions. Remove when this is fixed in a future Lint version
+ .allowCompilationErrors()
.run()
.expect(
"""
@@ -161,7 +162,6 @@
)
}
- @Ignore // b/193270279
@Test
fun returnsValue_explicitUnitType() {
lint().files(
@@ -245,6 +245,9 @@
Stubs.Composable,
Stubs.Remember
)
+ // TODO: incorrect missing import warning, because androidx.compose.runtime.remember
+ // resolves to multiple functions. Remove when this is fixed in a future Lint version
+ .allowCompilationErrors()
.run()
.expect(
"""
@@ -283,7 +286,6 @@
)
}
- @Ignore // b/193270279
@Test
fun noErrors() {
lint().files(
@@ -357,6 +359,9 @@
Stubs.Composable,
Stubs.Remember
)
+ // TODO: incorrect missing import warning, because androidx.compose.runtime.remember
+ // resolves to multiple functions. Remove when this is fixed in a future Lint version
+ .allowCompilationErrors()
.run()
.expectClean()
}
diff --git a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/UnrememberedMutableStateDetectorTest.kt b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/UnrememberedMutableStateDetectorTest.kt
index ea7f9f5..1a307c6 100644
--- a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/UnrememberedMutableStateDetectorTest.kt
+++ b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/UnrememberedMutableStateDetectorTest.kt
@@ -22,7 +22,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -39,7 +38,6 @@
override fun getIssues(): MutableList<Issue> =
mutableListOf(UnrememberedMutableStateDetector.UnrememberedMutableState)
- @Ignore // b/193270279
@Test
fun notRemembered() {
lint().files(
@@ -193,7 +191,6 @@
)
}
- @Ignore // b/193270279
@Test
fun rememberedInsideComposableBody() {
lint().files(
@@ -283,7 +280,6 @@
.expectClean()
}
- @Ignore // b/193270279
@Test
fun noErrors() {
lint().files(
diff --git a/compose/runtime/runtime-livedata/build.gradle b/compose/runtime/runtime-livedata/build.gradle
index 571700c..0ae4cea 100644
--- a/compose/runtime/runtime-livedata/build.gradle
+++ b/compose/runtime/runtime-livedata/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
@@ -34,8 +34,8 @@
api("androidx.lifecycle:lifecycle-livedata:2.2.0")
implementation("androidx.compose.ui:ui:1.0.0")
- androidTestImplementation(project(":compose:ui:ui-test-junit4"))
- androidTestImplementation(project(":compose:test-utils"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
+ androidTestImplementation(projectOrArtifact(":compose:test-utils"))
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.junit)
androidTestImplementation(libs.truth)
diff --git a/compose/runtime/runtime-livedata/samples/build.gradle b/compose/runtime/runtime-livedata/samples/build.gradle
index 7ed3f26..d1a1739 100644
--- a/compose/runtime/runtime-livedata/samples/build.gradle
+++ b/compose/runtime/runtime-livedata/samples/build.gradle
@@ -26,13 +26,13 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
- compileOnly(project(":annotation:annotation-sampled"))
+ compileOnly(projectOrArtifact(":annotation:annotation-sampled"))
implementation("androidx.compose.foundation:foundation:1.0.0")
implementation("androidx.compose.material:material:1.0.0")
- implementation(project(":compose:runtime:runtime-livedata"))
+ implementation(projectOrArtifact(":compose:runtime:runtime-livedata"))
}
androidx {
diff --git a/compose/runtime/runtime-rxjava2/build.gradle b/compose/runtime/runtime-rxjava2/build.gradle
index a5299b3..0b781ff 100644
--- a/compose/runtime/runtime-rxjava2/build.gradle
+++ b/compose/runtime/runtime-rxjava2/build.gradle
@@ -26,15 +26,15 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
api(project(":compose:runtime:runtime"))
api(libs.rxjava2)
- androidTestImplementation(project(":compose:ui:ui-test-junit4"))
- androidTestImplementation(project(":compose:test-utils"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
+ androidTestImplementation(projectOrArtifact(":compose:test-utils"))
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.junit)
androidTestImplementation(libs.truth)
diff --git a/compose/runtime/runtime-rxjava2/samples/build.gradle b/compose/runtime/runtime-rxjava2/samples/build.gradle
index ba79184..d451505 100644
--- a/compose/runtime/runtime-rxjava2/samples/build.gradle
+++ b/compose/runtime/runtime-rxjava2/samples/build.gradle
@@ -26,13 +26,13 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
- compileOnly(project(":annotation:annotation-sampled"))
+ compileOnly(projectOrArtifact(":annotation:annotation-sampled"))
implementation("androidx.compose.foundation:foundation:1.0.0")
implementation("androidx.compose.material:material:1.0.0")
- implementation(project(":compose:runtime:runtime-rxjava2"))
+ implementation(projectOrArtifact(":compose:runtime:runtime-rxjava2"))
}
androidx {
diff --git a/compose/runtime/runtime-rxjava3/build.gradle b/compose/runtime/runtime-rxjava3/build.gradle
index 3ac8f8c5..f63fc46 100644
--- a/compose/runtime/runtime-rxjava3/build.gradle
+++ b/compose/runtime/runtime-rxjava3/build.gradle
@@ -26,15 +26,15 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
api(project(":compose:runtime:runtime"))
api(libs.rxjava3)
- androidTestImplementation(project(":compose:ui:ui-test-junit4"))
- androidTestImplementation(project(":compose:test-utils"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
+ androidTestImplementation(projectOrArtifact(":compose:test-utils"))
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.junit)
androidTestImplementation(libs.truth)
diff --git a/compose/runtime/runtime-rxjava3/samples/build.gradle b/compose/runtime/runtime-rxjava3/samples/build.gradle
index 5580e54..2c9f9ec 100644
--- a/compose/runtime/runtime-rxjava3/samples/build.gradle
+++ b/compose/runtime/runtime-rxjava3/samples/build.gradle
@@ -26,13 +26,13 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
- compileOnly(project(":annotation:annotation-sampled"))
+ compileOnly(projectOrArtifact(":annotation:annotation-sampled"))
implementation("androidx.compose.foundation:foundation:1.0.0")
implementation("androidx.compose.material:material:1.0.0")
- implementation(project(":compose:runtime:runtime-rxjava3"))
+ implementation(projectOrArtifact(":compose:runtime:runtime-rxjava3"))
}
androidx {
diff --git a/compose/runtime/runtime-saveable-lint/build.gradle b/compose/runtime/runtime-saveable-lint/build.gradle
index 37c4b6f..ce48943 100644
--- a/compose/runtime/runtime-saveable-lint/build.gradle
+++ b/compose/runtime/runtime-saveable-lint/build.gradle
@@ -29,9 +29,9 @@
dependencies {
compileOnly(libs.androidLintMinComposeApi)
compileOnly(libs.kotlinStdlib)
- bundleInside(project(":compose:lint:common"))
+ bundleInside(projectOrArtifact(":compose:lint:common"))
- testImplementation(project(":compose:lint:common-test"))
+ testImplementation(projectOrArtifact(":compose:lint:common-test"))
testImplementation(libs.kotlinStdlib)
testImplementation(libs.androidLint)
testImplementation(libs.androidLintTests)
diff --git a/compose/runtime/runtime-saveable-lint/src/test/java/androidx/compose/runtime/saveable/lint/RememberSaveableDetectorTest.kt b/compose/runtime/runtime-saveable-lint/src/test/java/androidx/compose/runtime/saveable/lint/RememberSaveableDetectorTest.kt
index 2fadca1..b5ea2e6 100644
--- a/compose/runtime/runtime-saveable-lint/src/test/java/androidx/compose/runtime/saveable/lint/RememberSaveableDetectorTest.kt
+++ b/compose/runtime/runtime-saveable-lint/src/test/java/androidx/compose/runtime/saveable/lint/RememberSaveableDetectorTest.kt
@@ -24,7 +24,6 @@
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -43,6 +42,7 @@
private val rememberSaveableStub: TestFile = compiledStub(
filename = "RememberSaveable.kt",
filepath = "androidx/compose/runtime/saveable",
+ checksum = 0x90b6d5a7,
"""
package androidx.compose.runtime.saveable
@@ -80,15 +80,10 @@
Any() as Saver<MutableState<T>, MutableState<Any?>>
""",
"""
- androidx/compose/runtime/saveable/Saver.class:
- H4sIAAAAAAAAAI1PTUvDQBB9m/QjjVVT60f9BWIOphZBUBG8CJVKoQEvPW2b
- tWzbbCS7LT3md3mQnP1R4sTai3pwYd6bffOGmXn/eH0DcIEWwwlXUZrIaBWM
- k/gl0SJIF8rIWASaLwUfzUUQUpJWwRgebvqpnEjF51e9KV/yYM7VJOiPpmJs
- rsNv/x+l298Sg/dTq6LE0OjNEjOXKngUhkfccHJa8dKmfVkBZQY2I2kli1+b
- suicwc+zumu1LNdyKLw8c55beeaXnDzzmO84zLN8q213KIqODsNp75+H03xn
- czWlmysZ7YPmQMQiHol0o57NDEMtlBPFzSIlkxsmi3Qs7mXRcTxYT3iSWpL5
- TqnEcCMTpSu0FcpYPxsHhBbx4Rfv44j4kuZVyFMdwu7C6aJGCLeArS7q2B6C
- aexgd4iShqfR0NjTaH4C2V0QQe0BAAA=
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcUlkZiXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbKsTnW1qSmJSTGlySWJLqXcJlzqWIS61ecWJZKkitkFBQam5qblJq
+ UTBUBKiRl4ulJLW4RIjVLT/fu0SJQYsBAFB+NmSMAAAA
""",
"""
androidx/compose/runtime/saveable/RememberSaveableKt.class:
@@ -124,14 +119,18 @@
wsGog48crDuYd1BwcNOh/zoQ9zh9Di57xICDooOwgykHmX8BaeisIyQPAAA=
""",
"""
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcUlkZiXUpSfmVKhl5yfW5BfnKpX
- VJpXkpmbKsTnW1qSmJSTGlySWJLqXcJlzqWIS61ecWJZKkitkFBQam5qblJq
- UTBUBKiRl4ulJLW4RIjVLT/fu0SJQYsBAFB+NmSMAAAA
+ androidx/compose/runtime/saveable/Saver.class:
+ H4sIAAAAAAAAAI1PTUvDQBB9m/QjjVVT60f9BWIOphZBUBG8CJVKoQEvPW2b
+ tWzbbCS7LT3md3mQnP1R4sTai3pwYd6bffOGmXn/eH0DcIEWwwlXUZrIaBWM
+ k/gl0SJIF8rIWASaLwUfzUUQUpJWwRgebvqpnEjF51e9KV/yYM7VJOiPpmJs
+ rsNv/x+l298Sg/dTq6LE0OjNEjOXKngUhkfccHJa8dKmfVkBZQY2I2kli1+b
+ suicwc+zumu1LNdyKLw8c55beeaXnDzzmO84zLN8q213KIqODsNp75+H03xn
+ czWlmysZ7YPmQMQiHol0o57NDEMtlBPFzSIlkxsmi3Qs7mXRcTxYT3iSWpL5
+ TqnEcCMTpSu0FcpYPxsHhBbx4Rfv44j4kuZVyFMdwu7C6aJGCLeArS7q2B6C
+ aexgd4iShqfR0NjTaH4C2V0QQe0BAAA=
"""
)
- @Ignore // b/193270279
@Test
fun saverPassedToVarargs() {
lint().files(
@@ -233,7 +232,6 @@
)
}
- @Ignore // b/193270279
@Test
fun noErrors() {
lint().files(
diff --git a/compose/runtime/runtime-saveable/build.gradle b/compose/runtime/runtime-saveable/build.gradle
index e5fcce5..1743df4 100644
--- a/compose/runtime/runtime-saveable/build.gradle
+++ b/compose/runtime/runtime-saveable/build.gradle
@@ -28,7 +28,7 @@
AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
dependencies {
- kotlinPlugin project(":compose:compiler:compiler")
+ kotlinPlugin projectOrArtifact(":compose:compiler:compiler")
if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
/* When updating dependencies, make sure to make the an an analogous update in the
@@ -43,11 +43,11 @@
testImplementation(libs.testCore)
testImplementation(libs.testRules)
- androidTestImplementation project(':compose:ui:ui')
- androidTestImplementation project(":compose:ui:ui-test-junit4")
- androidTestImplementation project(":compose:test-utils")
+ androidTestImplementation projectOrArtifact(':compose:ui:ui')
+ androidTestImplementation projectOrArtifact(":compose:ui:ui-test-junit4")
+ androidTestImplementation projectOrArtifact(":compose:test-utils")
androidTestImplementation "androidx.fragment:fragment:1.3.0"
- androidTestImplementation project(":activity:activity-compose")
+ androidTestImplementation projectOrArtifact(":activity:activity-compose")
androidTestImplementation(libs.testUiautomator)
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRules)
diff --git a/compose/runtime/runtime-saveable/samples/build.gradle b/compose/runtime/runtime-saveable/samples/build.gradle
index ac95521..7706813 100644
--- a/compose/runtime/runtime-saveable/samples/build.gradle
+++ b/compose/runtime/runtime-saveable/samples/build.gradle
@@ -26,14 +26,14 @@
}
dependencies {
- kotlinPlugin project(":compose:compiler:compiler")
+ kotlinPlugin projectOrArtifact(":compose:compiler:compiler")
implementation(libs.kotlinStdlib)
- compileOnly project(":annotation:annotation-sampled")
+ compileOnly projectOrArtifact(":annotation:annotation-sampled")
- implementation project(":compose:foundation:foundation")
- implementation project(":compose:material:material")
+ implementation projectOrArtifact(":compose:foundation:foundation")
+ implementation projectOrArtifact(":compose:material:material")
implementation project(":compose:runtime:runtime")
implementation project(":compose:runtime:runtime-saveable")
}
diff --git a/compose/runtime/runtime/build.gradle b/compose/runtime/runtime/build.gradle
index ea291db..4a85e73 100644
--- a/compose/runtime/runtime/build.gradle
+++ b/compose/runtime/runtime/build.gradle
@@ -29,7 +29,7 @@
AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
/*
@@ -54,8 +54,8 @@
androidTestImplementation(libs.junit)
androidTestImplementation(libs.truth)
- lintChecks(project(":compose:runtime:runtime-lint"))
- lintPublish(project(":compose:runtime:runtime-lint"))
+ lintChecks(projectOrArtifact(":compose:runtime:runtime-lint"))
+ lintPublish(projectOrArtifact(":compose:runtime:runtime-lint"))
}
}
diff --git a/compose/runtime/runtime/compose-runtime-benchmark/build.gradle b/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
index de24070..a569c881 100644
--- a/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
+++ b/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
@@ -31,16 +31,16 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
- androidTestImplementation(project(":compose:ui:ui"))
- androidTestImplementation(project(":compose:ui:ui-test-junit4"))
- androidTestImplementation(project(":compose:foundation:foundation"))
- androidTestImplementation(project(":compose:foundation:foundation-layout"))
- androidTestImplementation(project(":compose:material:material"))
- androidTestImplementation(project(":compose:runtime:runtime"))
- androidTestImplementation(project(":compose:ui:ui-text"))
- androidTestImplementation(project(":compose:ui:ui-util"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
+ androidTestImplementation(projectOrArtifact(":compose:foundation:foundation"))
+ androidTestImplementation(projectOrArtifact(":compose:foundation:foundation-layout"))
+ androidTestImplementation(projectOrArtifact(":compose:material:material"))
+ androidTestImplementation(projectOrArtifact(":compose:runtime:runtime"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui-text"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui-util"))
androidTestImplementation(libs.junit)
androidTestImplementation(libs.testExtJunit)
@@ -49,11 +49,11 @@
androidTestImplementation(libs.testRules)
androidTestImplementation(libs.kotlinStdlib)
androidTestImplementation(libs.kotlinReflect)
- androidTestImplementation(project(":benchmark:benchmark-junit4"))
+ androidTestImplementation(projectOrArtifact(":benchmark:benchmark-junit4"))
androidTestImplementation("androidx.activity:activity:1.2.0")
- androidTestImplementation(project(":activity:activity-compose"))
+ androidTestImplementation(projectOrArtifact(":activity:activity-compose"))
}
androidx {
benchmarkRunAlsoInterpreted = true
-}
\ No newline at end of file
+}
diff --git a/compose/runtime/runtime/integration-tests/build.gradle b/compose/runtime/runtime/integration-tests/build.gradle
index 65a8c1d..d26ace2 100644
--- a/compose/runtime/runtime/integration-tests/build.gradle
+++ b/compose/runtime/runtime/integration-tests/build.gradle
@@ -27,14 +27,14 @@
AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
- androidTestImplementation(project(":compose:ui:ui"))
- androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui"))
+ androidTestImplementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
androidTestImplementation(project(":compose:runtime:runtime"))
- androidTestImplementation(project(":compose:test-utils"))
- androidTestImplementation(project(":activity:activity-compose"))
+ androidTestImplementation(projectOrArtifact(":compose:test-utils"))
+ androidTestImplementation(projectOrArtifact(":activity:activity-compose"))
androidTestImplementation(libs.junit)
androidTestImplementation(libs.kotlinTestJunit)
@@ -61,7 +61,7 @@
commonMain.dependencies {
implementation(libs.kotlinStdlibCommon)
implementation(libs.kotlinCoroutinesCore)
- implementation(project(":compose:ui:ui"))
+ implementation(projectOrArtifact(":compose:ui:ui"))
}
jvmMain.dependencies {
implementation(libs.kotlinStdlib)
@@ -87,10 +87,10 @@
implementation(kotlin("test-junit"))
}
androidAndroidTest.dependencies {
- implementation(project(":compose:ui:ui"))
- implementation(project(":compose:ui:ui-test-junit4"))
- implementation(project(":compose:test-utils"))
- implementation(project(":activity:activity-compose"))
+ implementation(projectOrArtifact(":compose:ui:ui"))
+ implementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
+ implementation(projectOrArtifact(":compose:test-utils"))
+ implementation(projectOrArtifact(":activity:activity-compose"))
implementation(libs.testExtJunit)
implementation(libs.testRules)
implementation(libs.testRunner)
diff --git a/compose/runtime/runtime/samples/build.gradle b/compose/runtime/runtime/samples/build.gradle
index 1c32eb2..f1304c2 100644
--- a/compose/runtime/runtime/samples/build.gradle
+++ b/compose/runtime/runtime/samples/build.gradle
@@ -26,11 +26,11 @@
}
dependencies {
- kotlinPlugin(project(":compose:compiler:compiler"))
+ kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
- compileOnly(project(":annotation:annotation-sampled"))
+ compileOnly(projectOrArtifact(":annotation:annotation-sampled"))
implementation("androidx.compose.foundation:foundation-layout:1.0.0")
implementation("androidx.compose.material:material:1.0.0")
implementation(project(":compose:runtime:runtime"))
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
index 3c2b1fb..87b346a 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
@@ -28,5 +28,5 @@
* IMPORTANT: Whenever updating this value, please make sure to also update `versionTable` and
* `minimumRuntimeVersionInt` in `VersionChecker.kt` of the compiler.
*/
- const val version: Int = 4100
+ const val version: Int = 4200
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MonotonicFrameClock.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MonotonicFrameClock.kt
index dcc1c59..10c81dd 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MonotonicFrameClock.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MonotonicFrameClock.kt
@@ -78,8 +78,8 @@
* completes it must not provide the same value again for a subsequent call.
*
* This function will invoke [MonotonicFrameClock.withFrameNanos] using the calling
- * [CoroutineContext]'s [MonotonicFrameClock] or a default frame clock if one is not present
- * in the [CoroutineContext].
+ * [CoroutineContext]'s [MonotonicFrameClock] and will throw an [IllegalStateException] if one is
+ * not present in the [CoroutineContext].
*/
@OptIn(ExperimentalComposeApi::class)
suspend fun <R> withFrameNanos(onFrame: (frameTimeMillis: Long) -> R): R =
@@ -100,8 +100,8 @@
* a subsequent call.
*
* This function will invoke [MonotonicFrameClock.withFrameNanos] using the calling
- * [CoroutineContext]'s [MonotonicFrameClock] or a default frame clock if one is not present
- * in the [CoroutineContext].
+ * [CoroutineContext]'s [MonotonicFrameClock] and will throw an [IllegalStateException] if one is
+ * not present in the [CoroutineContext].
*/
@OptIn(ExperimentalComposeApi::class)
suspend fun <R> withFrameMillis(onFrame: (frameTimeMillis: Long) -> R): R =
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
index 74e3053..cf481a3 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
@@ -97,9 +97,10 @@
startIndex = index + 1,
endIndex = size
)
- keys[size] = null
- values[size] = null
- this.size = size - 1
+ val newSize = size - 1
+ keys[newSize] = null
+ values[newSize] = null
+ this.size = newSize
return true
}
return false
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/Decoy.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/Decoy.kt
index 0dfd7ec..d93794f 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/Decoy.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/Decoy.kt
@@ -56,3 +56,16 @@
@ExperimentalComposeApi
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
annotation class DecoyImplementation(val name: String, val id: Long)
+
+/**
+ * Complements [DecoyImplementation] with extra information about default values for parameters.
+ * Default values are erased and not present in klib.
+ * This annotation uses [bitMask] to store the information about default values in original (decoy)
+ * functions.
+ *
+ * @param bitMask keeps the flags of default values presence.
+ */
+@Suppress("unused")
+@ExperimentalComposeApi
+@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
+internal annotation class DecoyImplementationDefaultsBitMask(val bitMask: Int)
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt
index b4f9bec..f615fb9 100644
--- a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt
@@ -105,4 +105,19 @@
}
}
}
+
+ @Test // b/195621739
+ fun canRemoveWhenFull() {
+ val map = IdentityArrayMap<Key, String>()
+ repeat(16) {
+ map[keys[it]] = it.toString()
+ }
+ repeat(16) {
+ val key = keys[it]
+ val removed = map.remove(key)
+ assertTrue(removed)
+ assertFalse(map.contains(key))
+ }
+ assertTrue(map.isEmpty())
+ }
}
\ No newline at end of file
diff --git a/compose/runtime/settings.gradle b/compose/runtime/settings.gradle
new file mode 100644
index 0000000..a76317c
--- /dev/null
+++ b/compose/runtime/settings.gradle
@@ -0,0 +1,12 @@
+rootProject.name = "compose-runtime"
+apply from: "../../playground-common/playground-include-settings.gradle"
+setupPlayground(this, "../..")
+
+selectProjectsFromAndroidX({ name ->
+ if (name.startsWith(":compose:runtime") && name != ":compose:runtime") return true
+ if (name == ":annotation:annotation-sampled") return true
+ if (isNeededForComposePlayground(name)) return true
+ return false
+})
+
+
diff --git a/compose/test-utils/lint-baseline.xml b/compose/test-utils/lint-baseline.xml
new file mode 100644
index 0000000..75d53c0
--- /dev/null
+++ b/compose/test-utils/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" view = findViewRootForTest(activity)!!.view"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt"
+ line="126"
+ column="48"/>
+ </issue>
+
+</issues>
diff --git a/compose/ui/ui-graphics-lint/src/test/java/androidx/compose/ui/graphics/lint/ColorDetectorTest.kt b/compose/ui/ui-graphics-lint/src/test/java/androidx/compose/ui/graphics/lint/ColorDetectorTest.kt
index 4ba5cae..c12d4b1 100644
--- a/compose/ui/ui-graphics-lint/src/test/java/androidx/compose/ui/graphics/lint/ColorDetectorTest.kt
+++ b/compose/ui/ui-graphics-lint/src/test/java/androidx/compose/ui/graphics/lint/ColorDetectorTest.kt
@@ -22,7 +22,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -42,7 +41,6 @@
ColorDetector.InvalidColorHexValue
)
- @Ignore // b/193270279
@Test
fun MissingColorAlphaChannel() {
lint().files(
@@ -112,7 +110,6 @@
)
}
- @Ignore // b/193270279
@Test
fun incorrectChannels() {
lint().files(
diff --git a/compose/ui/ui-graphics/benchmark/build.gradle b/compose/ui/ui-graphics/benchmark/build.gradle
index 9670e0f..90bdbca 100644
--- a/compose/ui/ui-graphics/benchmark/build.gradle
+++ b/compose/ui/ui-graphics/benchmark/build.gradle
@@ -32,6 +32,5 @@
implementation(libs.kotlinStdlib)
androidTestImplementation project(":benchmark:benchmark-junit4")
- androidTestImplementation project(":benchmark:benchmark-macro-junit4")
androidTestImplementation(libs.testRules)
}
diff --git a/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
index d4e4318..33af974 100644
--- a/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
+++ b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
@@ -16,7 +16,7 @@
package androidx.compose.ui.graphics.benchmark
-import androidx.benchmark.macro.junit4.PerfettoRule
+import androidx.benchmark.junit4.PerfettoRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import org.junit.Rule
diff --git a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt
index aaeacd9..2eceb87 100644
--- a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt
+++ b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt
@@ -20,6 +20,7 @@
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
@@ -61,7 +62,8 @@
/**
* Convert Compose [Painter] to AWT [Image]. The result will not be rasterized right now, it
* will be rasterized when AWT will request the image with needed width and height, by calling
- * [AbstractMultiResolutionImage.getResolutionVariant]
+ * [AbstractMultiResolutionImage.getResolutionVariant] on Windows/Linux, or
+ * [AbstractMultiResolutionImage.getResolutionVariants] on macOs.
*
* At the rasterization moment, [density] and [layoutDirection] will be passed to the painter.
* Usually most painters don't use them. Like the painters for svg/xml/raster resources:
@@ -90,10 +92,12 @@
private val painter: Painter,
private val density: Density,
private val layoutDirection: LayoutDirection,
- private val size: Size,
+ size: Size,
) : Image(), MultiResolutionImage {
- override fun getWidth(observer: ImageObserver?) = size.width.toInt()
- override fun getHeight(observer: ImageObserver?) = size.height.toInt()
+ private val width = size.width.toInt()
+ private val height = size.height.toInt()
+ override fun getWidth(observer: ImageObserver?) = width
+ override fun getHeight(observer: ImageObserver?) = height
override fun getResolutionVariant(
destImageWidth: Double,
@@ -138,9 +142,20 @@
"getGraphics() not supported"
)
- override fun getResolutionVariants() = throw UnsupportedOperationException(
- "getResolutionVariants() not supported"
- )
+ // AWT only calls this field on macOs
+ private val _resolutionVariants by lazy {
+ // optimizations to avoid unnecessary rasterizations
+ when (painter) {
+ is BufferedImagePainter -> listOf(painter.image)
+ is BitmapPainter -> listOf(asBitmap(width, height).asAwtImage())
+ else -> listOf(
+ asBitmap(width, height).asAwtImage(), // for usual displays
+ asBitmap(width * 2, height * 2).asAwtImage(), // for retina displays
+ )
+ }
+ }
+
+ override fun getResolutionVariants() = _resolutionVariants
}
// TODO(demin): should we optimize toAwtImage/toBitmap? Currently we convert colors according to the
diff --git a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ComposedModifierDetectorTest.kt b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ComposedModifierDetectorTest.kt
index 00a46f9..2a11064 100644
--- a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ComposedModifierDetectorTest.kt
+++ b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ComposedModifierDetectorTest.kt
@@ -23,7 +23,6 @@
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -46,6 +45,7 @@
private val composedStub = compiledStub(
filename = "ComposedModifier.kt",
filepath = "androidx/compose/ui",
+ checksum = 0xad91cb77,
"""
package androidx.compose.ui
@@ -57,6 +57,12 @@
): Modifier = this
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcYlkZiXUpSfmVKhl5yfW5BfnKpX
+ VJpXkpmbKsQVlJqbmpuUWuRdwqXJJYyhrjRTSMgZwk7xzU/JTMsEK+XjYilJ
+ LS4RYgsBkt4lSgxaDACMRj6sewAAAA==
+ """,
+ """
androidx/compose/ui/ComposedModifierKt$composed$1.class:
H4sIAAAAAAAAAJVUWU8TURT+7nQfipRFWdy1YgvKtOCaNiSEQJxQMBFsYni6
7Qxw6fSOmaXBN/6C/0Q0kUQTw7M/ynjutDW4gU4y956c831nn/n67dMXAA/w
@@ -96,16 +102,9 @@
nzerS8vvURmSWSVJKBMRq8mISZr+Gfqcpcl6RnaOwGYjZjNYi5K+wHN6b9D6
PYK/v4OEjQc2Fkhi0UYVSzaW8XAHLMAjWDvIBkgFuBFgKkCNehegFGAlwOMA
T/4BiHoaCXoHAAA=
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcklnJiXUpSfmVKhl5yfW5BfnKpX
- mikk5Axhp/jmp2SmZaYWeZdwKXKJY1Gql5afL8QWklpc4l2ixKDFAACfEiWG
- ZgAAAA==
"""
)
- @Ignore // b/193270279
@Test
fun noComposableCalls() {
lint().files(
@@ -167,8 +166,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
- import androidx.compose.runtime.Composable
- import androidx.compose.runtime.remember
+ import androidx.compose.runtime.*
inline fun <T> scopingFunction(lambda: () -> T): T {
return lambda()
@@ -228,7 +226,6 @@
Stubs.Modifier,
Stubs.Remember
)
- .allowCompilationErrors(true) // b/193270279
.run()
.expectClean()
}
diff --git a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ModifierDeclarationDetectorTest.kt b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ModifierDeclarationDetectorTest.kt
index 7fd93da9..3f7fa36 100644
--- a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ModifierDeclarationDetectorTest.kt
+++ b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/ModifierDeclarationDetectorTest.kt
@@ -48,12 +48,18 @@
private val DensityStub = compiledStub(
filename = "Density.kt",
filepath = "androidx/compose/ui/unit",
+ checksum = 0xaa534a7a,
"""
package androidx.compose.ui.unit
interface Density
""",
-"""
+ """
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcIlnpiXUpSfmVKhl5yfW5BfnKpX
+ mqmXlp8vxOmWn++SWJLoXaLEoMUAAALEmjo+AAAA
+ """,
+ """
androidx/compose/ui/unit/Density.class:
H4sIAAAAAAAAAIVOTUvDQBB9s7FNjV+pH1Bv4g9w2+LNkyBCoCIoeMlpm6yy
Tbor3U2pt/4uD9KzP0qcqHdn4M17M/DefH69fwC4xDHhTNly4Uy5koWbvzqv
@@ -61,11 +67,6 @@
RuxNLXQIVPFqZVo1ZFaOCCebdS8RA5GIlNnzYLMeiyG1xzHhfPLfP5wBQvKn
LqrA4tE1i0LfmloTTh8aG8xcPxlvprW+ttYFFYyzvssZ2MJvCRz+YB9HPEds
2eHu5ogyxBl6jNhuIcmwg90c5LGH/RzC48Aj/QaMxaG1RAEAAA==
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcIlnpiXUpSfmVKhl5yfW5BfnKpX
- mqmXlp8vxOmWn++SWJLoXaLEoMUAAALEmjo+AAAA
"""
)
@@ -73,6 +74,7 @@
private val MeasurableAndParentDataModifierStub = compiledStub(
filename = "Measurable.kt",
filepath = "androidx/compose/ui/layout",
+ checksum = 0xd1bf915a,
"""
package androidx.compose.ui.layout
@@ -88,6 +90,23 @@
}
""",
"""
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcIlnpiXUpSfmVKhl5yfW5BfnKpX
+ mqmXlp8vxOmWn++SWJLoXaLEoMUAAALEmjo+AAAA
+ """,
+ """
+ androidx/compose/ui/layout/Measurable.class:
+ H4sIAAAAAAAAAI1PwU7bQBB9YzuO65Li0AAJvVK1veAEcaInpAopUmirIKFK
+ OW2SJdrE2UXedURv+ZYe+hE9oChHPgoxRkhB7aV7eDPz5s3Om/uHP3cATtAi
+ vBd6nBs1vk1HZn5jrEwLlWbipylceiGFLXIxzGQVREimYiG4pyfpt+FUjlwV
+ PqE2ke67yKV2X4QThMbHT72/hZ8Jhz2TT9KpdMNcKG1TobVxwinD+dciy8ot
+ LKv3ZsZlSvNuJ8b8IXPefOGzXSqhQqAZU7eqrNqcjTuEzmq5FXtNL/aS1TL2
+ Ij+6bq6Wx16b+o3EOwia1KYf69/B+lcYHgSRnwTl4DHhQ++/zmcTIMQ3L86s
+ bbpHM0d41y+0U3PZ1QtlFbNnmwN59NIU+Uieq0wSWs/Sq3+EIdtCgPIRW6wg
+ 5LV7XJWxytHD/hPuosnxlNmIVa8G8LuIu3jNiK0Sal28wfYAZJGgPkDFYsfi
+ rUXDlnn4CLI2KhoDAgAA
+ """,
+ """
androidx/compose/ui/layout/ParentDataModifier$DefaultImpls.class:
H4sIAAAAAAAAAKVSW08TQRT+pqW01FZKtSii9UKVXoSVxCf7ZECTTdpKxPTF
p+nuUKbdnSGzsw3+Kx+JD8Znf5TxbGkQK0GJm+y5f9/MnHO+//jyFcBLOAyv
@@ -104,18 +123,6 @@
zf2PSLt44KJKEg9dPMJjF09+As+nXNieBAAA
""",
"""
- androidx/compose/ui/layout/Measurable.class:
- H4sIAAAAAAAAAI1PwU7bQBB9YzuO65Li0AAJvVK1veAEcaInpAopUmirIKFK
- OW2SJdrE2UXedURv+ZYe+hE9oChHPgoxRkhB7aV7eDPz5s3Om/uHP3cATtAi
- vBd6nBs1vk1HZn5jrEwLlWbipylceiGFLXIxzGQVREimYiG4pyfpt+FUjlwV
- PqE2ke67yKV2X4QThMbHT72/hZ8Jhz2TT9KpdMNcKG1TobVxwinD+dciy8ot
- LKv3ZsZlSvNuJ8b8IXPefOGzXSqhQqAZU7eqrNqcjTuEzmq5FXtNL/aS1TL2
- Ij+6bq6Wx16b+o3EOwia1KYf69/B+lcYHgSRnwTl4DHhQ++/zmcTIMQ3L86s
- bbpHM0d41y+0U3PZ1QtlFbNnmwN59NIU+Uieq0wSWs/Sq3+EIdtCgPIRW6wg
- 5LV7XJWxytHD/hPuosnxlNmIVa8G8LuIu3jNiK0Sal28wfYAZJGgPkDFYsfi
- rUXDlnn4CLI2KhoDAgAA
- """,
- """
androidx/compose/ui/layout/ParentDataModifier.class:
H4sIAAAAAAAAAJVRTW/TQBB963w4mARSKJC0fLWNqoIEDhEnqh4QAdUogQok
Ljlt4k21ib0beddRc8vv4oBy5kchxgHUkgYQh52d9/xmdjzv67fPXwA8xx7D
@@ -129,11 +136,6 @@
9kXaOPK0lGJma57BRYmY+4SKxF6h+wGdikPAyyRLKoeHFD1C2yS+izp2CDu4
h126j4i/igLKPeQCVAJco4jrWagG2MCNHpjBTWz2UDS4ZXDbwDW4Y1AzqH8H
FbjiFqEDAAA=
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3ApcIlnpiXUpSfmVKhl5yfW5BfnKpX
- mqmXlp8vxOmWn++SWJLoXaLEoMUAAALEmjo+AAAA
"""
)
diff --git a/compose/ui/ui-test-junit4/lint-baseline.xml b/compose/ui/ui-test-junit4/lint-baseline.xml
index 24081e2..76fa171 100644
--- a/compose/ui/ui-test-junit4/lint-baseline.xml
+++ b/compose/ui/ui-test-junit4/lint-baseline.xml
@@ -4,6 +4,72 @@
<issue
id="VisibleForTests"
message="This method should only be accessed from tests or within private scope"
+ errorLine1=" hadPendingMeasureLayout = composeRoots.any { it.hasPendingMeasureOrLayout }"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/android/ComposeIdlingResource.android.kt"
+ line="69"
+ column="61"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" return view.rootView.parent != null && !view.isAttachedToWindow"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/android/ComposeIdlingResource.android.kt"
+ line="113"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" return view.rootView.parent != null && !view.isAttachedToWindow"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/android/ComposeIdlingResource.android.kt"
+ line="113"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" get() = ViewRootForTest.onViewCreatedCallback == ::onViewRootCreated"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/android/ComposeRootRegistry.android.kt"
+ line="54"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" ViewRootForTest.onViewCreatedCallback = ::onViewRootCreated"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/android/ComposeRootRegistry.android.kt"
+ line="60"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" root.view.addOnAttachStateChangeListener(StateChangeHandler(root))"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/android/ComposeRootRegistry.android.kt"
+ line="88"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
errorLine1=" if (composeRoot == this.composeRoot && !registered) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -12,4 +78,26 @@
column="17"/>
</issue>
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" return composeRoots.filter { it.hasPendingMeasureOrLayout }"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/RobolectricIdlingStrategy.android.kt"
+ line="94"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" .onEach { it.view.requestLayout() }"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/junit4/RobolectricIdlingStrategy.android.kt"
+ line="95"
+ column="26"/>
+ </issue>
+
</issues>
diff --git a/compose/ui/ui-test/api/current.txt b/compose/ui/ui-test/api/current.txt
index 591ae00..a6d29d0 100644
--- a/compose/ui/ui-test/api/current.txt
+++ b/compose/ui/ui-test/api/current.txt
@@ -169,9 +169,6 @@
property public abstract boolean isIdleNow;
}
- public final class InputDispatcherKt {
- }
-
public final class KeyInputHelpersKt {
method public static boolean performKeyPress(androidx.compose.ui.test.SemanticsNodeInteraction, android.view.KeyEvent keyEvent);
}
diff --git a/compose/ui/ui-test/api/public_plus_experimental_current.txt b/compose/ui/ui-test/api/public_plus_experimental_current.txt
index c1466c8..af6af83 100644
--- a/compose/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-test/api/public_plus_experimental_current.txt
@@ -181,9 +181,6 @@
property public abstract boolean isIdleNow;
}
- public final class InputDispatcherKt {
- }
-
@kotlin.RequiresOptIn(message="This is internal API for Compose modules that may change frequently and without warning.") public @interface InternalTestApi {
}
diff --git a/compose/ui/ui-test/api/restricted_current.txt b/compose/ui/ui-test/api/restricted_current.txt
index 591ae00..a6d29d0 100644
--- a/compose/ui/ui-test/api/restricted_current.txt
+++ b/compose/ui/ui-test/api/restricted_current.txt
@@ -169,9 +169,6 @@
property public abstract boolean isIdleNow;
}
- public final class InputDispatcherKt {
- }
-
public final class KeyInputHelpersKt {
method public static boolean performKeyPress(androidx.compose.ui.test.SemanticsNodeInteraction, android.view.KeyEvent keyEvent);
}
diff --git a/compose/ui/ui-test/lint-baseline.xml b/compose/ui/ui-test/lint-baseline.xml
new file mode 100644
index 0000000..249b7e8
--- /dev/null
+++ b/compose/ui/ui-test/lint-baseline.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" if (!ViewMatchers.isDisplayed().matches(it.view)) {"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/AndroidAssertions.android.kt"
+ line="41"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" val composeView = (root as ViewRootForTest).view"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/AndroidAssertions.android.kt"
+ line="56"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" val composeView = (root as ViewRootForTest).view"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/AndroidAssertions.android.kt"
+ line="65"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" val view = (node.root as ViewRootForTest).view"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/AndroidImageHelpers.android.kt"
+ line="56"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" val view = root.view"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt"
+ line="40"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" root.view.getLocationOnScreen(array)"
+ errorLine2=" ~~~~">
+ <location
+ file="src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt"
+ line="120"
+ column="22"/>
+ </issue>
+
+</issues>
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/BatchingTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/BatchingTest.kt
index 4f1b9de..0f3d066 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/BatchingTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/BatchingTest.kt
@@ -16,15 +16,15 @@
package androidx.compose.ui.test.inputdispatcher
-import androidx.compose.ui.geometry.Offset
import androidx.compose.testutils.expectError
+import androidx.compose.ui.geometry.Offset
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class BatchingTest : InputDispatcherTest() {
companion object {
- private const val cannotEnqueueError = "Can't enqueue event \\(.*\\), " +
+ private const val cannotEnqueueError = "Can't enqueue touch event \\(.*\\), " +
"events have already been \\(or are being\\) dispatched or disposed"
private const val cannotSendError = "Events have already " +
"been \\(or are being\\) dispatched or disposed"
@@ -37,9 +37,9 @@
*/
@Test
fun enqueueSendDispose() {
- subject.enqueueDown(0, Offset.Zero)
- subject.enqueueMove()
- subject.enqueueMove()
+ subject.enqueueTouchDown(0, Offset.Zero)
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
assertThat(recorder.events).isEmpty()
subject.sendAllSynchronous()
@@ -54,16 +54,16 @@
*/
@Test
fun enqueueSendEnqueue() {
- subject.enqueueDown(0, Offset.Zero)
- subject.enqueueMove()
- subject.enqueueMove()
+ subject.enqueueTouchDown(0, Offset.Zero)
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
assertThat(recorder.events).isEmpty()
subject.sendAllSynchronous()
assertThat(recorder.events).hasSize(3)
expectError<IllegalStateException>(expectedMessage = cannotEnqueueError) {
- subject.enqueueMove()
+ subject.enqueueTouchMove()
}
assertThat(recorder.events).hasSize(3)
@@ -79,9 +79,9 @@
*/
@Test
fun enqueueSendSend() {
- subject.enqueueDown(0, Offset.Zero)
- subject.enqueueMove()
- subject.enqueueMove()
+ subject.enqueueTouchDown(0, Offset.Zero)
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
assertThat(recorder.events).isEmpty()
subject.sendAllSynchronous()
@@ -98,16 +98,16 @@
*/
@Test
fun enqueueDisposeEnqueue() {
- subject.enqueueDown(0, Offset.Zero)
- subject.enqueueMove()
- subject.enqueueMove()
+ subject.enqueueTouchDown(0, Offset.Zero)
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
assertThat(recorder.events).isEmpty()
subject.dispose()
assertThat(recorder.events).isEmpty()
expectError<IllegalStateException>(expectedMessage = cannotEnqueueError) {
- subject.enqueueMove()
+ subject.enqueueTouchMove()
}
assertThat(recorder.events).isEmpty()
@@ -123,9 +123,9 @@
*/
@Test
fun enqueueDisposeSend() {
- subject.enqueueDown(0, Offset.Zero)
- subject.enqueueMove()
- subject.enqueueMove()
+ subject.enqueueTouchDown(0, Offset.Zero)
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
assertThat(recorder.events).isEmpty()
subject.dispose()
@@ -143,9 +143,9 @@
*/
@Test
fun enqueueDisposeDispose() {
- subject.enqueueDown(0, Offset.Zero)
- subject.enqueueMove()
- subject.enqueueMove()
+ subject.enqueueTouchDown(0, Offset.Zero)
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
assertThat(recorder.events).isEmpty()
subject.dispose()
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/InputDispatcherTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/InputDispatcherTest.kt
index 9258b41..f819020 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/InputDispatcherTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/InputDispatcherTest.kt
@@ -60,34 +60,34 @@
}
}
-internal fun AndroidInputDispatcher.generateDownAndCheck(pointerId: Int, position: Offset) {
- enqueueDown(pointerId, position)
- assertThat(getCurrentPosition(pointerId)).isEqualTo(position)
+internal fun AndroidInputDispatcher.generateTouchDownAndCheck(pointerId: Int, position: Offset) {
+ enqueueTouchDown(pointerId, position)
+ assertThat(getCurrentTouchPosition(pointerId)).isEqualTo(position)
}
-internal fun AndroidInputDispatcher.movePointerAndCheck(pointerId: Int, position: Offset) {
- movePointer(pointerId, position)
- assertThat(getCurrentPosition(pointerId)).isEqualTo(position)
+internal fun AndroidInputDispatcher.updateTouchPointerAndCheck(pointerId: Int, position: Offset) {
+ updateTouchPointer(pointerId, position)
+ assertThat(getCurrentTouchPosition(pointerId)).isEqualTo(position)
}
-internal fun AndroidInputDispatcher.generateUpAndCheck(pointerId: Int, delay: Long? = null) {
+internal fun AndroidInputDispatcher.generateTouchUpAndCheck(pointerId: Int, delay: Long? = null) {
if (delay != null) {
- enqueueUp(pointerId, delay)
+ enqueueTouchUp(pointerId, delay)
} else {
- enqueueUp(pointerId)
+ enqueueTouchUp(pointerId)
}
- assertThat(getCurrentPosition(pointerId)).isNull()
+ assertThat(getCurrentTouchPosition(pointerId)).isNull()
}
-internal fun AndroidInputDispatcher.generateCancelAndCheck(delay: Long? = null) {
+internal fun AndroidInputDispatcher.generateTouchCancelAndCheck(delay: Long? = null) {
if (delay != null) {
- enqueueCancel(delay)
+ enqueueTouchCancel(delay)
} else {
- enqueueCancel()
+ enqueueTouchCancel()
}
- verifyNoGestureInProgress()
+ verifyNoTouchGestureInProgress()
}
-internal fun InputDispatcher.verifyNoGestureInProgress() {
- assertThat((this as AndroidInputDispatcher).isGestureInProgress).isFalse()
+internal fun InputDispatcher.verifyNoTouchGestureInProgress() {
+ assertThat((this as AndroidInputDispatcher).isTouchInProgress).isFalse()
}
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/IsGestureInProgressTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/IsGestureInProgressTest.kt
index 1d3589e..a094c61 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/IsGestureInProgressTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/IsGestureInProgressTest.kt
@@ -27,19 +27,19 @@
@Test
fun downUp() {
- assertThat(subject.isGestureInProgress).isFalse()
- subject.enqueueDown(1, anyPosition)
- assertThat(subject.isGestureInProgress).isTrue()
- subject.enqueueUp(1)
- assertThat(subject.isGestureInProgress).isFalse()
+ assertThat(subject.isTouchInProgress).isFalse()
+ subject.enqueueTouchDown(1, anyPosition)
+ assertThat(subject.isTouchInProgress).isTrue()
+ subject.enqueueTouchUp(1)
+ assertThat(subject.isTouchInProgress).isFalse()
}
@Test
fun downCancel() {
- assertThat(subject.isGestureInProgress).isFalse()
- subject.enqueueDown(1, anyPosition)
- assertThat(subject.isGestureInProgress).isTrue()
- subject.enqueueCancel()
- assertThat(subject.isGestureInProgress).isFalse()
+ assertThat(subject.isTouchInProgress).isFalse()
+ subject.enqueueTouchDown(1, anyPosition)
+ assertThat(subject.isTouchInProgress).isTrue()
+ subject.enqueueTouchCancel()
+ assertThat(subject.isTouchInProgress).isFalse()
}
}
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendCancelTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendCancelTest.kt
index 5a18cd5..52bc9c2 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendCancelTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendCancelTest.kt
@@ -33,7 +33,7 @@
import org.junit.Test
/**
- * Tests if [AndroidInputDispatcher.enqueueCancel] works
+ * Tests if [AndroidInputDispatcher.enqueueTouchCancel] works
*/
@SmallTest
class SendCancelTest : InputDispatcherTest() {
@@ -48,16 +48,16 @@
}
private fun AndroidInputDispatcher.generateCancelAndCheckPointers(delay: Long? = null) {
- generateCancelAndCheck(delay)
- assertThat(getCurrentPosition(pointer1)).isNull()
- assertThat(getCurrentPosition(pointer2)).isNull()
+ generateTouchCancelAndCheck(delay)
+ assertThat(getCurrentTouchPosition(pointer1)).isNull()
+ assertThat(getCurrentTouchPosition(pointer2)).isNull()
}
@Test
fun onePointer() {
- subject.generateDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
subject.generateCancelAndCheckPointers()
- subject.verifyNoGestureInProgress()
+ subject.verifyNoTouchGestureInProgress()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -75,9 +75,9 @@
@Test
fun onePointerWithDelay() {
- subject.generateDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
subject.generateCancelAndCheckPointers(2 * eventPeriodMillis)
- subject.verifyNoGestureInProgress()
+ subject.verifyNoTouchGestureInProgress()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -95,10 +95,10 @@
@Test
fun multiplePointers() {
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
subject.generateCancelAndCheckPointers()
- subject.verifyNoGestureInProgress()
+ subject.verifyNoTouchGestureInProgress()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -122,25 +122,25 @@
@Test
fun cancelWithoutDown() {
expectError<IllegalStateException> {
- subject.enqueueCancel()
+ subject.enqueueTouchCancel()
}
}
@Test
fun cancelAfterUp() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueUp(pointer1)
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchUp(pointer1)
expectError<IllegalStateException> {
- subject.enqueueCancel()
+ subject.enqueueTouchCancel()
}
}
@Test
fun cancelAfterCancel() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueCancel()
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchCancel()
expectError<IllegalStateException> {
- subject.enqueueCancel()
+ subject.enqueueTouchCancel()
}
}
}
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendDownTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendDownTest.kt
index 2533d41..27d8c26 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendDownTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendDownTest.kt
@@ -34,7 +34,7 @@
import org.junit.Test
/**
- * Tests if [AndroidInputDispatcher.enqueueDown] works
+ * Tests if [AndroidInputDispatcher.enqueueTouchDown] works
*/
@SmallTest
class SendDownTest : InputDispatcherTest() {
@@ -57,7 +57,7 @@
@Test
fun onePointer() {
- subject.generateDownAndCheck(pointer1, position1)
+ subject.generateTouchDownAndCheck(pointer1, position1)
subject.sendAllSynchronous()
val t = 0L
@@ -70,8 +70,8 @@
@Test
fun twoPointers_ascending() {
// 2 fingers, sent in ascending order of pointerId (matters for actionIndex)
- subject.generateDownAndCheck(pointer1, position1)
- subject.generateDownAndCheck(pointer2, position2)
+ subject.generateTouchDownAndCheck(pointer1, position1)
+ subject.generateTouchDownAndCheck(pointer2, position2)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -91,8 +91,8 @@
@Test
fun twoPointers_descending() {
// 2 fingers, sent in descending order of pointerId (matters for actionIndex)
- subject.generateDownAndCheck(pointer2, position2)
- subject.generateDownAndCheck(pointer1, position1)
+ subject.generateTouchDownAndCheck(pointer2, position2)
+ subject.generateTouchDownAndCheck(pointer1, position1)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -113,10 +113,10 @@
fun fourPointers() {
// 4 fingers, sent in non-trivial order of pointerId (matters for actionIndex)
- subject.generateDownAndCheck(pointer3, position3)
- subject.generateDownAndCheck(pointer1, position1)
- subject.generateDownAndCheck(pointer4, position4)
- subject.generateDownAndCheck(pointer2, position2)
+ subject.generateTouchDownAndCheck(pointer3, position3)
+ subject.generateTouchDownAndCheck(pointer1, position1)
+ subject.generateTouchDownAndCheck(pointer4, position4)
+ subject.generateTouchDownAndCheck(pointer2, position2)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -147,16 +147,16 @@
@Test
fun staggeredDown() {
// 4 fingers, going down at different times
- // Each [sendMove] increases the time by 10 milliseconds
+ // Each [enqueueTouchMove] increases the time by 10 milliseconds
- subject.generateDownAndCheck(pointer3, position3)
- subject.enqueueMove()
- subject.generateDownAndCheck(pointer1, position1)
- subject.generateDownAndCheck(pointer2, position2)
- subject.enqueueMove()
- subject.enqueueMove()
- subject.enqueueMove()
- subject.generateDownAndCheck(pointer4, position4)
+ subject.generateTouchDownAndCheck(pointer3, position3)
+ subject.enqueueTouchMove()
+ subject.generateTouchDownAndCheck(pointer1, position1)
+ subject.generateTouchDownAndCheck(pointer2, position2)
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
+ subject.enqueueTouchMove()
+ subject.generateTouchDownAndCheck(pointer4, position4)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -199,14 +199,14 @@
@Test
fun nonOverlappingPointers() {
// 3 fingers, where the 1st finger goes up before the 3rd finger goes down (no overlap)
- // Each [sendMove] increases the time by 10 milliseconds
+ // Each [enqueueTouchMove] increases the time by 10 milliseconds
- subject.generateDownAndCheck(pointer1, position1)
- subject.generateDownAndCheck(pointer2, position2)
- subject.enqueueMove()
- subject.generateUpAndCheck(pointer1)
- subject.enqueueMove()
- subject.generateDownAndCheck(pointer3, position3)
+ subject.generateTouchDownAndCheck(pointer1, position1)
+ subject.generateTouchDownAndCheck(pointer2, position2)
+ subject.enqueueTouchMove()
+ subject.generateTouchUpAndCheck(pointer1)
+ subject.enqueueTouchMove()
+ subject.generateTouchDownAndCheck(pointer3, position3)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -244,14 +244,14 @@
fun pointerIdReuse() {
// 3 fingers, where the 1st finger goes up before the 3rd finger goes down, and the 3rd
// fingers reuses the pointerId of finger 1
- // Each [sendMove] increases the time by 10 milliseconds
+ // Each [enqueueTouchMove] increases the time by 10 milliseconds
- subject.generateDownAndCheck(pointer1, position1)
- subject.generateDownAndCheck(pointer2, position2)
- subject.enqueueMove()
- subject.generateUpAndCheck(pointer1)
- subject.enqueueMove()
- subject.generateDownAndCheck(pointer1, position1_2)
+ subject.generateTouchDownAndCheck(pointer1, position1)
+ subject.generateTouchDownAndCheck(pointer2, position2)
+ subject.enqueueTouchMove()
+ subject.generateTouchUpAndCheck(pointer1)
+ subject.enqueueTouchMove()
+ subject.generateTouchDownAndCheck(pointer1, position1_2)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -287,9 +287,9 @@
@Test
fun downAfterDown() {
- subject.enqueueDown(pointer1, position1)
+ subject.enqueueTouchDown(pointer1, position1)
expectError<IllegalArgumentException> {
- subject.enqueueDown(pointer1, position2)
+ subject.enqueueTouchDown(pointer1, position2)
}
}
}
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendMoveTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendMoveTest.kt
index ec119ca..7aaf854 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendMoveTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendMoveTest.kt
@@ -35,7 +35,8 @@
import org.junit.Test
/**
- * Tests if [AndroidInputDispatcher.movePointer] and [AndroidInputDispatcher.enqueueMove] work
+ * Tests if [AndroidInputDispatcher.updateTouchPointer] and
+ * [AndroidInputDispatcher.enqueueTouchMove] work
*/
@SmallTest
class SendMoveTest : InputDispatcherTest() {
@@ -57,17 +58,17 @@
}
private fun AndroidInputDispatcher.generateCancelAndCheckPointers() {
- generateCancelAndCheck()
- assertThat(getCurrentPosition(pointer1)).isNull()
- assertThat(getCurrentPosition(pointer2)).isNull()
- assertThat(getCurrentPosition(pointer3)).isNull()
+ generateTouchCancelAndCheck()
+ assertThat(getCurrentTouchPosition(pointer1)).isNull()
+ assertThat(getCurrentTouchPosition(pointer2)).isNull()
+ assertThat(getCurrentTouchPosition(pointer3)).isNull()
}
@Test
fun onePointer() {
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.enqueueMove()
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.enqueueTouchMove()
subject.sendAllSynchronous()
var t = 0L
@@ -83,9 +84,9 @@
@Test
fun onePointerWithDelay() {
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.enqueueMove(2 * eventPeriodMillis)
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.enqueueTouchMove(2 * eventPeriodMillis)
subject.sendAllSynchronous()
var t = 0L
@@ -102,12 +103,12 @@
@Test
fun twoPointers_downDownMoveMove() {
// 2 fingers, both go down before they move
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.enqueueMove()
- subject.movePointerAndCheck(pointer2, position2_2)
- subject.enqueueMove()
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.enqueueTouchMove()
+ subject.updateTouchPointerAndCheck(pointer2, position2_2)
+ subject.enqueueTouchMove()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -137,12 +138,12 @@
@Test
fun twoPointers_downMoveDownMove() {
// 2 fingers, 1st finger moves before 2nd finger goes down and moves
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.enqueueMove()
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.movePointerAndCheck(pointer2, position2_2)
- subject.enqueueMove()
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.enqueueTouchMove()
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.updateTouchPointerAndCheck(pointer2, position2_2)
+ subject.enqueueTouchMove()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -170,12 +171,12 @@
@Test
fun movePointer_oneMovePerPointer() {
- // 2 fingers, use [movePointer] and [sendMove]
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.movePointerAndCheck(pointer2, position2_2)
- subject.enqueueMove()
+ // 2 fingers, use [updateTouchPointer] and [enqueueTouchMove]
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.updateTouchPointerAndCheck(pointer2, position2_2)
+ subject.enqueueTouchMove()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -199,12 +200,12 @@
@Test
fun movePointer_multipleMovesPerPointer() {
- // 2 fingers, do several [movePointer]s and then [sendMove]
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.movePointerAndCheck(pointer1, position1_3)
- subject.enqueueMove()
+ // 2 fingers, do several [updateTouchPointer]s and then [enqueueTouchMove]
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.updateTouchPointerAndCheck(pointer1, position1_3)
+ subject.enqueueTouchMove()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -228,10 +229,10 @@
@Test
fun sendMoveWithoutMovePointer() {
- // 2 fingers, do [sendMove] without [movePointer]
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.enqueueMove()
+ // 2 fingers, do [enqueueTouchMove] without [updateTouchPointer]
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.enqueueTouchMove()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -255,12 +256,12 @@
@Test
fun downFlushesPointerMovement() {
- // Movement from [movePointer] that hasn't been sent will be sent when sending DOWN
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.movePointerAndCheck(pointer1, position1_3)
- subject.generateDownAndCheck(pointer3, position3_1)
+ // Movement from [updateTouchPointer] that hasn't been sent will be sent when sending DOWN
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.updateTouchPointerAndCheck(pointer1, position1_3)
+ subject.generateTouchDownAndCheck(pointer3, position3_1)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -289,12 +290,12 @@
@Test
fun upFlushesPointerMovement() {
- // Movement from [movePointer] that hasn't been sent will be sent when sending UP
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.movePointerAndCheck(pointer1, position1_3)
- subject.generateUpAndCheck(pointer1)
+ // Movement from [updateTouchPointer] that hasn't been sent will be sent when sending UP
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.updateTouchPointerAndCheck(pointer1, position1_3)
+ subject.generateTouchUpAndCheck(pointer1)
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -324,10 +325,10 @@
fun cancelDoesNotFlushPointerMovement() {
// 2 fingers, both with pending movement.
// CANCEL doesn't force a MOVE, but _does_ reflect the latest positions
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.movePointerAndCheck(pointer1, position1_2)
- subject.movePointerAndCheck(pointer2, position2_2)
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.updateTouchPointerAndCheck(pointer1, position1_2)
+ subject.updateTouchPointerAndCheck(pointer2, position2_2)
subject.generateCancelAndCheckPointers()
subject.sendAllSynchronous()
@@ -352,58 +353,58 @@
@Test
fun movePointerWithoutDown() {
expectError<IllegalStateException> {
- subject.movePointer(pointer1, position1_1)
+ subject.updateTouchPointer(pointer1, position1_1)
}
}
@Test
fun movePointerWrongPointerId() {
- subject.enqueueDown(pointer1, position1_1)
+ subject.enqueueTouchDown(pointer1, position1_1)
expectError<IllegalArgumentException> {
- subject.movePointer(pointer2, position1_2)
+ subject.updateTouchPointer(pointer2, position1_2)
}
}
@Test
fun movePointerAfterUp() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueUp(pointer1)
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchUp(pointer1)
expectError<IllegalStateException> {
- subject.movePointer(pointer1, position1_2)
+ subject.updateTouchPointer(pointer1, position1_2)
}
}
@Test
fun movePointerAfterCancel() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueCancel()
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchCancel()
expectError<IllegalStateException> {
- subject.movePointer(pointer1, position1_2)
+ subject.updateTouchPointer(pointer1, position1_2)
}
}
@Test
fun sendMoveWithoutDown() {
expectError<IllegalStateException> {
- subject.enqueueMove()
+ subject.enqueueTouchMove()
}
}
@Test
fun sendMoveAfterUp() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueUp(pointer1)
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchUp(pointer1)
expectError<IllegalStateException> {
- subject.enqueueMove()
+ subject.enqueueTouchMove()
}
}
@Test
fun sendMoveAfterCancel() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueCancel()
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchCancel()
expectError<IllegalStateException> {
- subject.enqueueMove()
+ subject.enqueueTouchMove()
}
}
}
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendUpTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendUpTest.kt
index 4d5fb96..dbea7eb 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendUpTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/inputdispatcher/SendUpTest.kt
@@ -34,7 +34,7 @@
import org.junit.Test
/**
- * Tests if [AndroidInputDispatcher.enqueueUp] works
+ * Tests if [AndroidInputDispatcher.enqueueTouchUp] works
*/
@SmallTest
class SendUpTest : InputDispatcherTest() {
@@ -50,9 +50,9 @@
@Test
fun onePointer() {
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateUpAndCheck(pointer1)
- subject.verifyNoGestureInProgress()
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchUpAndCheck(pointer1)
+ subject.verifyNoTouchGestureInProgress()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -70,9 +70,9 @@
@Test
fun onePointerWithDelay() {
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateUpAndCheck(pointer1, 2 * eventPeriodMillis)
- subject.verifyNoGestureInProgress()
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchUpAndCheck(pointer1, 2 * eventPeriodMillis)
+ subject.verifyNoTouchGestureInProgress()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -91,11 +91,11 @@
@Test
fun multiplePointers_ascending() {
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.generateUpAndCheck(pointer1)
- subject.generateUpAndCheck(pointer2)
- subject.verifyNoGestureInProgress()
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.generateTouchUpAndCheck(pointer1)
+ subject.generateTouchUpAndCheck(pointer2)
+ subject.verifyNoTouchGestureInProgress()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -121,11 +121,11 @@
@Test
fun multiplePointers_descending() {
- subject.generateDownAndCheck(pointer1, position1_1)
- subject.generateDownAndCheck(pointer2, position2_1)
- subject.generateUpAndCheck(pointer2)
- subject.generateUpAndCheck(pointer1)
- subject.verifyNoGestureInProgress()
+ subject.generateTouchDownAndCheck(pointer1, position1_1)
+ subject.generateTouchDownAndCheck(pointer2, position2_1)
+ subject.generateTouchUpAndCheck(pointer2)
+ subject.generateTouchUpAndCheck(pointer1)
+ subject.verifyNoTouchGestureInProgress()
subject.sendAllSynchronous()
recorder.assertHasValidEventTimes()
@@ -152,33 +152,33 @@
@Test
fun upWithoutDown() {
expectError<IllegalStateException> {
- subject.enqueueUp(pointer1)
+ subject.enqueueTouchUp(pointer1)
}
}
@Test
fun upWrongPointerId() {
- subject.enqueueDown(pointer1, position1_1)
+ subject.enqueueTouchDown(pointer1, position1_1)
expectError<IllegalArgumentException> {
- subject.enqueueUp(pointer2)
+ subject.enqueueTouchUp(pointer2)
}
}
@Test
fun upAfterUp() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueUp(pointer1)
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchUp(pointer1)
expectError<IllegalStateException> {
- subject.enqueueUp(pointer1)
+ subject.enqueueTouchUp(pointer1)
}
}
@Test
fun upAfterCancel() {
- subject.enqueueDown(pointer1, position1_1)
- subject.enqueueCancel()
+ subject.enqueueTouchDown(pointer1, position1_1)
+ subject.enqueueTouchCancel()
expectError<IllegalStateException> {
- subject.enqueueUp(pointer1)
+ subject.enqueueTouchUp(pointer1)
}
}
}
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendCancelTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendCancelTest.kt
index 6958a74..bc4f3f0 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendCancelTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendCancelTest.kt
@@ -20,7 +20,7 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.test.cancel
import androidx.compose.ui.test.down
-import androidx.compose.ui.test.inputdispatcher.verifyNoGestureInProgress
+import androidx.compose.ui.test.inputdispatcher.verifyNoTouchGestureInProgress
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.partialgesturescope.Common.partialGesture
import androidx.compose.ui.test.up
@@ -71,7 +71,7 @@
}
// And no gesture is in progress
- rule.partialGesture { inputDispatcher.verifyNoGestureInProgress() }
+ rule.partialGesture { inputDispatcher.verifyNoTouchGestureInProgress() }
}
@Test
@@ -90,7 +90,7 @@
}
// And no gesture is in progress
- rule.partialGesture { inputDispatcher.verifyNoGestureInProgress() }
+ rule.partialGesture { inputDispatcher.verifyNoTouchGestureInProgress() }
}
@Test
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendUpTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendUpTest.kt
index 258a3ff..50355f1 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendUpTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/partialgesturescope/SendUpTest.kt
@@ -21,7 +21,7 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.test.cancel
import androidx.compose.ui.test.down
-import androidx.compose.ui.test.inputdispatcher.verifyNoGestureInProgress
+import androidx.compose.ui.test.inputdispatcher.verifyNoTouchGestureInProgress
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.partialgesturescope.Common.partialGesture
import androidx.compose.ui.test.up
@@ -80,7 +80,7 @@
}
// And no gesture is in progress
- rule.partialGesture { inputDispatcher.verifyNoGestureInProgress() }
+ rule.partialGesture { inputDispatcher.verifyNoTouchGestureInProgress() }
}
@Test
@@ -111,7 +111,7 @@
}
// And no gesture is in progress
- rule.partialGesture { inputDispatcher.verifyNoGestureInProgress() }
+ rule.partialGesture { inputDispatcher.verifyNoTouchGestureInProgress() }
}
@Test
diff --git a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt
index 1c2c113..fd2775f 100644
--- a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt
+++ b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.test
-import android.os.SystemClock
import android.view.InputDevice
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_CANCEL
@@ -29,7 +28,6 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.node.RootForTest
import androidx.compose.ui.platform.ViewRootForTest
-import kotlinx.coroutines.ExperimentalCoroutinesApi
internal actual fun createInputDispatcher(
testContext: TestContext,
@@ -52,30 +50,28 @@
private val batchLock = Any()
private var batchedEvents = mutableListOf<MotionEvent>()
private var acceptEvents = true
- private var lastEventTime = currentTime
-
- override val now: Long get() = SystemClock.uptimeMillis()
+ private var currentClockTime = currentTime
override fun PartialGesture.enqueueDown(pointerId: Int) {
- batchMotionEvent(
+ enqueueTouchEvent(
if (lastPositions.size == 1) ACTION_DOWN else ACTION_POINTER_DOWN,
lastPositions.keys.sorted().indexOf(pointerId)
)
}
override fun PartialGesture.enqueueMove() {
- batchMotionEvent(ACTION_MOVE, 0)
+ enqueueTouchEvent(ACTION_MOVE, 0)
}
override fun PartialGesture.enqueueUp(pointerId: Int) {
- batchMotionEvent(
+ enqueueTouchEvent(
if (lastPositions.size == 1) ACTION_UP else ACTION_POINTER_UP,
lastPositions.keys.sorted().indexOf(pointerId)
)
}
override fun PartialGesture.enqueueCancel() {
- batchMotionEvent(ACTION_CANCEL, 0)
+ enqueueTouchEvent(ACTION_CANCEL, 0)
}
/**
@@ -85,22 +81,22 @@
* @see MotionEvent.getAction
* @see MotionEvent.getActionIndex
*/
- private fun PartialGesture.batchMotionEvent(action: Int, actionIndex: Int) {
+ private fun PartialGesture.enqueueTouchEvent(action: Int, actionIndex: Int) {
val entries = lastPositions.entries.sortedBy { it.key }
- batchMotionEvent(
- downTime,
- currentTime,
- action,
- actionIndex,
- List(entries.size) { entries[it].value },
- List(entries.size) { entries[it].key }
+ enqueueTouchEvent(
+ downTime = downTime,
+ eventTime = currentTime,
+ action = action,
+ actionIndex = actionIndex,
+ coordinates = List(entries.size) { entries[it].value },
+ pointerIds = List(entries.size) { entries[it].key }
)
}
/**
* Generates an event with the given parameters.
*/
- private fun batchMotionEvent(
+ private fun enqueueTouchEvent(
downTime: Long,
eventTime: Long,
action: Int,
@@ -110,7 +106,7 @@
) {
synchronized(batchLock) {
check(acceptEvents) {
- "Can't enqueue event (" +
+ "Can't enqueue touch event (" +
"downTime=$downTime, " +
"eventTime=$eventTime, " +
"action=$action, " +
@@ -119,9 +115,6 @@
"coordinates=$coordinates" +
"), events have already been (or are being) dispatched or disposed"
}
- if (lastEventTime == TimeNotSet) {
- lastEventTime = eventTime
- }
val positionInScreen = if (root != null) {
val array = intArrayOf(0, 0)
root.view.getLocationOnScreen(array)
@@ -168,12 +161,11 @@
testContext.testOwner.runOnUiThread {
checkAndStopAcceptingEvents()
- var currentEventTime = lastEventTime
batchedEvents.forEach { event ->
// Before injecting the next event, pump the clock
// by the difference between this and the last event
- pumpClock(event.eventTime - currentEventTime)
- currentEventTime = event.eventTime
+ advanceClockTime(event.eventTime - currentClockTime)
+ currentClockTime = event.eventTime
sendAndRecycleEvent(event)
}
}
@@ -181,9 +173,9 @@
// dispatcher, so we don't have to reset firstEventTime after use
}
- @OptIn(InternalTestApi::class, ExperimentalCoroutinesApi::class)
- private fun pumpClock(millis: Long) {
- // Don't bother calling the method if there's nothing to advance
+ @OptIn(InternalTestApi::class)
+ private fun advanceClockTime(millis: Long) {
+ // Don't bother advancing the clock if there's nothing to advance
if (millis > 0) {
testContext.testOwner.mainClock.advanceTimeBy(millis, ignoreFrameDuration = true)
}
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
index d408e84..76e4aec 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
@@ -37,7 +37,7 @@
* Performs a click action on the element represented by the given semantics node.
*/
fun SemanticsNodeInteraction.performClick(): SemanticsNodeInteraction {
- // TODO(jellefresen): Replace with semantics action when semantics merging is done
+ // TODO(fresen): Replace with semantics action when semantics merging is done
// The problem we currently have is that the click action might be defined on a different
// semantics node than we're interacting with now, even though it is "semantically" the same.
// E.g., findByText(buttonText) finds the Text's semantics node, but the click action is
@@ -182,21 +182,17 @@
/**
* Executes the (partial) gesture specified in the given [block]. The gesture doesn't need to be
- * complete and can be resumed in a later invocation of [performGesture]. If there was a previous
- * invocation of [performGesture], the first event time of the current invocation is equal to the
- * last event time of the previous gesture plus the elapsed time in between on the [MainTestClock].
+ * complete and can be resumed in a later invocation of [performGesture]. The event time is
+ * initialized to the current time of the [MainTestClock].
*
* Be aware that if you split a gesture over two invocations of [performGesture], everything that
* happens in between will run as if the gesture is still ongoing (imagine a finger still
* touching the screen).
*
* All events that are injected from the [block] are batched together and sent after [block] is
- * complete. This method blocks until all those events have been injected, which normally takes
- * as long as the duration of the gesture. If an error occurs during execution of [block] or
- * injection of the events, all (subsequent) events are dropped and the error is thrown here.
- *
- * This method must not be called from the main thread. The block will be executed on the same
- * thread as the caller.
+ * complete. This method blocks while the events are injected. If an error occurs during
+ * execution of [block] or injection of the events, all (subsequent) events are dropped and the
+ * error is thrown here.
*
* Example usage:
* ```
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/GestureScope.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/GestureScope.kt
index 67ae14f..796de1c 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/GestureScope.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/GestureScope.kt
@@ -713,7 +713,7 @@
*/
fun GestureScope.down(pointerId: Int, position: Offset) {
val globalPosition = localToRoot(position)
- inputDispatcher.enqueueDown(pointerId, globalPosition)
+ inputDispatcher.enqueueTouchDown(pointerId, globalPosition)
}
/**
@@ -772,7 +772,7 @@
*/
fun GestureScope.movePointerTo(pointerId: Int, position: Offset) {
val globalPosition = localToRoot(position)
- inputDispatcher.movePointer(pointerId, globalPosition)
+ inputDispatcher.updateTouchPointer(pointerId, globalPosition)
}
/**
@@ -819,8 +819,8 @@
fun GestureScope.movePointerBy(pointerId: Int, delta: Offset) {
// Ignore currentPosition of null here, let movePointer generate the error
val globalPosition =
- (inputDispatcher.getCurrentPosition(pointerId) ?: Offset.Zero) + delta
- inputDispatcher.movePointer(pointerId, globalPosition)
+ (inputDispatcher.getCurrentTouchPosition(pointerId) ?: Offset.Zero) + delta
+ inputDispatcher.updateTouchPointer(pointerId, globalPosition)
}
/**
@@ -829,7 +829,7 @@
* [movePointerBy].
*/
fun GestureScope.move() {
- inputDispatcher.enqueueMove()
+ inputDispatcher.enqueueTouchMove()
}
/**
@@ -841,7 +841,7 @@
* @param pointerId The id of the pointer to lift up, as supplied in [down]
*/
fun GestureScope.up(pointerId: Int = 0) {
- inputDispatcher.enqueueUp(pointerId)
+ inputDispatcher.enqueueTouchUp(pointerId)
}
/**
@@ -849,7 +849,7 @@
* current position of all active pointers.
*/
fun GestureScope.cancel() {
- inputDispatcher.enqueueCancel()
+ inputDispatcher.enqueueTouchCancel()
}
/**
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/InputDispatcher.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/InputDispatcher.kt
index 0732d6c..3f7855b 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/InputDispatcher.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/InputDispatcher.kt
@@ -27,17 +27,10 @@
): InputDispatcher
/**
- * Indicates that [InputDispatcher.currentTime] is not set
- */
-internal const val TimeNotSet = -1L
-
-/**
* Dispatcher to inject full and partial gestures. An [InputDispatcher] is created at the
* beginning of [performGesture], and disposed at the end of that method. If there is still a
* [gesture going on][isGestureInProgress] when the dispatcher is disposed, the state of the
- * current gesture will be persisted and restored on the next invocation of [performGesture]. The
- * [current eventTime][currentTime] will be restored regardless, but will only be used when the
- * next invocation of [performGesture] has `resumeFinishedGesture = true`.
+ * current gesture will be persisted and restored on the next invocation of [performGesture].
*
* Dispatching input happens in two stages. In the first stage, all events are generated
* (enqueued), using the `enqueue*` methods, and in the second stage all events are injected.
@@ -50,12 +43,12 @@
* * [enqueueSwipes]
*
* Partial gestures:
- * * [enqueueDown]
- * * [enqueueMove]
- * * [enqueueUp]
- * * [enqueueCancel]
- * * [movePointer]
- * * [getCurrentPosition]
+ * * [enqueueTouchDown]
+ * * [enqueueTouchMove]
+ * * [enqueueTouchUp]
+ * * [enqueueTouchCancel]
+ * * [updateTouchPointer]
+ * * [getCurrentTouchPosition]
*
* Chaining methods:
* * [advanceEventTime]
@@ -66,7 +59,7 @@
) {
companion object {
/**
- * The minimum time between two successive injected MotionEvents, 10 milliseconds.
+ * The default time between two successively injected events, 10 milliseconds.
* Ideally, the value should reflect a realistic pointer input sample rate, but that
* depends on too many factors. Instead, the value is chosen comfortably below the
* targeted frame rate (60 fps, equating to a 16ms period).
@@ -76,13 +69,12 @@
}
/**
- * The eventTime of the next event. If [TimeNotSet], no gesture has been started yet, and
- * enqueuing anything other than a down event will fail.
+ * The eventTime of the next event.
*/
- protected var currentTime = TimeNotSet
+ protected var currentTime = testContext.currentTime
/**
- * The state of the current gesture in progress. If `null`, no gesture is in progress. This
+ * The state of the current touch gesture. If `null`, no touch gesture is in progress. This
* state contains the current position of all pointer ids and whether or not pointers have
* moved without having enqueued the corresponding move event.
*/
@@ -92,20 +84,12 @@
* Indicates if a gesture is in progress or not. A gesture is in progress if at least one
* finger is (still) touching the screen.
*/
- val isGestureInProgress: Boolean
+ val isTouchInProgress: Boolean
get() = partialGesture != null
- /**
- * The current wall clock time, in the time scale used by gesture events.
- */
- protected abstract val now: Long
-
init {
val state = testContext.states.remove(root)
if (state != null) {
- val elapsedTime = testContext.currentTime - state.clockTimeOnDispose
- // current gesture time = time where last gesture left off + elapsed time
- currentTime = state.currentTime + elapsedTime
partialGesture = state.partialGesture
}
}
@@ -114,9 +98,7 @@
if (root != null) {
testContext.states[root] =
InputDispatcherState(
- currentTime,
- partialGesture,
- testContext.currentTime
+ partialGesture
)
}
}
@@ -125,40 +107,27 @@
private val TestContext.currentTime get() = testOwner.mainClock.currentTime
/**
- * Returns the time to use for the next downTime. If no event has been enqueued yet, will
- * return the current wall clock time. Otherwise, will return the
- * [current eventTime][currentTime].
+ * Increases the current event time by [durationMillis]. Note that [enqueueTouchMove] and
+ * [enqueueTouchCancel] also increase the current time by 10ms.
*
- * Call [increaseEventTime] each time the gesture progresses forward in time to make sure the
- * current eventTime stays accurate.
+ * @param durationMillis The duration of the delay. Must be positive
*/
- private fun generateDownTime(): Long {
- return if (currentTime == TimeNotSet) {
- now.also { currentTime = it }
- } else {
- currentTime
- }
- }
-
- /**
- * Moves the eventTime for the next event ahead by the given [durationMillis].
- */
- private fun increaseEventTime(durationMillis: Long) {
- check(currentTime != TimeNotSet) {
- "Can't adjust current event time when no gesture is in progress."
+ fun advanceEventTime(durationMillis: Long = eventPeriodMillis) {
+ require(durationMillis >= 0) {
+ "duration of a delay can only be positive, not $durationMillis"
}
currentTime += durationMillis
}
/**
- * During a partial gesture, returns the position of the last touch event of the given
- * [pointerId]. Returns `null` if no partial gesture is in progress for that [pointerId].
+ * During a touch gesture, returns the position of the last touch event of the given
+ * [pointerId]. Returns `null` if no touch gesture is in progress for that [pointerId].
*
* @param pointerId The id of the pointer for which to return the current position
* @return The current position of the pointer with the given [pointerId], or `null` if the
* pointer is not currently in use
*/
- fun getCurrentPosition(pointerId: Int): Offset? {
+ fun getCurrentTouchPosition(pointerId: Int): Offset? {
return partialGesture?.lastPositions?.get(pointerId)
}
@@ -170,9 +139,9 @@
* @param position The coordinate of the click
*/
fun enqueueClick(position: Offset) {
- enqueueDown(0, position)
- enqueueMove()
- enqueueUp(0)
+ enqueueTouchDown(0, position)
+ enqueueTouchMove()
+ enqueueTouchUp(0)
}
/**
@@ -247,7 +216,7 @@
// Send down events
curves.forEachIndexed { i, curve ->
- enqueueDown(i, curve(startTime))
+ enqueueTouchDown(i, curve(startTime))
}
// Send move events between each consecutive pair in [t0, ..keyTimes, tN]
@@ -266,7 +235,7 @@
// And end with up events
repeat(curves.size) {
- enqueueUp(it)
+ enqueueTouchUp(it)
}
}
@@ -296,45 +265,30 @@
val progress = step / steps.toFloat()
val t = androidx.compose.ui.util.lerp(t0, tN, progress)
fs.forEachIndexed { i, f ->
- movePointer(i, f(t))
+ updateTouchPointer(i, f(t))
}
- enqueueMove(t - tPrev)
+ enqueueTouchMove(t - tPrev)
tPrev = t
}
}
/**
- * Adds an extra delay of [durationMillis] between the last and the next event. The delay is
- * added on top of the delay that would already be added between the two events. The normal
- * delay depends on the type of the next event: for [enqueueMove] and [enqueueCancel] move
- * the eventTime by 10ms, and all other methods don't move the eventTime.
- *
- * @param durationMillis The duration of the delay. Must be positive
- */
- fun advanceEventTime(durationMillis: Long) {
- require(durationMillis >= 0) {
- "duration of a delay can only be positive, not $durationMillis"
- }
- increaseEventTime(durationMillis)
- }
-
- /**
- * Generates a down event at [position] for the pointer with the given [pointerId], starting
- * a new partial gesture. A partial gesture can only be started if none was currently ongoing
- * for that pointer. Pointer ids may be reused during the same gesture. The generated event
- * is enqueued in this [InputDispatcher] and will be sent when [sendAllSynchronous] is called
- * at the end of [performGesture].
+ * Generates a down touch event at [position] for the pointer with the given [pointerId],
+ * starting a new partial gesture. A partial gesture can only be started if none was currently
+ * ongoing for that pointer. Pointer ids may be reused during the same gesture. The generated
+ * touch event is enqueued in this [InputDispatcher] and will be sent when [sendAllSynchronous]
+ * is called at the end of [performGesture].
*
* It is possible to mix partial gestures with full gestures (e.g. generate a
* [click][enqueueClick] during a partial gesture), as long as you make sure that the default
* pointer id (id=0) is free to be used by the full gesture.
*
* A full gesture starts with a down event at some position (with this method) that indicates
- * a finger has started touching the screen, followed by zero or more [down][enqueueDown],
- * [move][enqueueMove] and [up][enqueueUp] events that respectively indicate that another
- * finger started touching the screen, a finger moved around or a finger was lifted up from
- * the screen. A gesture is finished when [up][enqueueUp] lifts the last remaining finger
- * from the screen, or when a single [cancel][enqueueCancel] event is generated.
+ * a finger has started touching the screen, followed by zero or more [down][enqueueTouchDown],
+ * [move][enqueueTouchMove] and [up][enqueueTouchUp] events that respectively indicate that
+ * another finger started touching the screen, a finger moved around or a finger was lifted up
+ * from the screen. A gesture is finished when [up][enqueueTouchUp] lifts the last remaining
+ * finger from the screen, or when a single [cancel][enqueueTouchCancel] event is generated.
*
* Partial gestures don't have to be defined all in the same [performGesture] block, but
* keep in mind that while the gesture is not complete, all code you execute in between
@@ -348,12 +302,12 @@
* @param pointerId The id of the pointer, can be any number not yet in use by another pointer
* @param position The coordinate of the down event
*
- * @see movePointer
- * @see enqueueMove
- * @see enqueueUp
- * @see enqueueCancel
+ * @see updateTouchPointer
+ * @see enqueueTouchMove
+ * @see enqueueTouchUp
+ * @see enqueueTouchCancel
*/
- fun enqueueDown(pointerId: Int, position: Offset) {
+ fun enqueueTouchDown(pointerId: Int, position: Offset) {
var gesture = partialGesture
// Check if this pointer is not already down
@@ -361,11 +315,12 @@
"Cannot send DOWN event, a gesture is already in progress for pointer $pointerId"
}
+ // Send a MOVE event if pointers have changed since the last event
gesture?.flushPointerUpdates()
// Start a new gesture, or add the pointerId to the existing gesture
if (gesture == null) {
- gesture = PartialGesture(generateDownTime(), position, pointerId)
+ gesture = PartialGesture(currentTime, position, pointerId)
partialGesture = gesture
} else {
gesture.lastPositions[pointerId] = position
@@ -376,18 +331,22 @@
}
/**
- * Generates a move event [delay] milliseconds after the previous injected event of this
+ * Generates a move touch event [delay] milliseconds after the previous injected event of this
* gesture, without moving any of the pointers. The default [delay] is [10 milliseconds]
* [eventPeriodMillis]. Use this to commit all changes in pointer location made
- * with [movePointer]. The generated event will contain the current position of all pointers.
- * It is enqueued in this [InputDispatcher] and will be sent when [sendAllSynchronous] is
- * called at the end of [performGesture]. See [enqueueDown] for more information on how to
- * make complete gestures from partial gestures.
+ * with [updateTouchPointer]. The generated event will contain the current position of all
+ * pointers. It is enqueued in this [InputDispatcher] and will be sent when
+ * [sendAllSynchronous] is called at the end of [performGesture]. See [enqueueTouchDown] for
+ * documentation on creating touch gestures.
*
* @param delay The time in milliseconds between the previously injected event and the move
* event. [10 milliseconds][eventPeriodMillis] by default.
+ * @see enqueueTouchDown
+ * @see updateTouchPointer
+ * @see enqueueTouchUp
+ * @see enqueueTouchCancel
*/
- fun enqueueMove(delay: Long = eventPeriodMillis) {
+ fun enqueueTouchMove(delay: Long = eventPeriodMillis) {
val gesture = checkNotNull(partialGesture) {
"Cannot send MOVE event, no gesture is in progress"
}
@@ -395,29 +354,30 @@
"Cannot send MOVE event with a delay of $delay ms"
}
- increaseEventTime(delay)
+ advanceEventTime(delay)
gesture.enqueueMove()
gesture.hasPointerUpdates = false
}
/**
* Updates the position of the pointer with the given [pointerId] to the given [position],
- * but does not generate a move event. Use this to move multiple pointers simultaneously. To
- * generate the next move event, which will contain the current position of _all_ pointers
- * (not just the moved ones), call [enqueueMove] without arguments. If you move one or more
- * pointers and then call [enqueueDown] or [enqueueUp], without calling [enqueueMove] first,
- * a move event will be generated right before that down or up event. See [enqueueDown] for
- * more information on how to make complete gestures from partial gestures.
+ * but does not generate a move touch event. Use this to move multiple pointers
+ * simultaneously. To generate the next move touch event, which will contain the current
+ * position of _all_ pointers (not just the moved ones), call [enqueueTouchMove] without
+ * arguments. If you move one or more pointers and then call [enqueueTouchDown] or
+ * [enqueueTouchUp], without calling [enqueueTouchMove] first, a move event will be generated
+ * right before that down or up event. See [enqueueTouchDown] for documentation on creating
+ * touch gestures.
*
- * @param pointerId The id of the pointer to move, as supplied in [enqueueDown]
+ * @param pointerId The id of the pointer to move, as supplied in [enqueueTouchDown]
* @param position The position to move the pointer to
*
- * @see enqueueDown
- * @see enqueueMove
- * @see enqueueUp
- * @see enqueueCancel
+ * @see enqueueTouchDown
+ * @see enqueueTouchMove
+ * @see enqueueTouchUp
+ * @see enqueueTouchCancel
*/
- fun movePointer(pointerId: Int, position: Offset) {
+ fun updateTouchPointer(pointerId: Int, position: Offset) {
val gesture = partialGesture
// Check if this pointer is in the gesture
@@ -433,22 +393,22 @@
}
/**
- * Generates an up event for the given [pointerId] at the current position of that pointer,
- * [delay] milliseconds after the previous injected event of this gesture. The default
- * [delay] is 0 milliseconds. The generated event is enqueued in this [InputDispatcher] and
- * will be sent when [sendAllSynchronous] is called at the end of [performGesture]. See
- * [enqueueDown] for more information on how to make complete gestures from partial gestures.
+ * Generates an up touch event for the given [pointerId] at the current position of that
+ * pointer, [delay] milliseconds after the previous injected event of this gesture. The default
+ * [delay] is 0 milliseconds. The generated touch event is enqueued in this [InputDispatcher]
+ * and will be sent when [sendAllSynchronous] is called at the end of [performGesture]. See
+ * [enqueueTouchDown] for documentation on creating touch gestures.
*
- * @param pointerId The id of the pointer to lift up, as supplied in [enqueueDown]
+ * @param pointerId The id of the pointer to lift up, as supplied in [enqueueTouchDown]
* @param delay The time in milliseconds between the previously injected event and the move
* event. 0 milliseconds by default.
*
- * @see enqueueDown
- * @see movePointer
- * @see enqueueMove
- * @see enqueueCancel
+ * @see enqueueTouchDown
+ * @see updateTouchPointer
+ * @see enqueueTouchMove
+ * @see enqueueTouchCancel
*/
- fun enqueueUp(pointerId: Int, delay: Long = 0) {
+ fun enqueueTouchUp(pointerId: Int, delay: Long = 0) {
val gesture = partialGesture
// Check if this pointer is in the gesture
@@ -463,7 +423,7 @@
}
gesture.flushPointerUpdates()
- increaseEventTime(delay)
+ advanceEventTime(delay)
// First send the UP event
gesture.enqueueUp(pointerId)
@@ -476,21 +436,21 @@
}
/**
- * Generates a cancel event [delay] milliseconds after the previous injected event of this
- * gesture. The default [delay] is [10 milliseconds][InputDispatcher.eventPeriodMillis]. The
- * generated event is enqueued in this [InputDispatcher] and will be sent when
- * [sendAllSynchronous] is called at the end of [performGesture]. See [enqueueDown] for more
- * information on how to make complete gestures from partial gestures.
+ * Generates a cancel touch event [delay] milliseconds after the previous injected event of
+ * this gesture. The default [delay] is [10 milliseconds][InputDispatcher.eventPeriodMillis].
+ * The generated event is enqueued in this [InputDispatcher] and will be sent when
+ * [sendAllSynchronous] is called at the end of [performGesture]. See [enqueueTouchDown] for
+ * documentation on creating touch gestures.
*
* @param delay The time in milliseconds between the previously injected event and the cancel
* event. [10 milliseconds][InputDispatcher.eventPeriodMillis] by default.
*
- * @see enqueueDown
- * @see movePointer
- * @see enqueueMove
- * @see enqueueUp
+ * @see enqueueTouchDown
+ * @see updateTouchPointer
+ * @see enqueueTouchMove
+ * @see enqueueTouchUp
*/
- fun enqueueCancel(delay: Long = eventPeriodMillis) {
+ fun enqueueTouchCancel(delay: Long = eventPeriodMillis) {
val gesture = checkNotNull(partialGesture) {
"Cannot send CANCEL event, no gesture is in progress"
}
@@ -498,27 +458,27 @@
"Cannot send CANCEL event with a delay of $delay ms"
}
- increaseEventTime(delay)
+ advanceEventTime(delay)
gesture.enqueueCancel()
partialGesture = null
}
/**
+ * Generates a move event with all pointer locations, if any of the pointers has been moved by
+ * [updateTouchPointer] since the last move event.
+ */
+ private fun PartialGesture.flushPointerUpdates() {
+ if (hasPointerUpdates) {
+ enqueueTouchMove(eventPeriodMillis)
+ }
+ }
+
+ /**
* Sends all enqueued events and blocks while they are dispatched. If an exception is
* thrown during the process, all events that haven't yet been dispatched will be dropped.
*/
abstract fun sendAllSynchronous()
- /**
- * Generates a MOVE event with all pointer locations, if any of the pointers has been moved by
- * [movePointer] since the last MOVE event.
- */
- private fun PartialGesture.flushPointerUpdates() {
- if (hasPointerUpdates) {
- enqueueMove(eventPeriodMillis)
- }
- }
-
protected abstract fun PartialGesture.enqueueDown(pointerId: Int)
protected abstract fun PartialGesture.enqueueMove()
@@ -535,14 +495,16 @@
onDispose()
}
+ /**
+ * Override this method to take platform specific action when this dispatcher is disposed.
+ * E.g. to recycle event objects that the dispatcher still holds on to.
+ */
protected open fun onDispose() {}
}
/**
* The state of the current gesture. Contains the current position of all pointers and the
- * down time (start time) of the gesture. Does not contain the
- * [current time][InputDispatcher.currentTime], as the current time's lifecycle can span multiple
- * (chained) gestures.
+ * down time (start time) of the gesture. For the current time, see [InputDispatcher.currentTime].
*
* @param downTime The time of the first down event of this gesture
* @param startPosition The position of the first down event of this gesture
@@ -557,15 +519,9 @@
* The state of an [InputDispatcher], saved when the [GestureScope] is disposed and restored
* when the [GestureScope] is recreated.
*
- * @param currentTime The current event time. Usually this is when the last event was injected,
- * unless [InputDispatcher.advanceEventTime] has been used after the last event. The current time
- * will only be restored if there was an incomplete gesture or [performGesture]'s
- * `resumeFinishedGesture` parameter was true.
* @param partialGesture The state of an incomplete gesture. If no gesture was in progress
* when the state of the [InputDispatcher] was saved, this will be `null`.
*/
internal data class InputDispatcherState(
- val currentTime: Long,
- val partialGesture: PartialGesture?,
- val clockTimeOnDispose: Long
+ val partialGesture: PartialGesture?
)
diff --git a/compose/ui/ui-test/src/desktopMain/kotlin/androidx/compose/ui/test/DesktopInputDispatcher.desktop.kt b/compose/ui/ui-test/src/desktopMain/kotlin/androidx/compose/ui/test/DesktopInputDispatcher.desktop.kt
index 020c3ee..2601fb9 100644
--- a/compose/ui/ui-test/src/desktopMain/kotlin/androidx/compose/ui/test/DesktopInputDispatcher.desktop.kt
+++ b/compose/ui/ui-test/src/desktopMain/kotlin/androidx/compose/ui/test/DesktopInputDispatcher.desktop.kt
@@ -36,8 +36,6 @@
var gesturePointerId = 0L
}
- override val now: Long get() = System.nanoTime() / 1_000_000
-
private var isMousePressed = false
private var batchedEvents = mutableListOf<List<TestPointerInputEventData>>()
diff --git a/compose/ui/ui-text/benchmark/lint-baseline.xml b/compose/ui/ui-text/benchmark/lint-baseline.xml
index 00ea318..96b875a 100644
--- a/compose/ui/ui-text/benchmark/lint-baseline.xml
+++ b/compose/ui/ui-text/benchmark/lint-baseline.xml
@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+
+ <issue
+ id="SoonBlockedPrivateApi"
+ message="Reflective access to freeTextLayoutCaches will throw an exception when targeting API 31 and above"
+ errorLine1=" val freeCaches = Canvas::class.java.getDeclaredMethod("freeTextLayoutCaches")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/compose/ui/text/benchmark/TextBenchmarkTestRule.kt"
+ line="79"
+ column="30"/>
+ </issue>
<issue
id="BanUncheckedReflection"
diff --git a/compose/ui/ui-text/build.gradle b/compose/ui/ui-text/build.gradle
index 5137fe8..eabae59 100644
--- a/compose/ui/ui-text/build.gradle
+++ b/compose/ui/ui-text/build.gradle
@@ -57,6 +57,7 @@
androidTestImplementation(project(":compose:ui:ui-test-font"))
androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+ androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRules)
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.espressoCore)
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
index 886adf5..6308476 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
@@ -424,9 +424,13 @@
* http://www.unicode.org/reports/tr29/#Word_Boundaries
*/
fun getWordBoundary(offset: Int): TextRange {
- requireIndexInRange(offset)
+ requireIndexInRangeInclusiveEnd(offset)
- val paragraphIndex = findParagraphByIndex(paragraphInfoList, offset)
+ val paragraphIndex = if (offset == annotatedString.length) {
+ paragraphInfoList.lastIndex
+ } else {
+ findParagraphByIndex(paragraphInfoList, offset)
+ }
return with(paragraphInfoList[paragraphIndex]) {
paragraph.getWordBoundary(offset.toLocalIndex()).toGlobal()
diff --git a/compose/ui/ui-tooling-data/build.gradle b/compose/ui/ui-tooling-data/build.gradle
index e28a9fd..b5defed 100644
--- a/compose/ui/ui-tooling-data/build.gradle
+++ b/compose/ui/ui-tooling-data/build.gradle
@@ -37,6 +37,7 @@
androidTestImplementation project(":compose:ui:ui-test-junit4")
androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.testRules)
diff --git a/compose/ui/ui-tooling-data/src/androidTest/AndroidManifest.xml b/compose/ui/ui-tooling-data/src/androidTest/AndroidManifest.xml
index b2770d0..dbe9365 100644
--- a/compose/ui/ui-tooling-data/src/androidTest/AndroidManifest.xml
+++ b/compose/ui/ui-tooling-data/src/androidTest/AndroidManifest.xml
@@ -16,6 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.compose.ui.tooling.data.test">
<application>
- <activity android:name="androidx.compose.ui.tooling.data.TestActivity" />
+ <activity android:name="androidx.compose.ui.tooling.data.TestActivity" android:exported="true"/>
</application>
</manifest>
\ No newline at end of file
diff --git a/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt b/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt
index 6f49adf..65313de 100644
--- a/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt
+++ b/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt
@@ -16,10 +16,13 @@
package androidx.compose.desktop.ui.tooling.preview.runtime
-import androidx.compose.desktop.Window
import androidx.compose.runtime.Composable
import androidx.compose.runtime.currentComposer
import androidx.compose.ui.tooling.CommonPreviewUtils.invokeComposableViaReflection
+import androidx.compose.ui.window.Window
+import androidx.compose.ui.window.launchApplication
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.GlobalScope
internal class PreviewRunner {
companion object {
@@ -42,8 +45,11 @@
)
}
- Window {
- previewComposition()
+ @OptIn(DelicateCoroutinesApi::class)
+ GlobalScope.launchApplication {
+ Window(onCloseRequest = ::exitApplication) {
+ previewComposition()
+ }
}
}
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
index a073e46..e8234fa 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
@@ -106,6 +106,7 @@
import androidx.compose.ui.unit.offset
import androidx.compose.ui.unit.toOffset
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.FlakyTest
import androidx.test.filters.MediumTest
import androidx.test.filters.SdkSuppress
import org.junit.Assert.assertEquals
@@ -2915,6 +2916,7 @@
validateSquareColors(outerColor = Color.Blue, innerColor = Color.White, size = 10)
}
+ @FlakyTest
@Test
fun makingItemLarger() {
var height by mutableStateOf(30)
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParserTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParserTest.kt
index 2d9036f..01c9518 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParserTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParserTest.kt
@@ -16,6 +16,8 @@
package androidx.compose.ui.graphics.vector.compat
+import android.content.res.Resources
+import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
@@ -161,6 +163,107 @@
path[2].assertType<PathNode.Close>()
}
+ @Test
+ fun testParsePlus() {
+ val asset = loadVector(R.drawable.ic_triangle_plus)
+ assertEquals(Color.Blue, asset.tintColor)
+ assertEquals(BlendMode.Plus, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testParseScreen() {
+ val asset = loadVector(R.drawable.ic_triangle_screen)
+ assertEquals(Color.Blue, asset.tintColor)
+ assertEquals(BlendMode.Screen, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testParseSrcAtop() {
+ val asset = loadVector(R.drawable.ic_triangle_src_atop)
+ assertEquals(Color.Blue, asset.tintColor)
+ assertEquals(BlendMode.SrcAtop, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testParseSrcIn() {
+ val asset = loadVector(R.drawable.ic_triangle_src_in)
+ assertEquals(Color.Blue, asset.tintColor)
+ assertEquals(BlendMode.SrcIn, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testParseModulate() {
+ val asset = loadVector(R.drawable.ic_triangle_modulate)
+ assertEquals(Color.Blue, asset.tintColor)
+ assertEquals(BlendMode.Modulate, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testParseSrcOver() {
+ val asset = loadVector(R.drawable.ic_triangle_src_over)
+ assertEquals(Color.Blue, asset.tintColor)
+ assertEquals(BlendMode.SrcOver, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testTintFromColorStateList() {
+ val asset = loadVector(R.drawable.ic_triangle_csl_tint)
+ assertEquals(Color.Blue, asset.tintColor)
+ assertEquals(BlendMode.SrcIn, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testTintFromColorStateListTheme() {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ val theme = context.resources.newTheme()
+ theme.applyStyle(R.style.VectorTestTheme, true)
+
+ val asset = loadVector(R.drawable.ic_triangle_csl_tint_theme, theme)
+ assertEquals(Color.Green, asset.tintColor)
+ assertEquals(BlendMode.SrcIn, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testTintColorFromAndroidResources() {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ val theme = context.resources.newTheme()
+ theme.applyStyle(R.style.VectorTestTheme, true)
+ val asset = loadVector(R.drawable.ic_triangle_color_resource_tint, theme)
+ assertEquals(Color.Black, asset.tintColor)
+ assertEquals(BlendMode.SrcIn, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testTintColorFromThemeParsed() {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+
+ val theme = context.resources.newTheme()
+ theme.applyStyle(R.style.VectorTestTheme, true)
+
+ val asset = loadVector(R.drawable.ic_triangle_color_theme_tint, theme)
+ assertEquals(Color.Green, asset.tintColor)
+ assertEquals(BlendMode.SrcIn, asset.tintBlendMode)
+ }
+
+ @Test
+ fun testTintColorFromThemeIgnored() {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+
+ val theme = context.resources.newTheme()
+ val asset = loadVector(R.drawable.ic_triangle_color_theme_tint, theme)
+ assertEquals(Color.Unspecified, asset.tintColor)
+ assertEquals(BlendMode.SrcIn, asset.tintBlendMode)
+ }
+
+ private fun loadVector(id: Int, theme: Resources.Theme? = null): ImageVector {
+ val res = InstrumentationRegistry.getInstrumentation().targetContext.resources
+ return ImageVector.vectorResource(
+ theme,
+ res,
+ id
+ )
+ }
+
/**
* Asserts that [this] is the expected type [T], and then returns [this] cast to [T].
*/
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
index af745d5..5d8dd0f 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
@@ -35,6 +35,7 @@
import androidx.compose.ui.layout.layout
import androidx.compose.ui.node.InternalCoreApi
import androidx.compose.ui.node.LayoutNode
+import androidx.compose.ui.node.LayoutNodeDrawScope
import androidx.compose.ui.node.MeasureAndLayoutDelegate
import androidx.compose.ui.node.OwnedLayer
import androidx.compose.ui.node.Owner
@@ -3269,6 +3270,8 @@
override val viewConfiguration: ViewConfiguration
get() = TODO("Not yet implemented")
override val snapshotObserver = OwnerSnapshotObserver { it.invoke() }
+
+ override val sharedDrawScope = LayoutNodeDrawScope()
}
private fun List<LogEntry>.verifyOnPointerEventCall(
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/DepthSortedSetTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/DepthSortedSetTest.kt
index ef34894..68dd09e 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/DepthSortedSetTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/DepthSortedSetTest.kt
@@ -18,6 +18,7 @@
import androidx.compose.ui.node.DepthSortedSet
import androidx.compose.ui.node.LayoutNode
+import androidx.compose.ui.node.LayoutNodeDrawScope
import androidx.compose.ui.node.Owner
import androidx.compose.ui.node.add
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -156,6 +157,8 @@
}
internal abstract class DepthTestOwner : Owner {
+ override val sharedDrawScope = LayoutNodeDrawScope()
+
override val root: LayoutNode
get() = LayoutNode()
}
diff --git a/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_color_resource_tint.xml b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_color_resource_tint.xml
new file mode 100644
index 0000000..d14d840
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_color_resource_tint.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+ -->
+
+<vector android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="32"
+ android:viewportWidth="32"
+ android:tint="@android:color/black"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <path android:fillColor="#FF0000" android:pathData="h 32, l 0, 32, z" />
+</vector>
diff --git a/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_color_theme_tint.xml b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_color_theme_tint.xml
new file mode 100644
index 0000000..c4836c81
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_color_theme_tint.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+ -->
+
+<vector android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="32"
+ android:viewportWidth="32"
+ android:tint="?android:colorAccent"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <path android:fillColor="#FF0000" android:pathData="h 32, l 0, 32, z" />
+</vector>
diff --git a/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_csl_tint.xml b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_csl_tint.xml
new file mode 100644
index 0000000..56c533b
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_csl_tint.xml
@@ -0,0 +1,26 @@
+<!--
+ 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.
+ -->
+
+<vector android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="32"
+ android:viewportWidth="32"
+ android:tint="@color/vector_tint_color"
+ android:tintMode="src_in"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <path android:fillColor="#FF0000" android:pathData="h 32, l 0, 32, z" />
+</vector>
diff --git a/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_csl_tint_theme.xml b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_csl_tint_theme.xml
new file mode 100644
index 0000000..ce4bb68
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/res/drawable/ic_triangle_csl_tint_theme.xml
@@ -0,0 +1,26 @@
+<!--
+ 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.
+ -->
+
+<vector android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="32"
+ android:viewportWidth="32"
+ android:tint="@color/vector_tint_theme_color"
+ android:tintMode="src_in"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <path android:fillColor="#FF0000" android:pathData="h 32, l 0, 32, z" />
+</vector>
diff --git a/compose/ui/ui/src/androidAndroidTest/res/values/themes.xml b/compose/ui/ui/src/androidAndroidTest/res/values/themes.xml
index 15b11a3..5f24027 100644
--- a/compose/ui/ui/src/androidAndroidTest/res/values/themes.xml
+++ b/compose/ui/ui/src/androidAndroidTest/res/values/themes.xml
@@ -22,4 +22,8 @@
-->
<item name="android:scrollbars">vertical</item>
</style>
+
+ <style name="VectorTestTheme" parent="android:Theme.Material">
+ <item name="android:colorAccent">#00FF00</item>
+ </style>
</resources>
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParser.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParser.android.kt
index f55167e..af63288 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParser.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParser.android.kt
@@ -186,15 +186,24 @@
val tintColor = if (
vectorAttrs.hasValue(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_TINT)
) {
- // first check if is a simple color
val value = TypedValue()
vectorAttrs.getValue(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_TINT, value)
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
- value.type <= TypedValue.TYPE_LAST_COLOR_INT
- ) {
- Color(value.data)
- } else {
+ // Unable to parse theme attributes outside of the framework here.
+ // This is a similar limitation to VectorDrawableCompat's parsing logic within
+ // updateStateFromTypedArray as TypedArray#extractThemeAttrs is not a public API
+ // ignore tint colors provided from the theme itself.
+ if (value.type == TypedValue.TYPE_ATTRIBUTE) {
Color.Unspecified
+ } else {
+ val tintColorStateList = TypedArrayUtils.getNamedColorStateList(
+ vectorAttrs, this, theme, "tint",
+ AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_TINT
+ )
+ if (tintColorStateList != null) {
+ Color(tintColorStateList.defaultColor)
+ } else {
+ Color.Unspecified
+ }
}
} else {
Color.Unspecified
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index ed7fb62..988de49 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -90,6 +90,7 @@
import androidx.compose.ui.node.InternalCoreApi
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.node.LayoutNode.UsageByParent
+import androidx.compose.ui.node.LayoutNodeDrawScope
import androidx.compose.ui.node.MeasureAndLayoutDelegate
import androidx.compose.ui.node.OwnedLayer
import androidx.compose.ui.node.Owner
@@ -139,6 +140,8 @@
*/
private var superclassInitComplete = true
+ override val sharedDrawScope = LayoutNodeDrawScope()
+
override val view: View get() = this
override var density = Density(context)
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index cdd0827..b553e6a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -69,10 +69,6 @@
*/
private const val DebugChanges = false
-// Top level DrawScope instance shared across the LayoutNode hierarchy to re-use internal
-// drawing objects
-internal val sharedDrawScope = LayoutNodeDrawScope()
-
/**
* An element in the layout hierarchy, built with compose UI.
*/
@@ -541,7 +537,8 @@
*/
internal val alignmentLines = LayoutNodeAlignmentLines(this)
- internal val mDrawScope: LayoutNodeDrawScope = sharedDrawScope
+ internal val mDrawScope: LayoutNodeDrawScope
+ get() = requireOwner().sharedDrawScope
/**
* Whether or not this [LayoutNode] and all of its parents have been placed in the hierarchy.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index 5a70959..bab077b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -46,6 +46,11 @@
*/
val root: LayoutNode
+ /**
+ * Draw scope reused for drawing speed up.
+ */
+ val sharedDrawScope: LayoutNodeDrawScope
+
val rootForTest: RootForTest
/**
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AWTDebounceEventQueue.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AWTDebounceEventQueue.desktop.kt
deleted file mode 100644
index 5fdfb29..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AWTDebounceEventQueue.desktop.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.desktop
-
-import kotlinx.coroutines.DelicateCoroutinesApi
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.swing.Swing
-import kotlinx.coroutines.yield
-import kotlin.coroutines.CoroutineContext
-
-/**
- * Dispatch events on the next EDT tick if they are blocking EDT too long,
- * so EDT can handle more important actions (like render a new frame).
- *
- * (EDT - AWT event dispatch thread)
- *
- * [maxNanosToBlockThread] defines how long events can block EDT.
- *
- * It is needed in a case when we have a lot of heavy events (like mouse scroll)
- * in a short period of time.
- *
- * Without dispatching events we may have a situation
- * when 30 events of scroll block AWT Thread for 1 second, without rerendering content.
- */
-@OptIn(DelicateCoroutinesApi::class)
-internal class AWTDebounceEventQueue constructor(
- // 4 ms is enough for the user not to see the lags
- private val maxNanosToBlockThread: Long = 4_000_000, // 4 milliseconds
- private val nanoTime: () -> Long = System::nanoTime,
- context: CoroutineContext = Dispatchers.Swing
-) {
- private val queue = Channel<() -> Unit>(Channel.UNLIMITED)
-
- private var job = GlobalScope.launch(context) {
- var lastTime = nanoTime()
- for (event in queue) {
- val time = nanoTime()
- if (time - lastTime >= maxNanosToBlockThread) {
- lastTime = time
- yield()
- }
- event()
- }
- }
-
- fun cancel() {
- job.cancel()
- }
-
- fun post(event: () -> Unit) {
- queue.trySend(event)
- }
-}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppFrame.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppFrame.desktop.kt
index b2fe299..10b03a9 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppFrame.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppFrame.desktop.kt
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
package androidx.compose.desktop
import androidx.compose.ui.unit.IntOffset
@@ -28,6 +29,10 @@
* <p>
* Known subclasses: AppWindow
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Window_API_new)"
+)
abstract class AppFrame {
/**
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppManager.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppManager.desktop.kt
index 2cdac33..8427584 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppManager.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppManager.desktop.kt
@@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
package androidx.compose.desktop
import androidx.compose.ui.window.v1.MenuBar
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Window_API_new)"
+)
object AppManager {
init {
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppWindow.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppWindow.desktop.kt
index 867c549..7a8c107 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppWindow.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/AppWindow.desktop.kt
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
package androidx.compose.desktop
import androidx.compose.runtime.Composable
@@ -20,11 +21,10 @@
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.configureSwingGlobalsForCompose
-import androidx.compose.ui.platform.Keyboard
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.window.v1.MenuBar
-import java.awt.Container
import java.awt.Frame
import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent
@@ -42,12 +42,13 @@
* Local composition of [AppWindow]. [AppWindow] is a high level window implementation. This local
* composition is used to get the current [AppWindow].
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Window_API_new)"
+)
val LocalAppWindow = compositionLocalOf<AppWindow> {
error("CompositionLocal LocalAppWindow not provided")
}
-internal val LocalLayerContainer = compositionLocalOf<Container> {
- error("CompositionLocal LayerContainer not provided")
-}
/**
* Opens a window with the given content.
@@ -70,6 +71,10 @@
* onResize, onRelocate.
* @param onDismissRequest Executes when the user tries to close the Window.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Window_API_new)"
+)
fun Window(
title: String = "JetpackDesktopWindow",
size: IntSize = IntSize(800, 600),
@@ -107,6 +112,10 @@
/**
* AppWindow is a class that represents a window.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Tray_Notifications_MenuBar_new)"
+)
class AppWindow : AppFrame {
/**
@@ -448,7 +457,6 @@
}
onCreate(parentComposition) {
- window.layer.owners.keyboard = keyboard
content()
}
@@ -522,9 +530,4 @@
override fun removeMouseMotionListener(listener: MouseMotionListener) {
window.layer.component.removeMouseMotionListener(listener)
}
-
- /**
- * Gets the Keyboard object of the window.
- */
- val keyboard: Keyboard = Keyboard()
}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeDialog.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeDialog.desktop.kt
deleted file mode 100644
index 971b7af..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeDialog.desktop.kt
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.compose.desktop
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionContext
-import androidx.compose.ui.input.key.KeyEvent
-import androidx.compose.ui.window.DialogWindowScope
-import org.jetbrains.skiko.GraphicsApi
-import java.awt.Component
-import java.awt.Window
-import java.awt.event.MouseListener
-import java.awt.event.MouseMotionListener
-import java.awt.event.MouseWheelListener
-import javax.swing.JDialog
-
-/**
- * ComposeDialog is a dialog for building UI using Compose for Desktop.
- * ComposeDialog inherits javax.swing.JDialog.
- */
-class ComposeDialog(
- owner: Window? = null,
- modalityType: ModalityType = ModalityType.MODELESS
-) : JDialog(owner, modalityType) {
- private val delegate = ComposeWindowDelegate()
- internal val layer get() = delegate.layer
-
- init {
- contentPane.add(delegate.pane)
- }
-
- override fun add(component: Component) = delegate.add(component)
-
- override fun remove(component: Component) = delegate.remove(component)
-
- /**
- * Composes the given composable into the ComposeDialog.
- *
- * The new composition can be logically "linked" to an existing one, by providing a
- * [parentComposition]. This will ensure that invalidations and CompositionLocals will flow
- * through the two compositions as if they were not separate.
- *
- * @param parentComposition The parent composition reference to coordinate
- * scheduling of composition updates.
- * If null then default root composition will be used.
- * @param onPreviewKeyEvent This callback is invoked when the user interacts with the hardware
- * keyboard. It gives ancestors of a focused component the chance to intercept a [KeyEvent].
- * Return true to stop propagation of this event. If you return false, the key event will be
- * sent to this [onPreviewKeyEvent]'s child. If none of the children consume the event,
- * it will be sent back up to the root using the onKeyEvent callback.
- * @param onKeyEvent This callback is invoked when the user interacts with the hardware
- * keyboard. While implementing this callback, return true to stop propagation of this event.
- * If you return false, the key event will be sent to this [onKeyEvent]'s parent.
- * @param content Composable content of the ComposeWindow.
- */
- fun setContent(
- parentComposition: CompositionContext? = null,
- onPreviewKeyEvent: ((KeyEvent) -> Boolean) = { false },
- onKeyEvent: ((KeyEvent) -> Boolean) = { false },
- content: @Composable DialogWindowScope.() -> Unit
- ) {
- val scope = object : DialogWindowScope {
- override val window: ComposeDialog get() = this@ComposeDialog
- }
- delegate.setContent(
- parentComposition,
- onPreviewKeyEvent,
- onKeyEvent,
- ) {
- scope.content()
- }
- }
-
- override fun dispose() {
- delegate.dispose()
- super.dispose()
- }
-
- override fun setVisible(value: Boolean) {
- if (value != isVisible) {
- super.setVisible(value)
- delegate.setVisible(value)
- }
- }
-
- /**
- * Registers a task to run when the rendering API changes.
- */
- fun onRenderApiChanged(action: () -> Unit) {
- delegate.onRenderApiChanged(action)
- }
-
- /**
- * Retrieve underlying platform-specific operating system handle for the root window where
- * ComposeDialog is rendered. Currently returns HWND on Windows, Display on X11 and NSWindow
- * on macOS.
- */
- val windowHandle: Long get() = delegate.windowHandle
-
- /**
- * Returns low-level rendering API used for rendering in this ComposeDialog. API is
- * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
- * environment variable.
- */
- val renderApi: GraphicsApi get() = delegate.renderApi
-
- // We need overridden listeners because we mix Swing and AWT components in the
- // org.jetbrains.skiko.SkiaLayer, they don't work well together.
- // TODO(demin): is it possible to fix that without overriding?
-
- override fun addMouseListener(listener: MouseListener) =
- delegate.addMouseListener(listener)
-
- override fun removeMouseListener(listener: MouseListener) =
- delegate.removeMouseListener(listener)
-
- override fun addMouseMotionListener(listener: MouseMotionListener) =
- delegate.addMouseMotionListener(listener)
-
- override fun removeMouseMotionListener(listener: MouseMotionListener) =
- delegate.removeMouseMotionListener(listener)
-
- override fun addMouseWheelListener(listener: MouseWheelListener) =
- delegate.addMouseWheelListener(listener)
-
- override fun removeMouseWheelListener(listener: MouseWheelListener) =
- delegate.removeMouseWheelListener(listener)
-}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
deleted file mode 100644
index 42af9fd..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.desktop
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Composition
-import androidx.compose.runtime.CompositionContext
-import androidx.compose.ui.input.mouse.MouseScrollEvent
-import androidx.compose.ui.input.mouse.MouseScrollOrientation
-import androidx.compose.ui.input.mouse.MouseScrollUnit
-import androidx.compose.ui.platform.DesktopComponent
-import androidx.compose.ui.platform.DesktopOwner
-import androidx.compose.ui.platform.DesktopOwners
-import androidx.compose.ui.platform.setContent
-import androidx.compose.ui.unit.Density
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.swing.Swing
-import org.jetbrains.skija.Canvas
-import org.jetbrains.skiko.SkiaLayer
-import org.jetbrains.skiko.SkiaRenderer
-import java.awt.Dimension
-import java.awt.Point
-import java.awt.event.FocusEvent
-import java.awt.event.InputMethodEvent
-import java.awt.event.InputMethodListener
-import java.awt.event.KeyAdapter
-import java.awt.event.KeyEvent
-import java.awt.event.MouseAdapter
-import java.awt.event.MouseEvent
-import java.awt.event.MouseMotionAdapter
-import java.awt.event.MouseWheelEvent
-import java.awt.im.InputMethodRequests
-import androidx.compose.ui.input.key.KeyEvent as ComposeKeyEvent
-import androidx.compose.ui.window.density
-
-internal class ComposeLayer {
- private var isDisposed = false
-
- private val coroutineScope = CoroutineScope(Dispatchers.Swing)
- // TODO(demin): probably we need to get rid of asynchronous events. it was added because of
- // slow lazy scroll. But events become unpredictable, and we can't consume them.
- // Alternative solution to a slow scroll - merge multiple scroll events into a single one.
- private val events = AWTDebounceEventQueue()
-
- internal val wrapped = Wrapped().apply {
- onStateChanged(SkiaLayer.PropertyKind.ContentScale) { _ ->
- resetDensity()
- }
- }
-
- internal val owners: DesktopOwners = DesktopOwners(
- coroutineScope,
- wrapped,
- wrapped::needRedraw
- )
-
- private var owner: DesktopOwner? = null
- private var composition: Composition? = null
-
- private var initOwner: (() -> Unit)? = null
-
- private lateinit var density: Density
-
- inner class Wrapped : SkiaLayer(), DesktopComponent {
- var currentInputMethodRequests: InputMethodRequests? = null
-
- var isInit = false
- private set
-
- override fun init() {
- super.init()
- isInit = true
- resetDensity()
- initOwner?.invoke()
- }
-
- internal fun resetDensity() {
- this@ComposeLayer.density = (this as SkiaLayer).density
- owner?.density = density
- }
-
- override fun getInputMethodRequests() = currentInputMethodRequests
-
- override fun enableInput(inputMethodRequests: InputMethodRequests) {
- currentInputMethodRequests = inputMethodRequests
- enableInputMethods(true)
- val focusGainedEvent = FocusEvent(this, FocusEvent.FOCUS_GAINED)
- inputContext.dispatchEvent(focusGainedEvent)
- }
-
- override fun disableInput() {
- currentInputMethodRequests = null
- }
-
- override fun doLayout() {
- super.doLayout()
- val owner = owner
- if (owner != null) {
- val density = density.density
- owner.setSize(
- (width * density).toInt().coerceAtLeast(0),
- (height * density).toInt().coerceAtLeast(0)
- )
- owner.measureAndLayout()
- preferredSize = Dimension(
- (owner.root.width / density).toInt(),
- (owner.root.height / density).toInt()
- )
- }
- }
-
- override val locationOnScreen: Point
- @Suppress("ACCIDENTAL_OVERRIDE") // KT-47743
- get() = super.getLocationOnScreen()
-
- override val density: Density
- get() = this@ComposeLayer.density
- }
-
- val component: SkiaLayer
- get() = wrapped
-
- init {
- wrapped.renderer = object : SkiaRenderer {
- override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
- try {
- owners.onFrame(canvas, width, height, nanoTime)
- } catch (e: Throwable) {
- if (System.getProperty("compose.desktop.render.ignore.errors") == null) {
- throw e
- }
- }
- }
- }
- initCanvas()
- }
-
- private fun initCanvas() {
- wrapped.addInputMethodListener(object : InputMethodListener {
- override fun caretPositionChanged(event: InputMethodEvent?) {
- if (event != null) {
- owners.onInputMethodEvent(event)
- }
- }
-
- override fun inputMethodTextChanged(event: InputMethodEvent) = events.post {
- owners.onInputMethodEvent(event)
- }
- })
-
- wrapped.addMouseListener(object : MouseAdapter() {
- override fun mouseClicked(event: MouseEvent) = Unit
-
- override fun mousePressed(event: MouseEvent) = events.post {
- owners.onMousePressed(
- (event.x * density.density).toInt(),
- (event.y * density.density).toInt(),
- event
- )
- }
-
- override fun mouseReleased(event: MouseEvent) = events.post {
- owners.onMouseReleased(
- (event.x * density.density).toInt(),
- (event.y * density.density).toInt(),
- event
- )
- }
-
- override fun mouseEntered(event: MouseEvent) = events.post {
- owners.onMouseEntered(
- (event.x * density.density).toInt(),
- (event.y * density.density).toInt()
- )
- }
-
- override fun mouseExited(event: MouseEvent) = events.post {
- owners.onMouseExited()
- }
- })
- wrapped.addMouseMotionListener(object : MouseMotionAdapter() {
- override fun mouseDragged(event: MouseEvent) = events.post {
- owners.onMouseMoved(
- (event.x * density.density).toInt(),
- (event.y * density.density).toInt(),
- event
- )
- }
-
- override fun mouseMoved(event: MouseEvent) = events.post {
- owners.onMouseMoved(
- (event.x * density.density).toInt(),
- (event.y * density.density).toInt(),
- event
- )
- }
- })
- wrapped.addMouseWheelListener { event ->
- events.post {
- owners.onMouseScroll(
- (event.x * density.density).toInt(),
- (event.y * density.density).toInt(),
- event.toComposeEvent()
- )
- }
- }
- wrapped.focusTraversalKeysEnabled = false
- wrapped.addKeyListener(object : KeyAdapter() {
- override fun keyPressed(event: KeyEvent) {
- if (owners.onKeyPressed(event)) {
- event.consume()
- }
- }
-
- override fun keyReleased(event: KeyEvent) {
- if (owners.onKeyReleased(event)) {
- event.consume()
- }
- }
-
- override fun keyTyped(event: KeyEvent) {
- if (owners.onKeyTyped(event)) {
- event.consume()
- }
- }
- })
- }
-
- private fun MouseWheelEvent.toComposeEvent() = MouseScrollEvent(
- delta = if (scrollType == MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
- MouseScrollUnit.Page((scrollAmount * preciseWheelRotation).toFloat())
- } else {
- MouseScrollUnit.Line((scrollAmount * preciseWheelRotation).toFloat())
- },
-
- // There are no other way to detect horizontal scrolling in AWT
- orientation = if (isShiftDown) {
- MouseScrollOrientation.Horizontal
- } else {
- MouseScrollOrientation.Vertical
- }
- )
-
- fun dispose() {
- check(!isDisposed)
- composition?.dispose()
- owner?.dispose()
- events.cancel()
- coroutineScope.cancel()
- wrapped.dispose()
- initOwner = null
- isDisposed = true
- }
-
- internal fun setContent(
- parentComposition: CompositionContext? = null,
- onPreviewKeyEvent: (ComposeKeyEvent) -> Boolean = { false },
- onKeyEvent: (ComposeKeyEvent) -> Boolean = { false },
- content: @Composable () -> Unit
- ) {
- check(!isDisposed)
- check(composition == null && initOwner == null) { "Cannot set content twice" }
- initOwner = {
- check(!isDisposed)
- if (wrapped.isInit && owner == null) {
- owner = DesktopOwner(
- owners,
- density,
- onPreviewKeyEvent = onPreviewKeyEvent,
- onKeyEvent = onKeyEvent
- )
- composition = owner!!.setContent(parent = parentComposition, content = content)
- initOwner = null
- }
- }
- // We can't create DesktopOwner now, because we don't know density yet.
- // We will know density only after SkiaLayer will be visible.
- initOwner!!()
- }
-}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposePanel.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposePanel.desktop.kt
deleted file mode 100644
index 60f7182..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposePanel.desktop.kt
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.compose.desktop
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import org.jetbrains.skiko.ClipComponent
-import org.jetbrains.skiko.GraphicsApi
-import java.awt.Color
-import java.awt.Component
-import javax.swing.JLayeredPane
-import javax.swing.SwingUtilities.isEventDispatchThread
-
-/**
- * ComposePanel is a panel for building UI using Compose for Desktop.
- */
-class ComposePanel : JLayeredPane() {
- init {
- check(isEventDispatchThread()) {
- "ComposePanel should be created inside AWT Event Dispatch Thread" +
- " (use SwingUtilities.invokeLater).\n" +
- "Creating from another thread isn't supported."
- }
- setBackground(Color.white)
- setLayout(null)
- }
-
- internal var layer: ComposeLayer? = null
- private val clipMap = mutableMapOf<Component, ClipComponent>()
- private var content: (@Composable () -> Unit)? = null
-
- override fun setBounds(x: Int, y: Int, width: Int, height: Int) {
- layer?.wrapped?.setSize(width, height)
- super.setBounds(x, y, width, height)
- }
-
- override fun getPreferredSize() = layer?.wrapped?.preferredSize
-
- /**
- * Sets Compose content of the ComposePanel.
- *
- * @param content Composable content of the ComposePanel.
- */
- fun setContent(content: @Composable () -> Unit) {
- // The window (or root container) may not be ready to render composable content, so we need
- // to keep the lambda describing composable content and set the content only when
- // everything is ready to avoid accidental crashes and memory leaks on all supported OS
- // types.
- this.content = content
- initContent()
- }
-
- private fun initContent() {
- if (layer != null && content != null) {
- layer!!.setContent {
- CompositionLocalProvider(
- LocalLayerContainer provides this,
- content = content!!
- )
- }
- }
- }
-
- override fun add(component: Component): Component {
- if (layer == null) {
- return component
- }
- val clipComponent = ClipComponent(component)
- clipMap.put(component, clipComponent)
- layer!!.wrapped.clipComponents.add(clipComponent)
- return super.add(component, Integer.valueOf(0))
- }
-
- override fun remove(component: Component) {
- layer!!.wrapped.clipComponents.remove(clipMap.get(component)!!)
- clipMap.remove(component)
- super.remove(component)
- }
-
- override fun addNotify() {
- super.addNotify()
-
- // After [super.addNotify] is called we can safely initialize the layer and composable
- // content.
- layer = ComposeLayer().apply {
- wrapped.setSize(width, height)
- }
- initContent()
- super.add(layer!!.component, Integer.valueOf(1))
- }
-
- override fun removeNotify() {
- if (layer != null) {
- layer!!.dispose()
- super.remove(layer!!.component)
- }
-
- super.removeNotify()
- }
-
- override fun requestFocus() {
- if (layer != null) {
- layer!!.component.requestFocus()
- }
- }
-
- /**
- * Returns low-level rendering API used for rendering in this ComposeWindow. API is
- * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
- * environment variable.
- */
- val renderApi: GraphicsApi
- get() = if (layer != null) layer!!.component.renderApi else GraphicsApi.UNKNOWN
-}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindow.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindow.desktop.kt
deleted file mode 100644
index db0d2de..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindow.desktop.kt
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.compose.desktop
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionContext
-import androidx.compose.ui.input.key.KeyEvent
-import androidx.compose.ui.window.FrameWindowScope
-import androidx.compose.ui.window.UndecoratedWindowResizer
-import androidx.compose.ui.window.WindowPlacement
-import org.jetbrains.skiko.GraphicsApi
-import java.awt.Component
-import java.awt.event.MouseListener
-import java.awt.event.MouseMotionListener
-import java.awt.event.MouseWheelListener
-import javax.swing.JFrame
-
-/**
- * ComposeWindow is a window for building UI using Compose for Desktop.
- * ComposeWindow inherits javax.swing.JFrame.
- */
-class ComposeWindow : JFrame() {
- private val delegate = ComposeWindowDelegate()
- internal val layer get() = delegate.layer
-
- init {
- contentPane.add(delegate.pane)
- }
-
- override fun add(component: Component) = delegate.add(component)
-
- override fun remove(component: Component) = delegate.remove(component)
-
- /**
- * Composes the given composable into the ComposeWindow.
- *
- * The new composition can be logically "linked" to an existing one, by providing a
- * [parentComposition]. This will ensure that invalidations and CompositionLocals will flow
- * through the two compositions as if they were not separate.
- *
- * @param parentComposition The parent composition reference to coordinate
- * scheduling of composition updates.
- * If null then default root composition will be used.
- * @param onPreviewKeyEvent This callback is invoked when the user interacts with the hardware
- * keyboard. It gives ancestors of a focused component the chance to intercept a [KeyEvent].
- * Return true to stop propagation of this event. If you return false, the key event will be
- * sent to this [onPreviewKeyEvent]'s child. If none of the children consume the event,
- * it will be sent back up to the root using the onKeyEvent callback.
- * @param onKeyEvent This callback is invoked when the user interacts with the hardware
- * keyboard. While implementing this callback, return true to stop propagation of this event.
- * If you return false, the key event will be sent to this [onKeyEvent]'s parent.
- * @param content Composable content of the ComposeWindow.
- */
- fun setContent(
- parentComposition: CompositionContext? = null,
- onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
- onKeyEvent: (KeyEvent) -> Boolean = { false },
- content: @Composable FrameWindowScope.() -> Unit
- ) {
- val scope = object : FrameWindowScope {
- override val window: ComposeWindow get() = this@ComposeWindow
- }
- delegate.setContent(
- parentComposition,
- onPreviewKeyEvent,
- onKeyEvent
- ) {
- scope.content()
- }
- }
-
- override fun dispose() {
- delegate.dispose()
- super.dispose()
- }
-
- private val undecoratedWindowResizer = UndecoratedWindowResizer(this)
-
- override fun setUndecorated(value: Boolean) {
- super.setUndecorated(value)
- undecoratedWindowResizer.enabled = isUndecorated && isResizable
- }
-
- override fun setResizable(value: Boolean) {
- super.setResizable(value)
- undecoratedWindowResizer.enabled = isUndecorated && isResizable
- }
-
- override fun setVisible(value: Boolean) {
- if (value != isVisible) {
- super.setVisible(value)
- delegate.setVisible(value)
- }
- }
-
- var placement: WindowPlacement
- get() = when {
- isFullscreen -> WindowPlacement.Fullscreen
- isMaximized -> WindowPlacement.Maximized
- else -> WindowPlacement.Floating
- }
- set(value) {
- when (value) {
- WindowPlacement.Fullscreen -> {
- isFullscreen = true
- }
- WindowPlacement.Maximized -> {
- isMaximized = true
- }
- WindowPlacement.Floating -> {
- isFullscreen = false
- isMaximized = false
- }
- }
- }
-
- /**
- * `true` if the window is in fullscreen mode, `false` otherwise
- */
- private var isFullscreen: Boolean
- get() = layer.component.fullscreen
- set(value) {
- layer.component.fullscreen = value
- }
-
- /**
- * `true` if the window is maximized to fill all available screen space, `false` otherwise
- */
- private var isMaximized: Boolean
- get() = extendedState and MAXIMIZED_BOTH != 0
- set(value) {
- extendedState = if (value) {
- extendedState or MAXIMIZED_BOTH
- } else {
- extendedState and MAXIMIZED_BOTH.inv()
- }
- }
-
- /**
- * `true` if the window is minimized to the taskbar, `false` otherwise
- */
- var isMinimized: Boolean
- get() = extendedState and ICONIFIED != 0
- set(value) {
- extendedState = if (value) {
- extendedState or ICONIFIED
- } else {
- extendedState and ICONIFIED.inv()
- }
- }
-
- /**
- * Registers a task to run when the rendering API changes.
- */
- fun onRenderApiChanged(action: () -> Unit) {
- delegate.onRenderApiChanged(action)
- }
-
- /**
- * Retrieve underlying platform-specific operating system handle for the root window where
- * ComposeWindow is rendered. Currently returns HWND on Windows, Display on X11 and NSWindow
- * on macOS.
- */
- val windowHandle: Long get() = delegate.windowHandle
-
- /**
- * Returns low-level rendering API used for rendering in this ComposeWindow. API is
- * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
- * environment variable.
- */
- val renderApi: GraphicsApi get() = delegate.renderApi
-
- // We need overridden listeners because we mix Swing and AWT components in the
- // org.jetbrains.skiko.SkiaLayer, they don't work well together.
- // TODO(demin): is it possible to fix that without overriding?
-
- override fun addMouseListener(listener: MouseListener) =
- delegate.addMouseListener(listener)
-
- override fun removeMouseListener(listener: MouseListener) =
- delegate.removeMouseListener(listener)
-
- override fun addMouseMotionListener(listener: MouseMotionListener) =
- delegate.addMouseMotionListener(listener)
-
- override fun removeMouseMotionListener(listener: MouseMotionListener) =
- delegate.removeMouseMotionListener(listener)
-
- override fun addMouseWheelListener(listener: MouseWheelListener) =
- delegate.addMouseWheelListener(listener)
-
- override fun removeMouseWheelListener(listener: MouseWheelListener) =
- delegate.removeMouseWheelListener(listener)
-}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindowDelegate.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindowDelegate.desktop.kt
deleted file mode 100644
index e888186..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindowDelegate.desktop.kt
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.desktop
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionContext
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.input.key.KeyEvent
-import org.jetbrains.skiko.ClipComponent
-import org.jetbrains.skiko.GraphicsApi
-import org.jetbrains.skiko.SkiaLayer
-import java.awt.Component
-import java.awt.event.MouseListener
-import java.awt.event.MouseMotionListener
-import java.awt.event.MouseWheelListener
-import javax.swing.JLayeredPane
-
-internal class ComposeWindowDelegate {
- private var isDisposed = false
-
- val layer = ComposeLayer()
- val pane = object : JLayeredPane() {
- override fun setBounds(x: Int, y: Int, width: Int, height: Int) {
- layer.wrapped.setSize(width, height)
- super.setBounds(x, y, width, height)
- }
-
- override fun add(component: Component): Component {
- val clipComponent = ClipComponent(component)
- clipMap[component] = clipComponent
- layer.wrapped.clipComponents.add(clipComponent)
- return add(component, Integer.valueOf(0))
- }
-
- override fun remove(component: Component) {
- layer.wrapped.clipComponents.remove(clipMap[component]!!)
- clipMap.remove(component)
- super.remove(component)
- }
-
- override fun getPreferredSize() = layer.wrapped.preferredSize
- }
-
- private val clipMap = mutableMapOf<Component, ClipComponent>()
-
- init {
- pane.layout = null
- pane.add(layer.component, Integer.valueOf(1))
- }
-
- fun add(component: Component): Component {
- return pane.add(component)
- }
-
- fun remove(component: Component) {
- pane.remove(component)
- }
-
- fun setContent(
- parentComposition: CompositionContext? = null,
- onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
- onKeyEvent: (KeyEvent) -> Boolean = { false },
- content: @Composable () -> Unit
- ) {
- layer.setContent(
- parentComposition = parentComposition,
- onPreviewKeyEvent = onPreviewKeyEvent,
- onKeyEvent = onKeyEvent,
- ) {
- CompositionLocalProvider(
- LocalLayerContainer provides pane
- ) {
- content()
- }
- }
- }
-
- fun dispose() {
- if (!isDisposed) {
- layer.dispose()
- isDisposed = true
- }
- }
-
- fun setVisible(value: Boolean) {
- if (value) {
- layer.component.requestFocus()
- }
- }
-
- fun onRenderApiChanged(action: () -> Unit) {
- layer.component.onStateChanged(SkiaLayer.PropertyKind.Renderer) {
- action()
- }
- }
-
- val windowHandle: Long
- get() = layer.component.windowHandle
-
- val renderApi: GraphicsApi
- get() = layer.component.renderApi
-
- fun addMouseListener(listener: MouseListener) {
- layer.component.addMouseListener(listener)
- }
-
- fun removeMouseListener(listener: MouseListener) {
- layer.component.removeMouseListener(listener)
- }
-
- fun addMouseMotionListener(listener: MouseMotionListener) {
- layer.component.addMouseMotionListener(listener)
- }
-
- fun removeMouseMotionListener(listener: MouseMotionListener) {
- layer.component.removeMouseMotionListener(listener)
- }
-
- fun addMouseWheelListener(listener: MouseWheelListener) {
- layer.component.addMouseWheelListener(listener)
- }
-
- fun removeMouseWheelListener(listener: MouseWheelListener) {
- layer.component.removeMouseWheelListener(listener)
- }
-}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/Deprecated.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/Deprecated.desktop.kt
new file mode 100644
index 0000000..1b88351
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/Deprecated.desktop.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.desktop
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.NoOpUpdate
+import androidx.compose.ui.graphics.Color
+import java.awt.Component
+
+@Deprecated(
+ "Use androidx.compose.ui.awt.ComposeWindow",
+ replaceWith = ReplaceWith(
+ "ComposeWindow",
+ "androidx.compose.ui.awt.ComposeWindow"
+ )
+)
+typealias ComposeWindow = androidx.compose.ui.awt.ComposeWindow
+
+@Deprecated(
+ "Use androidx.compose.ui.awt.ComposeDialog",
+ replaceWith = ReplaceWith(
+ "ComposeDialog",
+ "androidx.compose.ui.awt.ComposeDialog"
+ )
+)
+typealias ComposeDialog = androidx.compose.ui.awt.ComposeDialog
+
+@Deprecated(
+ "Use androidx.compose.ui.awt.ComposePanel",
+ replaceWith = ReplaceWith(
+ "ComposePanel",
+ "androidx.compose.ui.awt.ComposePanel"
+ )
+)
+typealias ComposePanel = androidx.compose.ui.awt.ComposePanel
+
+/**
+ * Composes an AWT/Swing component obtained from [factory]. The [factory]
+ * block will be called to obtain the [Component] to be composed. The Swing component is
+ * placed on top of the Compose layer.
+ * The [update] block runs due to recomposition, this is the place to set [Component] properties
+ * depending on state. When state changes, the block will be reexecuted to set the new properties.
+ *
+ * @param background Background color of SwingPanel
+ * @param factory The block creating the [Component] to be composed.
+ * @param modifier The modifier to be applied to the layout.
+ * @param update The callback to be invoked after the layout is inflated.
+ */
+@Composable
+@Deprecated(
+ "Use androidx.compose.ui.awt.SwingPanel",
+ replaceWith = ReplaceWith(
+ "SwingPanel(background, factory, modifier, update)",
+ "androidx.compose.ui.awt.SwingPanel"
+ )
+)
+fun <T : Component> SwingPanel(
+ background: Color = Color.White,
+ factory: () -> T,
+ modifier: Modifier = Modifier,
+ update: (T) -> Unit = NoOpUpdate
+) = androidx.compose.ui.awt.SwingPanel(
+ background, factory, modifier, update
+)
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/SwingPanel.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/SwingPanel.desktop.kt
deleted file mode 100644
index a8780d3..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/SwingPanel.desktop.kt
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.compose.desktop
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.snapshots.SnapshotStateObserver
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.layout.Layout
-import androidx.compose.ui.layout.onGloballyPositioned
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.round
-import java.awt.BorderLayout
-import java.util.concurrent.atomic.AtomicBoolean
-import java.awt.Component
-import java.awt.Container
-import javax.swing.JPanel
-import javax.swing.SwingUtilities
-
-val NoOpUpdate: Component.() -> Unit = {}
-
-/**
- * Composes an AWT/Swing component obtained from [factory]. The [factory]
- * block will be called to obtain the [Component] to be composed. The Swing component is
- * placed on top of the Compose layer.
- * The [update] block runs due to recomposition, this is the place to set [Component] properties
- * depending on state. When state changes, the block will be reexecuted to set the new properties.
- *
- * @param background Background color of SwingPanel
- * @param factory The block creating the [Component] to be composed.
- * @param modifier The modifier to be applied to the layout.
- * @param update The callback to be invoked after the layout is inflated.
- */
-@Composable
-public fun <T : Component> SwingPanel(
- background: Color = Color.White,
- factory: () -> T,
- modifier: Modifier = Modifier,
- update: (T) -> Unit = NoOpUpdate
-) {
- val componentInfo = remember { ComponentInfo<T>() }
-
- val container = LocalLayerContainer.current
- val density = LocalDensity.current.density
-
- Layout(
- content = {},
- modifier = modifier.onGloballyPositioned { childCoordinates ->
- val coordinates = childCoordinates.parentCoordinates!!
- val location = coordinates.localToWindow(Offset.Zero).round()
- val size = coordinates.size
- componentInfo.layout.setBounds(
- (location.x / density).toInt(),
- (location.y / density).toInt(),
- (size.width / density).toInt(),
- (size.height / density).toInt()
- )
- componentInfo.layout.validate()
- componentInfo.layout.repaint()
- },
- measurePolicy = { _, _ ->
- layout(0, 0) {}
- }
- )
-
- DisposableEffect(factory) {
- componentInfo.factory = factory()
- componentInfo.layout = JPanel().apply {
- setLayout(BorderLayout(0, 0))
- add(componentInfo.factory)
- }
- componentInfo.updater = Updater(componentInfo.factory, update)
- container.add(componentInfo.layout)
- onDispose {
- container.remove(componentInfo.layout)
- componentInfo.updater.dispose()
- }
- }
-
- SideEffect {
- componentInfo.layout.setBackground(parseColor(background))
- componentInfo.updater.update = update
- }
-}
-
-private fun parseColor(color: Color): java.awt.Color {
- return java.awt.Color(
- color.component1(),
- color.component2(),
- color.component3(),
- color.component4()
- )
-}
-
-private class ComponentInfo<T : Component> {
- lateinit var layout: Container
- lateinit var factory: T
- lateinit var updater: Updater<T>
-}
-
-private class Updater<T : Component>(
- private val component: T,
- update: (T) -> Unit
-) {
- private var isDisposed = false
- private val isUpdateScheduled = AtomicBoolean()
- private val snapshotObserver = SnapshotStateObserver { command ->
- command()
- }
-
- private val scheduleUpdate = { _: T ->
- if (!isUpdateScheduled.getAndSet(true)) {
- SwingUtilities.invokeLater {
- isUpdateScheduled.set(false)
- if (!isDisposed) {
- performUpdate()
- }
- }
- }
- }
-
- var update: (T) -> Unit = update
- set(value) {
- if (field != value) {
- field = value
- performUpdate()
- }
- }
-
- private fun performUpdate() {
- // don't replace scheduleUpdate by lambda reference,
- // scheduleUpdate should always be the same instance
- snapshotObserver.observeReads(component, scheduleUpdate) {
- update(component)
- }
- }
-
- init {
- snapshotObserver.start()
- performUpdate()
- }
-
- fun dispose() {
- snapshotObserver.stop()
- snapshotObserver.clear()
- isDisposed = true
- }
-}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/AWTDebounceEventQueue.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/AWTDebounceEventQueue.desktop.kt
new file mode 100644
index 0000000..0016be5
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/AWTDebounceEventQueue.desktop.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.awt
+
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.swing.Swing
+import kotlinx.coroutines.yield
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * Dispatch events on the next EDT tick if they are blocking EDT too long,
+ * so EDT can handle more important actions (like render a new frame).
+ *
+ * (EDT - AWT event dispatch thread)
+ *
+ * [maxNanosToBlockThread] defines how long events can block EDT.
+ *
+ * It is needed in a case when we have a lot of heavy events (like mouse scroll)
+ * in a short period of time.
+ *
+ * Without dispatching events we may have a situation
+ * when 30 events of scroll block AWT Thread for 1 second, without rerendering content.
+ */
+@OptIn(DelicateCoroutinesApi::class)
+internal class AWTDebounceEventQueue constructor(
+ // 4 ms is enough for the user not to see the lags
+ private val maxNanosToBlockThread: Long = 4_000_000, // 4 milliseconds
+ private val nanoTime: () -> Long = System::nanoTime,
+ context: CoroutineContext = Dispatchers.Swing
+) {
+ private val queue = Channel<() -> Unit>(Channel.UNLIMITED)
+
+ private var job = GlobalScope.launch(context) {
+ var lastTime = nanoTime()
+ for (event in queue) {
+ val time = nanoTime()
+ if (time - lastTime >= maxNanosToBlockThread) {
+ lastTime = time
+ yield()
+ }
+ event()
+ }
+ }
+
+ fun cancel() {
+ job.cancel()
+ }
+
+ fun post(event: () -> Unit) {
+ queue.trySend(event)
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeDialog.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeDialog.desktop.kt
new file mode 100644
index 0000000..6f6d33f
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeDialog.desktop.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.compose.ui.awt
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionContext
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.window.DialogWindowScope
+import androidx.compose.ui.window.UndecoratedWindowResizer
+import org.jetbrains.skiko.GraphicsApi
+import java.awt.Component
+import java.awt.Window
+import java.awt.event.MouseListener
+import java.awt.event.MouseMotionListener
+import java.awt.event.MouseWheelListener
+import javax.swing.JDialog
+
+/**
+ * ComposeDialog is a dialog for building UI using Compose for Desktop.
+ * ComposeDialog inherits javax.swing.JDialog.
+ */
+class ComposeDialog(
+ owner: Window? = null,
+ modalityType: ModalityType = ModalityType.MODELESS
+) : JDialog(owner, modalityType) {
+ private val delegate = ComposeWindowDelegate(this)
+ internal val layer get() = delegate.layer
+
+ init {
+ contentPane.add(delegate.pane)
+ }
+
+ override fun add(component: Component) = delegate.add(component)
+
+ override fun remove(component: Component) = delegate.remove(component)
+
+ /**
+ * Composes the given composable into the ComposeDialog.
+ *
+ * The new composition can be logically "linked" to an existing one, by providing a
+ * [parentComposition]. This will ensure that invalidations and CompositionLocals will flow
+ * through the two compositions as if they were not separate.
+ *
+ * @param parentComposition The parent composition reference to coordinate
+ * scheduling of composition updates.
+ * If null then default root composition will be used.
+ * @param onPreviewKeyEvent This callback is invoked when the user interacts with the hardware
+ * keyboard. It gives ancestors of a focused component the chance to intercept a [KeyEvent].
+ * Return true to stop propagation of this event. If you return false, the key event will be
+ * sent to this [onPreviewKeyEvent]'s child. If none of the children consume the event,
+ * it will be sent back up to the root using the onKeyEvent callback.
+ * @param onKeyEvent This callback is invoked when the user interacts with the hardware
+ * keyboard. While implementing this callback, return true to stop propagation of this event.
+ * If you return false, the key event will be sent to this [onKeyEvent]'s parent.
+ * @param content Composable content of the ComposeWindow.
+ */
+ fun setContent(
+ parentComposition: CompositionContext? = null,
+ onPreviewKeyEvent: ((KeyEvent) -> Boolean) = { false },
+ onKeyEvent: ((KeyEvent) -> Boolean) = { false },
+ content: @Composable DialogWindowScope.() -> Unit
+ ) {
+ val scope = object : DialogWindowScope {
+ override val window: ComposeDialog get() = this@ComposeDialog
+ }
+ delegate.setContent(
+ parentComposition,
+ onPreviewKeyEvent,
+ onKeyEvent,
+ ) {
+ scope.content()
+ }
+ }
+
+ override fun dispose() {
+ delegate.dispose()
+ super.dispose()
+ }
+
+ private val undecoratedWindowResizer = UndecoratedWindowResizer(this, layer)
+
+ override fun setUndecorated(value: Boolean) {
+ super.setUndecorated(value)
+ undecoratedWindowResizer.enabled = isUndecorated && isResizable
+ }
+
+ override fun setResizable(value: Boolean) {
+ super.setResizable(value)
+ undecoratedWindowResizer.enabled = isUndecorated && isResizable
+ }
+
+ /**
+ * Registers a task to run when the rendering API changes.
+ */
+ fun onRenderApiChanged(action: () -> Unit) {
+ delegate.onRenderApiChanged(action)
+ }
+
+ /**
+ * Retrieve underlying platform-specific operating system handle for the root window where
+ * ComposeDialog is rendered. Currently returns HWND on Windows, Display on X11 and NSWindow
+ * on macOS.
+ */
+ val windowHandle: Long get() = delegate.windowHandle
+
+ /**
+ * Returns low-level rendering API used for rendering in this ComposeDialog. API is
+ * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
+ * environment variable.
+ */
+ val renderApi: GraphicsApi get() = delegate.renderApi
+
+ // We need overridden listeners because we mix Swing and AWT components in the
+ // org.jetbrains.skiko.SkiaLayer, they don't work well together.
+ // TODO(demin): is it possible to fix that without overriding?
+
+ override fun addMouseListener(listener: MouseListener) =
+ delegate.addMouseListener(listener)
+
+ override fun removeMouseListener(listener: MouseListener) =
+ delegate.removeMouseListener(listener)
+
+ override fun addMouseMotionListener(listener: MouseMotionListener) =
+ delegate.addMouseMotionListener(listener)
+
+ override fun removeMouseMotionListener(listener: MouseMotionListener) =
+ delegate.removeMouseMotionListener(listener)
+
+ override fun addMouseWheelListener(listener: MouseWheelListener) =
+ delegate.addMouseWheelListener(listener)
+
+ override fun removeMouseWheelListener(listener: MouseWheelListener) =
+ delegate.removeMouseWheelListener(listener)
+}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
new file mode 100644
index 0000000..28cdaf8
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.awt
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Composition
+import androidx.compose.runtime.CompositionContext
+import androidx.compose.ui.input.mouse.MouseScrollEvent
+import androidx.compose.ui.input.mouse.MouseScrollOrientation
+import androidx.compose.ui.input.mouse.MouseScrollUnit
+import androidx.compose.ui.platform.DesktopComponent
+import androidx.compose.ui.platform.DesktopOwner
+import androidx.compose.ui.platform.DesktopOwners
+import androidx.compose.ui.platform.setContent
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.window.density
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.swing.Swing
+import org.jetbrains.skija.Canvas
+import org.jetbrains.skiko.SkiaLayer
+import org.jetbrains.skiko.SkiaRenderer
+import java.awt.Dimension
+import java.awt.Point
+import java.awt.event.FocusEvent
+import java.awt.event.InputMethodEvent
+import java.awt.event.InputMethodListener
+import java.awt.event.KeyAdapter
+import java.awt.event.KeyEvent
+import java.awt.event.MouseAdapter
+import java.awt.event.MouseEvent
+import java.awt.event.MouseMotionAdapter
+import java.awt.event.MouseWheelEvent
+import java.awt.im.InputMethodRequests
+import androidx.compose.ui.input.key.KeyEvent as ComposeKeyEvent
+
+internal class ComposeLayer {
+ private var isDisposed = false
+
+ private val coroutineScope = CoroutineScope(Dispatchers.Swing)
+ // TODO(demin): probably we need to get rid of asynchronous events. it was added because of
+ // slow lazy scroll. But events become unpredictable, and we can't consume them.
+ // Alternative solution to a slow scroll - merge multiple scroll events into a single one.
+ private val events = AWTDebounceEventQueue()
+
+ internal val wrapped = Wrapped().apply {
+ onStateChanged(SkiaLayer.PropertyKind.ContentScale) { _ ->
+ resetDensity()
+ }
+ }
+
+ internal val owners: DesktopOwners = DesktopOwners(
+ coroutineScope,
+ wrapped,
+ wrapped::needRedraw
+ )
+
+ private var owner: DesktopOwner? = null
+ private var composition: Composition? = null
+
+ private var initOwner: (() -> Unit)? = null
+
+ private lateinit var density: Density
+
+ inner class Wrapped : SkiaLayer(), DesktopComponent {
+ var currentInputMethodRequests: InputMethodRequests? = null
+
+ var isInit = false
+ private set
+
+ override fun init() {
+ super.init()
+ isInit = true
+ resetDensity()
+ initOwner?.invoke()
+ }
+
+ internal fun resetDensity() {
+ this@ComposeLayer.density = (this as SkiaLayer).density
+ owner?.density = density
+ }
+
+ override fun getInputMethodRequests() = currentInputMethodRequests
+
+ override fun enableInput(inputMethodRequests: InputMethodRequests) {
+ currentInputMethodRequests = inputMethodRequests
+ enableInputMethods(true)
+ val focusGainedEvent = FocusEvent(this, FocusEvent.FOCUS_GAINED)
+ inputContext.dispatchEvent(focusGainedEvent)
+ }
+
+ override fun disableInput() {
+ currentInputMethodRequests = null
+ }
+
+ override fun doLayout() {
+ super.doLayout()
+ val owner = owner
+ if (owner != null) {
+ val density = density.density
+ owner.setSize(
+ (width * density).toInt().coerceAtLeast(0),
+ (height * density).toInt().coerceAtLeast(0)
+ )
+ owner.measureAndLayout()
+ preferredSize = Dimension(
+ (owner.root.width / density).toInt(),
+ (owner.root.height / density).toInt()
+ )
+ }
+ }
+
+ override val locationOnScreen: Point
+ @Suppress("ACCIDENTAL_OVERRIDE") // KT-47743
+ get() = super.getLocationOnScreen()
+
+ override val density: Density
+ get() = this@ComposeLayer.density
+ }
+
+ val component: SkiaLayer
+ get() = wrapped
+
+ init {
+ wrapped.renderer = object : SkiaRenderer {
+ override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
+ try {
+ owners.onFrame(canvas, width, height, nanoTime)
+ } catch (e: Throwable) {
+ if (System.getProperty("compose.desktop.render.ignore.errors") == null) {
+ throw e
+ }
+ }
+ }
+ }
+ initCanvas()
+ }
+
+ private fun initCanvas() {
+ wrapped.addInputMethodListener(object : InputMethodListener {
+ override fun caretPositionChanged(event: InputMethodEvent?) {
+ if (event != null) {
+ owners.onInputMethodEvent(event)
+ }
+ }
+
+ override fun inputMethodTextChanged(event: InputMethodEvent) = events.post {
+ owners.onInputMethodEvent(event)
+ }
+ })
+
+ wrapped.addMouseListener(object : MouseAdapter() {
+ override fun mouseClicked(event: MouseEvent) = Unit
+
+ override fun mousePressed(event: MouseEvent) = events.post {
+ owners.onMousePressed(
+ (event.x * density.density).toInt(),
+ (event.y * density.density).toInt(),
+ event
+ )
+ }
+
+ override fun mouseReleased(event: MouseEvent) = events.post {
+ owners.onMouseReleased(
+ (event.x * density.density).toInt(),
+ (event.y * density.density).toInt(),
+ event
+ )
+ }
+
+ override fun mouseEntered(event: MouseEvent) = events.post {
+ owners.onMouseEntered(
+ (event.x * density.density).toInt(),
+ (event.y * density.density).toInt()
+ )
+ }
+
+ override fun mouseExited(event: MouseEvent) = events.post {
+ owners.onMouseExited()
+ }
+ })
+ wrapped.addMouseMotionListener(object : MouseMotionAdapter() {
+ override fun mouseDragged(event: MouseEvent) = events.post {
+ owners.onMouseMoved(
+ (event.x * density.density).toInt(),
+ (event.y * density.density).toInt(),
+ event
+ )
+ }
+
+ override fun mouseMoved(event: MouseEvent) = events.post {
+ owners.onMouseMoved(
+ (event.x * density.density).toInt(),
+ (event.y * density.density).toInt(),
+ event
+ )
+ }
+ })
+ wrapped.addMouseWheelListener { event ->
+ events.post {
+ owners.onMouseScroll(
+ (event.x * density.density).toInt(),
+ (event.y * density.density).toInt(),
+ event.toComposeEvent()
+ )
+ }
+ }
+ wrapped.focusTraversalKeysEnabled = false
+ wrapped.addKeyListener(object : KeyAdapter() {
+ override fun keyPressed(event: KeyEvent) {
+ if (owners.onKeyPressed(event)) {
+ event.consume()
+ }
+ }
+
+ override fun keyReleased(event: KeyEvent) {
+ if (owners.onKeyReleased(event)) {
+ event.consume()
+ }
+ }
+
+ override fun keyTyped(event: KeyEvent) {
+ if (owners.onKeyTyped(event)) {
+ event.consume()
+ }
+ }
+ })
+ }
+
+ private fun MouseWheelEvent.toComposeEvent() = MouseScrollEvent(
+ delta = if (scrollType == MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
+ MouseScrollUnit.Page((scrollAmount * preciseWheelRotation).toFloat())
+ } else {
+ MouseScrollUnit.Line((scrollAmount * preciseWheelRotation).toFloat())
+ },
+
+ // There are no other way to detect horizontal scrolling in AWT
+ orientation = if (isShiftDown) {
+ MouseScrollOrientation.Horizontal
+ } else {
+ MouseScrollOrientation.Vertical
+ }
+ )
+
+ fun dispose() {
+ check(!isDisposed)
+ composition?.dispose()
+ owner?.dispose()
+ events.cancel()
+ coroutineScope.cancel()
+ wrapped.dispose()
+ initOwner = null
+ isDisposed = true
+ }
+
+ internal fun setContent(
+ parentComposition: CompositionContext? = null,
+ onPreviewKeyEvent: (ComposeKeyEvent) -> Boolean = { false },
+ onKeyEvent: (ComposeKeyEvent) -> Boolean = { false },
+ content: @Composable () -> Unit
+ ) {
+ check(!isDisposed)
+ check(composition == null && initOwner == null) { "Cannot set content twice" }
+ initOwner = {
+ check(!isDisposed)
+ if (wrapped.isInit && owner == null) {
+ owner = DesktopOwner(
+ owners,
+ density,
+ onPreviewKeyEvent = onPreviewKeyEvent,
+ onKeyEvent = onKeyEvent
+ )
+ composition = owner!!.setContent(parent = parentComposition, content = content)
+ initOwner = null
+ }
+ }
+ // We can't create DesktopOwner now, because we don't know density yet.
+ // We will know density only after SkiaLayer will be visible.
+ initOwner!!()
+ }
+}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposePanel.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposePanel.desktop.kt
new file mode 100644
index 0000000..cf49721
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposePanel.desktop.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.compose.ui.awt
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import org.jetbrains.skiko.ClipComponent
+import org.jetbrains.skiko.GraphicsApi
+import java.awt.Color
+import java.awt.Component
+import javax.swing.JLayeredPane
+import javax.swing.SwingUtilities.isEventDispatchThread
+
+/**
+ * ComposePanel is a panel for building UI using Compose for Desktop.
+ */
+class ComposePanel : JLayeredPane() {
+ init {
+ check(isEventDispatchThread()) {
+ "ComposePanel should be created inside AWT Event Dispatch Thread" +
+ " (use SwingUtilities.invokeLater).\n" +
+ "Creating from another thread isn't supported."
+ }
+ setBackground(Color.white)
+ setLayout(null)
+ }
+
+ internal var layer: ComposeLayer? = null
+ private val clipMap = mutableMapOf<Component, ClipComponent>()
+ private var content: (@Composable () -> Unit)? = null
+
+ override fun setBounds(x: Int, y: Int, width: Int, height: Int) {
+ layer?.wrapped?.setSize(width, height)
+ super.setBounds(x, y, width, height)
+ }
+
+ override fun getPreferredSize() = layer?.wrapped?.preferredSize
+
+ /**
+ * Sets Compose content of the ComposePanel.
+ *
+ * @param content Composable content of the ComposePanel.
+ */
+ fun setContent(content: @Composable () -> Unit) {
+ // The window (or root container) may not be ready to render composable content, so we need
+ // to keep the lambda describing composable content and set the content only when
+ // everything is ready to avoid accidental crashes and memory leaks on all supported OS
+ // types.
+ this.content = content
+ initContent()
+ }
+
+ private fun initContent() {
+ if (layer != null && content != null) {
+ layer!!.setContent {
+ CompositionLocalProvider(
+ LocalLayerContainer provides this,
+ content = content!!
+ )
+ }
+ }
+ }
+
+ override fun add(component: Component): Component {
+ if (layer == null) {
+ return component
+ }
+ val clipComponent = ClipComponent(component)
+ clipMap.put(component, clipComponent)
+ layer!!.wrapped.clipComponents.add(clipComponent)
+ return super.add(component, Integer.valueOf(0))
+ }
+
+ override fun remove(component: Component) {
+ layer!!.wrapped.clipComponents.remove(clipMap.get(component)!!)
+ clipMap.remove(component)
+ super.remove(component)
+ }
+
+ override fun addNotify() {
+ super.addNotify()
+
+ // After [super.addNotify] is called we can safely initialize the layer and composable
+ // content.
+ layer = ComposeLayer().apply {
+ wrapped.setSize(width, height)
+ }
+ initContent()
+ super.add(layer!!.component, Integer.valueOf(1))
+ }
+
+ override fun removeNotify() {
+ if (layer != null) {
+ layer!!.dispose()
+ super.remove(layer!!.component)
+ }
+
+ super.removeNotify()
+ }
+
+ override fun requestFocus() {
+ if (layer != null) {
+ layer!!.component.requestFocus()
+ }
+ }
+
+ /**
+ * Returns low-level rendering API used for rendering in this ComposeWindow. API is
+ * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
+ * environment variable.
+ */
+ val renderApi: GraphicsApi
+ get() = if (layer != null) layer!!.component.renderApi else GraphicsApi.UNKNOWN
+}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeWindow.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeWindow.desktop.kt
new file mode 100644
index 0000000..9ba240f
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeWindow.desktop.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.compose.ui.awt
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionContext
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.window.FrameWindowScope
+import androidx.compose.ui.window.UndecoratedWindowResizer
+import androidx.compose.ui.window.WindowPlacement
+import org.jetbrains.skiko.GraphicsApi
+import java.awt.Component
+import java.awt.event.MouseListener
+import java.awt.event.MouseMotionListener
+import java.awt.event.MouseWheelListener
+import javax.swing.JFrame
+
+/**
+ * ComposeWindow is a window for building UI using Compose for Desktop.
+ * ComposeWindow inherits javax.swing.JFrame.
+ */
+class ComposeWindow : JFrame() {
+ private val delegate = ComposeWindowDelegate(this)
+ internal val layer get() = delegate.layer
+
+ init {
+ contentPane.add(delegate.pane)
+ }
+
+ override fun add(component: Component) = delegate.add(component)
+
+ override fun remove(component: Component) = delegate.remove(component)
+
+ /**
+ * Composes the given composable into the ComposeWindow.
+ *
+ * The new composition can be logically "linked" to an existing one, by providing a
+ * [parentComposition]. This will ensure that invalidations and CompositionLocals will flow
+ * through the two compositions as if they were not separate.
+ *
+ * @param parentComposition The parent composition reference to coordinate
+ * scheduling of composition updates.
+ * If null then default root composition will be used.
+ * @param onPreviewKeyEvent This callback is invoked when the user interacts with the hardware
+ * keyboard. It gives ancestors of a focused component the chance to intercept a [KeyEvent].
+ * Return true to stop propagation of this event. If you return false, the key event will be
+ * sent to this [onPreviewKeyEvent]'s child. If none of the children consume the event,
+ * it will be sent back up to the root using the onKeyEvent callback.
+ * @param onKeyEvent This callback is invoked when the user interacts with the hardware
+ * keyboard. While implementing this callback, return true to stop propagation of this event.
+ * If you return false, the key event will be sent to this [onKeyEvent]'s parent.
+ * @param content Composable content of the ComposeWindow.
+ */
+ fun setContent(
+ parentComposition: CompositionContext? = null,
+ onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
+ onKeyEvent: (KeyEvent) -> Boolean = { false },
+ content: @Composable FrameWindowScope.() -> Unit
+ ) {
+ val scope = object : FrameWindowScope {
+ override val window: ComposeWindow get() = this@ComposeWindow
+ }
+ delegate.setContent(
+ parentComposition,
+ onPreviewKeyEvent,
+ onKeyEvent
+ ) {
+ scope.content()
+ }
+ }
+
+ override fun dispose() {
+ delegate.dispose()
+ super.dispose()
+ }
+
+ private val undecoratedWindowResizer = UndecoratedWindowResizer(this, layer)
+
+ override fun setUndecorated(value: Boolean) {
+ super.setUndecorated(value)
+ undecoratedWindowResizer.enabled = isUndecorated && isResizable
+ }
+
+ override fun setResizable(value: Boolean) {
+ super.setResizable(value)
+ undecoratedWindowResizer.enabled = isUndecorated && isResizable
+ }
+
+ var placement: WindowPlacement
+ get() = when {
+ isFullscreen -> WindowPlacement.Fullscreen
+ isMaximized -> WindowPlacement.Maximized
+ else -> WindowPlacement.Floating
+ }
+ set(value) {
+ when (value) {
+ WindowPlacement.Fullscreen -> {
+ isFullscreen = true
+ }
+ WindowPlacement.Maximized -> {
+ isMaximized = true
+ }
+ WindowPlacement.Floating -> {
+ isFullscreen = false
+ isMaximized = false
+ }
+ }
+ }
+
+ /**
+ * `true` if the window is in fullscreen mode, `false` otherwise
+ */
+ private var isFullscreen: Boolean
+ get() = layer.component.fullscreen
+ set(value) {
+ layer.component.fullscreen = value
+ }
+
+ /**
+ * `true` if the window is maximized to fill all available screen space, `false` otherwise
+ */
+ private var isMaximized: Boolean
+ get() = extendedState and MAXIMIZED_BOTH != 0
+ set(value) {
+ extendedState = if (value) {
+ extendedState or MAXIMIZED_BOTH
+ } else {
+ extendedState and MAXIMIZED_BOTH.inv()
+ }
+ }
+
+ /**
+ * `true` if the window is minimized to the taskbar, `false` otherwise
+ */
+ var isMinimized: Boolean
+ get() = extendedState and ICONIFIED != 0
+ set(value) {
+ extendedState = if (value) {
+ extendedState or ICONIFIED
+ } else {
+ extendedState and ICONIFIED.inv()
+ }
+ }
+
+ /**
+ * Registers a task to run when the rendering API changes.
+ */
+ fun onRenderApiChanged(action: () -> Unit) {
+ delegate.onRenderApiChanged(action)
+ }
+
+ /**
+ * Retrieve underlying platform-specific operating system handle for the root window where
+ * ComposeWindow is rendered. Currently returns HWND on Windows, Display on X11 and NSWindow
+ * on macOS.
+ */
+ val windowHandle: Long get() = delegate.windowHandle
+
+ /**
+ * Returns low-level rendering API used for rendering in this ComposeWindow. API is
+ * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
+ * environment variable.
+ */
+ val renderApi: GraphicsApi get() = delegate.renderApi
+
+ // We need overridden listeners because we mix Swing and AWT components in the
+ // org.jetbrains.skiko.SkiaLayer, they don't work well together.
+ // TODO(demin): is it possible to fix that without overriding?
+
+ override fun addMouseListener(listener: MouseListener) =
+ delegate.addMouseListener(listener)
+
+ override fun removeMouseListener(listener: MouseListener) =
+ delegate.removeMouseListener(listener)
+
+ override fun addMouseMotionListener(listener: MouseMotionListener) =
+ delegate.addMouseMotionListener(listener)
+
+ override fun removeMouseMotionListener(listener: MouseMotionListener) =
+ delegate.removeMouseMotionListener(listener)
+
+ override fun addMouseWheelListener(listener: MouseWheelListener) =
+ delegate.addMouseWheelListener(listener)
+
+ override fun removeMouseWheelListener(listener: MouseWheelListener) =
+ delegate.removeMouseWheelListener(listener)
+}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeWindowDelegate.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeWindowDelegate.desktop.kt
new file mode 100644
index 0000000..ce63cab
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeWindowDelegate.desktop.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.awt
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionContext
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.window.LocalWindow
+import org.jetbrains.skiko.ClipComponent
+import org.jetbrains.skiko.GraphicsApi
+import org.jetbrains.skiko.SkiaLayer
+import java.awt.Component
+import java.awt.Window
+import java.awt.event.MouseListener
+import java.awt.event.MouseMotionListener
+import java.awt.event.MouseWheelListener
+import javax.swing.JLayeredPane
+
+internal class ComposeWindowDelegate(private val window: Window) {
+ private var isDisposed = false
+
+ val layer = ComposeLayer()
+ val pane = object : JLayeredPane() {
+ override fun setBounds(x: Int, y: Int, width: Int, height: Int) {
+ layer.wrapped.setSize(width, height)
+ super.setBounds(x, y, width, height)
+ }
+
+ override fun add(component: Component): Component {
+ val clipComponent = ClipComponent(component)
+ clipMap[component] = clipComponent
+ layer.wrapped.clipComponents.add(clipComponent)
+ return add(component, Integer.valueOf(0))
+ }
+
+ override fun remove(component: Component) {
+ layer.wrapped.clipComponents.remove(clipMap[component]!!)
+ clipMap.remove(component)
+ super.remove(component)
+ }
+
+ override fun addNotify() {
+ super.addNotify()
+ layer.wrapped.requestFocus()
+ }
+
+ override fun getPreferredSize() = layer.wrapped.preferredSize
+ }
+
+ private val clipMap = mutableMapOf<Component, ClipComponent>()
+
+ init {
+ pane.layout = null
+ pane.add(layer.component, Integer.valueOf(1))
+ }
+
+ fun add(component: Component): Component {
+ return pane.add(component)
+ }
+
+ fun remove(component: Component) {
+ pane.remove(component)
+ }
+
+ fun setContent(
+ parentComposition: CompositionContext? = null,
+ onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
+ onKeyEvent: (KeyEvent) -> Boolean = { false },
+ content: @Composable () -> Unit
+ ) {
+ layer.setContent(
+ parentComposition = parentComposition,
+ onPreviewKeyEvent = onPreviewKeyEvent,
+ onKeyEvent = onKeyEvent,
+ ) {
+ CompositionLocalProvider(
+ LocalWindow provides window,
+ LocalLayerContainer provides pane
+ ) {
+ content()
+ }
+ }
+ }
+
+ fun dispose() {
+ if (!isDisposed) {
+ layer.dispose()
+ isDisposed = true
+ }
+ }
+
+ fun onRenderApiChanged(action: () -> Unit) {
+ layer.component.onStateChanged(SkiaLayer.PropertyKind.Renderer) {
+ action()
+ }
+ }
+
+ val windowHandle: Long
+ get() = layer.component.windowHandle
+
+ val renderApi: GraphicsApi
+ get() = layer.component.renderApi
+
+ fun addMouseListener(listener: MouseListener) {
+ layer.component.addMouseListener(listener)
+ }
+
+ fun removeMouseListener(listener: MouseListener) {
+ layer.component.removeMouseListener(listener)
+ }
+
+ fun addMouseMotionListener(listener: MouseMotionListener) {
+ layer.component.addMouseMotionListener(listener)
+ }
+
+ fun removeMouseMotionListener(listener: MouseMotionListener) {
+ layer.component.removeMouseMotionListener(listener)
+ }
+
+ fun addMouseWheelListener(listener: MouseWheelListener) {
+ layer.component.addMouseWheelListener(listener)
+ }
+
+ fun removeMouseWheelListener(listener: MouseWheelListener) {
+ layer.component.removeMouseWheelListener(listener)
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/LocalLayerContainer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/LocalLayerContainer.desktop.kt
new file mode 100644
index 0000000..7999d4f
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/LocalLayerContainer.desktop.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.awt
+
+import androidx.compose.runtime.compositionLocalOf
+import java.awt.Container
+
+internal val LocalLayerContainer = compositionLocalOf<Container> {
+ error("CompositionLocal LayerContainer not provided")
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/SwingPanel.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/SwingPanel.desktop.kt
new file mode 100644
index 0000000..664605f
--- /dev/null
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/SwingPanel.desktop.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.compose.ui.awt
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshots.SnapshotStateObserver
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.round
+import java.awt.BorderLayout
+import java.awt.Component
+import java.awt.Container
+import java.util.concurrent.atomic.AtomicBoolean
+import javax.swing.JPanel
+import javax.swing.SwingUtilities
+
+val NoOpUpdate: Component.() -> Unit = {}
+
+/**
+ * Composes an AWT/Swing component obtained from [factory]. The [factory]
+ * block will be called to obtain the [Component] to be composed. The Swing component is
+ * placed on top of the Compose layer.
+ * The [update] block runs due to recomposition, this is the place to set [Component] properties
+ * depending on state. When state changes, the block will be reexecuted to set the new properties.
+ *
+ * @param background Background color of SwingPanel
+ * @param factory The block creating the [Component] to be composed.
+ * @param modifier The modifier to be applied to the layout.
+ * @param update The callback to be invoked after the layout is inflated.
+ */
+@Composable
+public fun <T : Component> SwingPanel(
+ background: Color = Color.White,
+ factory: () -> T,
+ modifier: Modifier = Modifier,
+ update: (T) -> Unit = NoOpUpdate
+) {
+ val componentInfo = remember { ComponentInfo<T>() }
+
+ val container = LocalLayerContainer.current
+ val density = LocalDensity.current.density
+
+ Layout(
+ content = {},
+ modifier = modifier.onGloballyPositioned { childCoordinates ->
+ val coordinates = childCoordinates.parentCoordinates!!
+ val location = coordinates.localToWindow(Offset.Zero).round()
+ val size = coordinates.size
+ componentInfo.layout.setBounds(
+ (location.x / density).toInt(),
+ (location.y / density).toInt(),
+ (size.width / density).toInt(),
+ (size.height / density).toInt()
+ )
+ componentInfo.layout.validate()
+ componentInfo.layout.repaint()
+ },
+ measurePolicy = { _, _ ->
+ layout(0, 0) {}
+ }
+ )
+
+ DisposableEffect(factory) {
+ componentInfo.factory = factory()
+ componentInfo.layout = JPanel().apply {
+ setLayout(BorderLayout(0, 0))
+ add(componentInfo.factory)
+ }
+ componentInfo.updater = Updater(componentInfo.factory, update)
+ container.add(componentInfo.layout)
+ onDispose {
+ container.remove(componentInfo.layout)
+ componentInfo.updater.dispose()
+ }
+ }
+
+ SideEffect {
+ componentInfo.layout.setBackground(parseColor(background))
+ componentInfo.updater.update = update
+ }
+}
+
+private fun parseColor(color: Color): java.awt.Color {
+ return java.awt.Color(
+ color.component1(),
+ color.component2(),
+ color.component3(),
+ color.component4()
+ )
+}
+
+private class ComponentInfo<T : Component> {
+ lateinit var layout: Container
+ lateinit var factory: T
+ lateinit var updater: Updater<T>
+}
+
+private class Updater<T : Component>(
+ private val component: T,
+ update: (T) -> Unit
+) {
+ private var isDisposed = false
+ private val isUpdateScheduled = AtomicBoolean()
+ private val snapshotObserver = SnapshotStateObserver { command ->
+ command()
+ }
+
+ private val scheduleUpdate = { _: T ->
+ if (!isUpdateScheduled.getAndSet(true)) {
+ SwingUtilities.invokeLater {
+ isUpdateScheduled.set(false)
+ if (!isDisposed) {
+ performUpdate()
+ }
+ }
+ }
+ }
+
+ var update: (T) -> Unit = update
+ set(value) {
+ if (field != value) {
+ field = value
+ performUpdate()
+ }
+ }
+
+ private fun performUpdate() {
+ // don't replace scheduleUpdate by lambda reference,
+ // scheduleUpdate should always be the same instance
+ snapshotObserver.observeReads(component, scheduleUpdate) {
+ update(component)
+ }
+ }
+
+ init {
+ snapshotObserver.start()
+ performUpdate()
+ }
+
+ fun dispose() {
+ snapshotObserver.stop()
+ snapshotObserver.clear()
+ isDisposed = true
+ }
+}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/key/ShortcutsModifier.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/key/ShortcutsModifier.desktop.kt
deleted file mode 100644
index 5f69dc6..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/key/ShortcutsModifier.desktop.kt
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.input.key
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
-import java.util.TreeMap
-
-/**
- * Defines a set of keys. Can be used in keys handlers, see
- * [androidx.compose.ui.platform.Keyboard] and [Modifier.shortcuts]
- */
-class KeysSet(internal val keys: Set<Key>) : Comparable<KeysSet> {
- /**
- * Returns a new [KeysSet] consists of current keys set + additional key
- *
- * @param key: additional key
- */
- operator fun plus(key: Key): KeysSet {
- return KeysSet(keys + key)
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as KeysSet
-
- if (keys != other.keys) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- return keys.hashCode()
- }
-
- override fun toString(): String {
- return "KeysSet(keys=$keys)"
- }
-
- override fun compareTo(other: KeysSet): Int {
- return when {
- other.keys == keys -> 0
- other.keys.size < keys.size -> 1
- else -> -1
- }
- }
-}
-
-/**
- * Converts two keys into [KeysSet]
- */
-operator fun Key.plus(other: Key): KeysSet {
- return KeysSet(setOf(this, other))
-}
-
-/**
- * [KeysSet] constructor for single-key sets
- */
-fun KeysSet(key: Key): KeysSet {
- return KeysSet(setOf(key))
-}
-
-private fun makeHandlers() = TreeMap<KeysSet, () -> Unit>()
-
-internal class ShortcutsInstance(
- internal var handlers: TreeMap<KeysSet, () -> Unit> = makeHandlers()
-) {
- private var pressedKeys = mutableSetOf<Key>()
-
- fun process(event: KeyEvent): Boolean {
- if (event.type == KeyEventType.Unknown) {
- return false
- }
- syncPressedKeys(event)
- return findHandler()?.let {
- it()
- true
- } ?: false
- }
-
- internal fun setHandler(keysSet: KeysSet, handler: () -> Unit) {
- handlers[keysSet] = handler
- }
-
- internal fun removeHandler(keysSet: KeysSet) {
- handlers.remove(keysSet)
- }
-
- private fun syncPressedKeys(event: KeyEvent) {
- when (event.type) {
- KeyEventType.KeyDown -> {
- pressedKeys.add(event.key)
- }
- KeyEventType.KeyUp -> {
- pressedKeys.remove(event.key)
- }
- else -> {}
- }
- }
-
- private fun findHandler(): (() -> Unit)? {
- handlers.descendingMap().forEach { (keysSet, handler) ->
- if (pressedKeys.containsAll(keysSet.keys)) {
- return handler
- }
- }
- return null
- }
-}
-
-/**
- * [KeyEvent] handler which tracks pressed keys and triggers matched callbacks
- *
- * @see [onKeyEvent]
- * @see [androidx.compose.ui.platform.Keyboard] to define window-scoped shortcuts
- */
-@Composable
-fun Modifier.shortcuts(builder: (ShortcutsBuilderScope).() -> Unit) = composed {
- val instance = remember { ShortcutsInstance() }
- instance.handlers = ShortcutsBuilderScope().also(builder).handlers
- onKeyEvent(instance::process)
-}
-
-class ShortcutsBuilderScope {
- internal val handlers = makeHandlers()
- /**
- * @param keysSet: represents a set of keys that can be simultaneously pressed
- * @param callback: called when all keys in [keysSet] are pressed
- */
- fun on(keysSet: KeysSet, callback: () -> Unit) {
- handlers[keysSet] = callback
- }
-
- /**
- * @param key: [Key] instance
- * @param callback: called when [key] is pressed
- */
- fun on(key: Key, callback: () -> Unit) {
- handlers[KeysSet(key)] = callback
- }
-}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt
index c514ccf..24552d8 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt
@@ -57,6 +57,7 @@
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.node.InternalCoreApi
import androidx.compose.ui.node.LayoutNode
+import androidx.compose.ui.node.LayoutNodeDrawScope
import androidx.compose.ui.node.MeasureAndLayoutDelegate
import androidx.compose.ui.node.Owner
import androidx.compose.ui.node.OwnerSnapshotObserver
@@ -99,6 +100,8 @@
// TODO(demin): support RTL
override val layoutDirection: LayoutDirection = LayoutDirection.Ltr
+ override val sharedDrawScope = LayoutNodeDrawScope()
+
private val semanticsModifier = SemanticsModifierCore(
id = SemanticsModifierCore.generateSemanticsId(),
mergeDescendants = false,
@@ -185,9 +188,6 @@
override val viewConfiguration: ViewConfiguration = DesktopViewConfiguration(density)
- val keyboard: Keyboard?
- get() = container.keyboard
-
override fun sendKeyEvent(keyEvent: KeyEvent): Boolean {
when {
keyEvent.nativeKeyEvent.id == java.awt.event.KeyEvent.KEY_TYPED ->
@@ -196,8 +196,7 @@
container.platformInputService.charKeyPressed = false
}
- return keyInputModifier.processKeyInput(keyEvent) ||
- keyboard?.processKeyInput(keyEvent) ?: false
+ return keyInputModifier.processKeyInput(keyEvent)
}
override var showLayoutBounds = false
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt
index cf3f42f..fd239fd 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt
@@ -67,8 +67,6 @@
val list = LinkedHashSet<DesktopOwner>()
private val listCopy = mutableListOf<DesktopOwner>()
- var keyboard: Keyboard? = null
-
private var pointerId = 0L
private var isMousePressed = false
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/Keyboard.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/Keyboard.desktop.kt
deleted file mode 100644
index 95b1628..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/Keyboard.desktop.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.platform
-
-import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.KeyEvent
-import androidx.compose.ui.input.key.KeysSet
-import androidx.compose.ui.input.key.ShortcutsInstance
-import androidx.compose.ui.input.key.shortcuts
-
-/**
- * Window-scoped keyboard handling.
- *
- * @see [shortcuts] to setup event handlers based on the element that is in focus
- */
-class Keyboard {
- private val shortcutsInstance = lazy {
- ShortcutsInstance()
- }
-
- /**
- * Set a callback for [KeysSet]. If callback for the same [KeysSet] already exists, it
- * overrides it.
- *
- * @param keysSet: [KeysSet] instance to react
- * @param callback: Called when all keys from keysSet are pressed
- */
- fun setShortcut(keysSet: KeysSet, callback: () -> Unit) {
- shortcutsInstance.value.setHandler(keysSet, callback)
- }
-
- /**
- * Set a callback for [Key]. If callback for the same [Key] already exists, it
- * overrides it.
- *
- * @param key: [Key] instance to react
- * @param callback: Called when all keys from keysSet are pressed
- */
- fun setShortcut(key: Key, callback: () -> Unit) {
- shortcutsInstance.value.setHandler(KeysSet(key), callback)
- }
-
- /**
- * Remove a callback for [KeysSet]. If no such callback it's noop
- *
- * @param keysSet: [KeysSet] instance
- */
- fun removeShortcut(keysSet: KeysSet) {
- shortcutsInstance.value.removeHandler(keysSet)
- }
-
- internal fun processKeyInput(keyEvent: KeyEvent): Boolean {
- return if (shortcutsInstance.isInitialized()) {
- shortcutsInstance.value.process(keyEvent)
- } else {
- false
- }
- }
-}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt
index 7e179e90ef..4a6b15f 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt
@@ -16,10 +16,11 @@
package androidx.compose.ui.util
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.ui.Alignment
-import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.awt.ComposeWindow
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.asAwtImage
+import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.isSpecified
@@ -145,6 +146,11 @@
}
}
+// In fact, this size doesn't affect anything on Windows/Linux, and isn't used by macOs (macOs
+// doesn't have separate Window icons). We specify it to support Painter's with
+// Unspecified intrinsicSize
+private val iconSize = Size(32f, 32f)
+
internal fun Window.setIcon(painter: Painter?) {
- setIconImage(painter?.asAwtImage(density, layoutDirection))
+ setIconImage(painter?.asAwtImage(density, layoutDirection, iconSize))
}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Application.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Application.desktop.kt
index 20b6ac6..8073778 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Application.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Application.desktop.kt
@@ -16,9 +16,6 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.AppManager
-import androidx.compose.desktop.AppWindow
-import androidx.compose.desktop.ComposePanel
import androidx.compose.runtime.Applier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composition
@@ -30,8 +27,8 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.withFrameNanos
+import androidx.compose.ui.awt.ComposePanel
import androidx.compose.ui.configureSwingGlobalsForCompose
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.platform.GlobalSnapshotManager
import androidx.compose.ui.platform.LocalDensity
import kotlinx.coroutines.CoroutineScope
@@ -44,9 +41,6 @@
import kotlinx.coroutines.yield
import java.awt.Window
-// TODO(demin): remove ExperimentalComposeUiApi once we implement Dialog/Menu/Tray/Notifier, deprecate
-// AppWindow/AppWindowManager
-
/**
* An entry point for the Compose application. See [awaitApplication] for more information.
*
@@ -70,11 +64,8 @@
* }
* ```
*
- * This API is experimental and will eventually will replace [AppWindow] / [AppManager].
- *
* @see [awaitApplication]
*/
-@ExperimentalComposeUiApi
fun application(
content: @Composable ApplicationScope.() -> Unit
) {
@@ -105,11 +96,8 @@
* (because global coroutines are daemon threads, daemon threads don't keep process alive:
* https://kotlinlang.org/docs/coroutines-basics.html#global-coroutines-are-like-daemon-threads)
*
- * This API is experimental and will eventually replace [AppWindow] / [AppManager].
- *
* @see [awaitApplication]
*/
-@ExperimentalComposeUiApi
fun CoroutineScope.launchApplication(
content: @Composable ApplicationScope.() -> Unit
): Job {
@@ -157,8 +145,6 @@
*
* All animation's should be created inside Composable content of the
* [Window] / [Dialog] / [ComposePanel].
- *
- * This API is experimental and will eventually replace [AppWindow] / [AppManager].
*/
suspend fun awaitApplication(
content: @Composable ApplicationScope.() -> Unit
@@ -174,8 +160,6 @@
var isOpen by mutableStateOf(true)
val applicationScope = object : ApplicationScope {
- override val ownerWindow: Window? get() = null
-
override fun exitApplication() {
isOpen = false
}
@@ -210,7 +194,7 @@
}
}
-interface ApplicationScope : OwnerWindowScope {
+interface ApplicationScope {
fun exitApplication()
}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/AwtWindow.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/AwtWindow.desktop.kt
index 2cd0909..3b046e3 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/AwtWindow.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/AwtWindow.desktop.kt
@@ -16,15 +16,12 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.AppManager
-import androidx.compose.desktop.AppWindow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.node.Ref
import androidx.compose.ui.util.UpdateEffect
import kotlinx.coroutines.DelicateCoroutinesApi
@@ -52,8 +49,6 @@
* the default Compose functions [androidx.compose.ui.window.Window] or
* [androidx.compose.ui.window.Dialog].
*
- * This API is experimental and will eventually replace [AppWindow] / [AppManager].
- *
* @param visible Is [Window] visible to user.
* Note that if we set `false` - native resources will not be released. They will be released
* only when [Window] will leave the composition.
@@ -64,9 +59,8 @@
*/
@OptIn(DelicateCoroutinesApi::class)
@Suppress("unused")
-@ExperimentalComposeUiApi
@Composable
-fun <T : Window> OwnerWindowScope.AwtWindow(
+fun <T : Window> AwtWindow(
visible: Boolean = true,
create: () -> T,
dispose: (T) -> Unit,
@@ -74,17 +68,24 @@
) {
val currentVisible by rememberUpdatedState(visible)
- val window = remember { Ref<T>() }
+ val windowRef = remember { Ref<T>() }
+ fun window() = windowRef.value!!
DisposableEffect(Unit) {
- window.value = create()
+ windowRef.value = create()
+ // We should init a native window even if it is not yet visible.
+ // `pack` method makes window displayable, creates a native window, init graphic
+ // context, performs the first composition and runs effects
+ if (!currentVisible) {
+ window().pack()
+ }
onDispose {
- dispose(window.value!!)
+ dispose(window())
}
}
UpdateEffect {
- update(window.value!!)
+ update(window())
}
val showJob = Ref<Job?>()
@@ -118,14 +119,14 @@
showJob.value?.cancel()
showJob.value = GlobalScope.launch(Dispatchers.Swing) {
- window.value!!.isVisible = currentVisible
+ window().isVisible = currentVisible
}
}
DisposableEffect(Unit) {
onDispose {
showJob.value?.cancel()
- window.value!!.isVisible = false
+ window().isVisible = false
}
}
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/DesktopPopup.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/DesktopPopup.desktop.kt
index 8443a06..0cb06a1 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/DesktopPopup.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/DesktopPopup.desktop.kt
@@ -15,7 +15,6 @@
*/
package androidx.compose.ui.window
-import androidx.compose.desktop.LocalLayerContainer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
@@ -25,6 +24,7 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.LocalLayerContainer
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.layout.Layout
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt
index 3eb5c83..f9b2450 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt
@@ -16,13 +16,12 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.ComposeDialog
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCompositionContext
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.awt.ComposeDialog
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.unit.dp
@@ -89,12 +88,9 @@
* keyboard. While implementing this callback, return true to stop propagation of this event.
* If you return false, the key event will be sent to this [onKeyEvent]'s parent.
* @param content content of the dialog
- *
- * This API is experimental and will eventually replace [androidx.compose.ui.window.v1.Dialog]
*/
-@ExperimentalComposeUiApi
@Composable
-fun OwnerWindowScope.Dialog(
+fun Dialog(
onCloseRequest: () -> Unit,
state: DialogState = rememberDialogState(),
visible: Boolean = true,
@@ -108,7 +104,7 @@
onKeyEvent: ((KeyEvent) -> Boolean) = { false },
content: @Composable DialogWindowScope.() -> Unit
) {
- val owner = this.ownerWindow
+ val owner = LocalWindow.current
val currentState by rememberUpdatedState(state)
val currentTitle by rememberUpdatedState(title)
@@ -184,8 +180,6 @@
* Dialog is needed for creating dialog's that still can't be created with
* the default Compose function [androidx.compose.ui.window.Dialog]
*
- * This API is experimental and will eventually replace [androidx.compose.ui.window.v1.Dialog].
- *
* @param visible Is [ComposeDialog] visible to user.
* If `false`:
* - internal state of [ComposeDialog] is preserved and will be restored next time the dialog
@@ -207,9 +201,8 @@
* @param content Composable content of the creating dialog.
*/
@Suppress("unused")
-@ExperimentalComposeUiApi
@Composable
-fun OwnerWindowScope.Dialog(
+fun Dialog(
visible: Boolean = true,
onPreviewKeyEvent: ((KeyEvent) -> Boolean) = { false },
onKeyEvent: ((KeyEvent) -> Boolean) = { false },
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/LocalWindow.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/LocalWindow.kt
index 11ae455..3b8921b 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/LocalWindow.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/LocalWindow.kt
@@ -16,9 +16,9 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.ComposeDialog
-import androidx.compose.desktop.ComposePanel
-import androidx.compose.desktop.ComposeWindow
+import androidx.compose.ui.awt.ComposeDialog
+import androidx.compose.ui.awt.ComposePanel
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.runtime.compositionLocalOf
import java.awt.Window
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Notifier.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Notifier.desktop.kt
index 084d72b..c11779b 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Notifier.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Notifier.desktop.kt
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
+
package androidx.compose.ui.window
import java.awt.SystemTray
@@ -24,6 +26,11 @@
/**
* Notifier is a class that can send system notifications.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Tray_Notifications_MenuBar_new). Global notifications was not " +
+ "implemented in the new API as we don't properly support them in the current API."
+)
class Notifier {
/**
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/OwnerWindowScope.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/OwnerWindowScope.kt
deleted file mode 100644
index b641fea..0000000
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/OwnerWindowScope.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.window
-
-import java.awt.Window
-
-/**
- * Scope that is created by [application], [Window] or [Dialog] and provides an owner window of
- * this scope
- */
-interface OwnerWindowScope {
- /**
- * Owner window of this scope
- */
- val ownerWindow: Window?
-}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Tray.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Tray.desktop.kt
index a332f1b..157fe34 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Tray.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Tray.desktop.kt
@@ -16,8 +16,6 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.AppManager
-import androidx.compose.desktop.AppWindow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.SideEffect
@@ -26,9 +24,10 @@
import androidx.compose.runtime.rememberCompositionContext
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.asAwtImage
+import androidx.compose.ui.platform.DesktopPlatform
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.launchIn
@@ -38,6 +37,20 @@
import java.awt.SystemTray
import java.awt.TrayIcon
+// In fact, this size doesn't affect anything on Windows/Linux, because they request what they
+// need, and not what we provide. It only affects macOs. This size will be scaled in asAwtImage to
+// support DPI=2.0
+// Unfortunately I hadn't enough time to find sources from the official docs
+private val iconSize = when (DesktopPlatform.Current) {
+ // https://doc.qt.io/qt-5/qtwidgets-desktop-systray-example.html (search 22x22)
+ DesktopPlatform.Linux -> Size(22f, 22f)
+ // https://doc.qt.io/qt-5/qtwidgets-desktop-systray-example.html (search 16x16)
+ DesktopPlatform.Windows -> Size(16f, 16f)
+ // https://medium.com/@acwrightdesign/creating-a-macos-menu-bar-application-using-swiftui-54572a5d5f87
+ DesktopPlatform.MacOS -> Size(22f, 22f)
+ DesktopPlatform.Unknown -> Size(32f, 32f)
+}
+
/**
* `true` if the platform supports tray icons in the taskbar
*/
@@ -53,8 +66,6 @@
* See [isTraySupported] to know if tray icon is supported
* (for example to show/hide an option in the application settings)
*
- * This API is experimental and will eventually replace [AppWindow] / [AppManager].
- *
* @param icon Icon of the tray
* @param state State to control tray and show notifications
* @param hint Hint/tooltip that will be shown to the user
@@ -65,7 +76,6 @@
* right click on macOs)
*/
@Suppress("unused")
-@ExperimentalComposeUiApi
@Composable
fun ApplicationScope.Tray(
icon: Painter,
@@ -100,7 +110,7 @@
// (see MultiResolutionImage.getResolutionVariant). Resources like svg/xml should look okay
// because they don't use absolute '.dp' values to draw, they use values which are
// relative to their viewport.
- icon.asAwtImage(GlobalDensity, GlobalLayoutDirection)
+ icon.asAwtImage(GlobalDensity, GlobalLayoutDirection, iconSize)
}
val tray = remember {
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/UndecoratedWindowResizer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/UndecoratedWindowResizer.desktop.kt
index 555fa85..5c0c493 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/UndecoratedWindowResizer.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/UndecoratedWindowResizer.desktop.kt
@@ -16,7 +16,7 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.ComposeWindow
+import androidx.compose.ui.awt.ComposeLayer
import java.awt.Dimension
import java.awt.Cursor
import java.awt.event.MouseAdapter
@@ -24,11 +24,13 @@
import java.awt.event.MouseMotionAdapter
import java.awt.MouseInfo
import java.awt.Point
+import java.awt.Window
-internal val DefaultBorderThickness = 8
+internal const val DefaultBorderThickness = 8
internal class UndecoratedWindowResizer(
- private val window: ComposeWindow,
+ private val window: Window,
+ layer: ComposeLayer,
var enabled: Boolean = false,
var borderThickness: Int = DefaultBorderThickness
) {
@@ -58,8 +60,8 @@
}
init {
- window.layer.component.addMouseListener(mouseListener)
- window.layer.component.addMouseMotionListener(motionListener)
+ layer.component.addMouseListener(mouseListener)
+ layer.component.addMouseMotionListener(motionListener)
}
private fun changeCursor(event: MouseEvent) {
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt
index 979c71f..ea71dc7 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt
@@ -16,16 +16,13 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.AppManager
-import androidx.compose.desktop.AppWindow
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCompositionContext
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.unit.dp
@@ -104,13 +101,9 @@
* keyboard. While implementing this callback, return true to stop propagation of this event.
* If you return false, the key event will be sent to this [onKeyEvent]'s parent.
* @param content Content of the window
- *
- * This API is experimental and will eventually replace [AppWindow] / [AppManager]
*/
-@Suppress("unused")
-@ExperimentalComposeUiApi
@Composable
-fun ApplicationScope.Window(
+fun Window(
onCloseRequest: () -> Unit,
state: WindowState = rememberWindowState(),
visible: Boolean = true,
@@ -230,10 +223,7 @@
* keyboard. While implementing this callback, return true to stop propagation of this event.
* If you return false, the key event will be sent to this [onKeyEvent]'s parent.
* @param content Content of the window
- *
- * This API is experimental and will eventually replace [AppWindow] / [AppManager]
*/
-@ExperimentalComposeUiApi
fun singleWindowApplication(
state: WindowState = WindowState(),
visible: Boolean = true,
@@ -281,8 +271,6 @@
* Window is needed for creating window's that still can't be created with
* the default Compose function [androidx.compose.ui.window.Window]
*
- * This API is experimental and will eventually replace [AppWindow] / [AppManager].
- *
* @param visible Is [ComposeWindow] visible to user.
* If `false`:
* - internal state of [ComposeWindow] is preserved and will be restored next time the window
@@ -304,9 +292,8 @@
* @param content Composable content of the creating window.
*/
@Suppress("unused")
-@ExperimentalComposeUiApi
@Composable
-fun ApplicationScope.Window(
+fun Window(
visible: Boolean = true,
onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
onKeyEvent: (KeyEvent) -> Boolean = { false },
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/WindowScope.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/WindowScope.kt
index e44b4d1..6ea1ebb 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/WindowScope.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/WindowScope.kt
@@ -22,12 +22,10 @@
* Receiver scope which is used by [androidx.compose.ui.window.Window] and
* [androidx.compose.ui.window.Dialog].
*/
-interface WindowScope : OwnerWindowScope {
+interface WindowScope {
/**
* [Window] that was created inside [androidx.compose.ui.window.Window]
* or [androidx.compose.ui.window.Dialog]
*/
val window: Window
-
- override val ownerWindow: Window get() = window
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/DesktopDialog.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/DesktopDialog.desktop.kt
index a16f12a..b98b817 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/DesktopDialog.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/DesktopDialog.desktop.kt
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
package androidx.compose.ui.window.v1
@@ -48,6 +49,10 @@
* Supported events: onOpen, onClose, onMinimize, onMaximize, onRestore, onFocusGet, onFocusLost,
* onResize, onRelocate.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Window_API_new)"
+)
@Immutable
data class DialogProperties(
val title: String = "JetpackDesktopDialog",
@@ -72,6 +77,10 @@
* @param properties [DialogProperties] for further customization of this dialog's behavior.
* @param content The content to be displayed inside the dialog.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Window_API_new)"
+)
@Composable
fun Dialog(
onDismissRequest: () -> Unit,
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuBar.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuBar.desktop.kt
index 8f65fcf..9a18f99 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuBar.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuBar.desktop.kt
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
+
package androidx.compose.ui.window.v1
import org.jetbrains.skiko.Library
@@ -27,6 +29,10 @@
* The menu bar can be displayed inside a window (Windows, Linux) or at the top of
* the screen (Mac OS).
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Tray_Notifications_MenuBar_new)"
+)
class MenuBar {
internal var menuBar: JMenuBar
@@ -74,6 +80,10 @@
/**
* Menu is a class that represents a menu on a menu bar.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Tray_Notifications_MenuBar_new)"
+)
class Menu {
/**
* Gets the menu name.
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuItem.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuItem.desktop.kt
index 737c672..94113b11 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuItem.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/MenuItem.desktop.kt
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
+
package androidx.compose.ui.window.v1
import androidx.compose.ui.ExperimentalComposeUiApi
@@ -26,6 +28,11 @@
* Can be used with Menu or Tray.
*/
@OptIn(ExperimentalComposeUiApi::class)
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Tray_Notifications_MenuBar_new)"
+)
+@Suppress("DEPRECATION")
class MenuItem {
/**
@@ -69,6 +76,10 @@
*
* @return KeyStroke for the given key.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Tray_Notifications_MenuBar_new)"
+)
fun KeyStroke(key: Key): KeyStroke {
return KeyStroke.getKeyStroke(
key.nativeKeyCode,
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/Tray.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/Tray.desktop.kt
index 6affd42..2233163 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/Tray.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/v1/Tray.desktop.kt
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:Suppress("DEPRECATION")
+
package androidx.compose.ui.window.v1
import java.awt.Image
@@ -26,6 +28,10 @@
/**
* Tray is class for working with the system tray.
*/
+@Deprecated(
+ "Use new Composable Window API (https://github.com/JetBrains/compose-jb/" +
+ "tree/master/tutorials/Tray_Notifications_MenuBar_new)"
+)
class Tray {
private lateinit var trayIcon: TrayIcon
private var init: Boolean = false
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/desktop/AWTDebounceEventQueueTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/desktop/AWTDebounceEventQueueTest.kt
index 0ec8658..7e6dd86 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/desktop/AWTDebounceEventQueueTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/desktop/AWTDebounceEventQueueTest.kt
@@ -18,6 +18,7 @@
import androidx.compose.desktop.AWTDebounceEventQueueTest.Event.Input
import androidx.compose.desktop.AWTDebounceEventQueueTest.Event.Render
+import androidx.compose.ui.awt.AWTDebounceEventQueue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScope
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/TestUtils.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/TestUtils.kt
index 60ae294..481f255 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/TestUtils.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/TestUtils.kt
@@ -23,6 +23,8 @@
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import java.awt.Image
+import java.awt.Window
+import java.awt.event.KeyEvent
import java.awt.image.BufferedImage
import java.awt.image.MultiResolutionImage
import javax.swing.Icon
@@ -45,4 +47,19 @@
private val os = System.getProperty("os.name").lowercase()
internal val isLinux = os.startsWith("linux")
internal val isWindows = os.startsWith("win")
-internal val isMacOs = os.startsWith("mac")
\ No newline at end of file
+internal val isMacOs = os.startsWith("mac")
+
+fun Window.sendKey(
+ code: Int,
+ modifiers: Int = 0
+) = dispatchEvent(
+ KeyEvent(
+ focusOwner,
+ KeyEvent.KEY_PRESSED,
+ 0,
+ modifiers,
+ code,
+ code.toChar(),
+ KeyEvent.KEY_LOCATION_STANDARD
+ )
+)
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/input/key/ShortcutsTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/input/key/ShortcutsTest.kt
deleted file mode 100644
index 4db718b..0000000
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/input/key/ShortcutsTest.kt
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.input.key
-
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.size
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusRequester
-import androidx.compose.ui.focus.focusRequester
-import androidx.compose.ui.focus.focusTarget
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onRoot
-import androidx.compose.ui.test.performKeyPress
-import com.google.common.truth.Truth
-import androidx.compose.ui.unit.dp
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@OptIn(ExperimentalComposeUiApi::class)
-@RunWith(JUnit4::class)
-class ShortcutsTest {
- @get:Rule
- val rule = createComposeRule()
-
- @Test
- fun shortcuts_triggered() {
- val focusRequester = FocusRequester()
- var triggered = 0
- rule.setContent {
- Box(
- modifier = Modifier
- .size(10.dp, 10.dp)
- .focusRequester(focusRequester)
- .focusTarget()
- .shortcuts {
- on(Key.MetaLeft + Key.Enter) {
- triggered += 1
- }
- }
- )
- }
- rule.runOnIdle {
- focusRequester.requestFocus()
- }
-
- val firstKeyConsumed = rule.onRoot().performKeyPress(
- keyEvent(
- Key.MetaLeft, KeyEventType.KeyDown
- )
- )
-
- val secondKeyConsumed = rule.onRoot().performKeyPress(
- keyEvent(
- Key.Enter, KeyEventType.KeyDown
- )
- )
-
- rule.onRoot().performKeyPress(
- keyTypedEvent(Key.Enter)
- )
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.MetaLeft, KeyEventType.KeyUp
- )
- )
-
- rule.runOnIdle {
- Truth.assertThat(triggered).isEqualTo(1)
- Truth.assertThat(firstKeyConsumed).isFalse()
- Truth.assertThat(secondKeyConsumed).isTrue()
- }
- }
-
- @Test
- fun shortcuts_states() {
- val focusRequester = FocusRequester()
- var triggered = 0
- var setShortcuts by mutableStateOf(true)
- rule.setContent {
- Box(
- modifier = Modifier
- .size(10.dp, 10.dp)
- .focusRequester(focusRequester)
- .focusTarget()
- .shortcuts {
- if (setShortcuts) {
- on(Key.Enter) {
- triggered += 1
- }
- }
- }
- )
- }
-
- rule.runOnIdle {
- focusRequester.requestFocus()
- }
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.Enter, KeyEventType.KeyDown
- )
- )
-
- rule.runOnIdle {
- Truth.assertThat(triggered).isEqualTo(1)
- }
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.Enter, KeyEventType.KeyUp
- )
- )
-
- // Disables shortcuts
- rule.runOnIdle {
- setShortcuts = false
- }
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.Enter, KeyEventType.KeyDown
- )
- )
-
- rule.runOnIdle {
- Truth.assertThat(triggered).isEqualTo(1)
- }
- }
-
- @Test
- fun shortcuts_priority() {
- val focusRequester = FocusRequester()
- var enterTriggered = 0
- var shortcutTriggered = 0
- rule.setContent {
- Box(
- modifier = Modifier
- .size(10.dp, 10.dp)
- .focusRequester(focusRequester)
- .focusTarget()
- .shortcuts {
- on(Key.Enter) {
- enterTriggered += 1
- }
-
- on(Key.ShiftLeft + Key.Enter) {
- shortcutTriggered += 1
- }
- }
- )
- }
-
- rule.runOnIdle {
- focusRequester.requestFocus()
- }
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.ShiftLeft, KeyEventType.KeyDown
- )
- )
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.Enter, KeyEventType.KeyDown
- )
- )
-
- rule.runOnIdle {
- Truth.assertThat(enterTriggered).isEqualTo(0)
- Truth.assertThat(shortcutTriggered).isEqualTo(1)
- }
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.Enter, KeyEventType.KeyUp
- )
- )
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.ShiftLeft, KeyEventType.KeyUp
- )
- )
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.Enter, KeyEventType.KeyDown
- )
- )
-
- rule.runOnIdle {
- Truth.assertThat(enterTriggered).isEqualTo(1)
- Truth.assertThat(shortcutTriggered).isEqualTo(1)
- }
- }
-
- @Test
- fun shortcuts_multiple() {
- val focusRequester = FocusRequester()
- var aTriggered = 0
- var cTriggered = 0
- rule.setContent {
- Box(
- modifier = Modifier
- .size(10.dp, 10.dp)
- .focusRequester(focusRequester)
- .focusTarget()
- .shortcuts {
- on(Key.MetaLeft + Key.A) {
- aTriggered += 1
- }
-
- on(Key.MetaLeft + Key.C) {
- cTriggered += 1
- }
- }
- )
- }
-
- rule.runOnIdle {
- focusRequester.requestFocus()
- }
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.MetaLeft, KeyEventType.KeyDown
- )
- )
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.C, KeyEventType.KeyDown
- )
- )
-
- rule.runOnIdle {
- Truth.assertThat(aTriggered).isEqualTo(0)
- Truth.assertThat(cTriggered).isEqualTo(1)
- }
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.C, KeyEventType.KeyUp
- )
- )
-
- rule.onRoot().performKeyPress(
- keyEvent(
- Key.A, KeyEventType.KeyDown
- )
- )
-
- rule.runOnIdle {
- Truth.assertThat(aTriggered).isEqualTo(1)
- Truth.assertThat(cTriggered).isEqualTo(1)
- }
- }
-}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/ApplicationTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/ApplicationTest.kt
index a640b3b..97e33d7 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/ApplicationTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/ApplicationTest.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
@@ -27,6 +26,7 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.google.common.truth.Truth.assertThat
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/MenuBarTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/MenuBarTest.kt
index b862980..511bc01 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/MenuBarTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/MenuBarTest.kt
@@ -16,11 +16,11 @@
package androidx.compose.ui.window
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.readFirstPixel
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/dialog/DialogTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/dialog/DialogTest.kt
new file mode 100644
index 0000000..916cffb
--- /dev/null
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/dialog/DialogTest.kt
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.window.dialog
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.compositionLocalOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.ComposeDialog
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.focusTarget
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.onKeyEvent
+import androidx.compose.ui.input.key.onPreviewKeyEvent
+import androidx.compose.ui.sendKey
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import androidx.compose.ui.window.WindowSize
+import androidx.compose.ui.window.launchApplication
+import androidx.compose.ui.window.rememberDialogState
+import androidx.compose.ui.window.runApplicationTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import java.awt.Dimension
+import java.awt.event.KeyEvent
+import java.awt.event.WindowAdapter
+import java.awt.event.WindowEvent
+
+@OptIn(ExperimentalComposeUiApi::class)
+class DialogTest {
+ @Test
+ fun `open and close custom dialog`() = runApplicationTest {
+ var window: ComposeDialog? = null
+
+ launchApplication {
+ var isOpen by remember { mutableStateOf(true) }
+
+ fun createWindow() = ComposeDialog().apply {
+ size = Dimension(300, 200)
+
+ addWindowListener(object : WindowAdapter() {
+ override fun windowClosing(e: WindowEvent) {
+ isOpen = false
+ }
+ })
+ }
+
+ if (isOpen) {
+ Dialog(
+ create = ::createWindow,
+ dispose = ComposeDialog::dispose
+ ) {
+ window = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(window?.isShowing).isTrue()
+
+ window?.dispatchEvent(WindowEvent(window, WindowEvent.WINDOW_CLOSING))
+ }
+
+ @Test
+ fun `update custom dialog`() = runApplicationTest {
+ var window: ComposeDialog? = null
+
+ var isOpen by mutableStateOf(true)
+ var title by mutableStateOf("Title1")
+
+ launchApplication {
+ fun createWindow() = ComposeDialog().apply {
+ size = Dimension(300, 200)
+
+ addWindowListener(object : WindowAdapter() {
+ override fun windowClosing(e: WindowEvent) {
+ isOpen = false
+ }
+ })
+ }
+
+ if (isOpen) {
+ Dialog(
+ create = ::createWindow,
+ dispose = ComposeDialog::dispose,
+ update = { it.title = title }
+ ) {
+ window = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(window?.isShowing).isTrue()
+ assertThat(window?.title).isEqualTo(title)
+
+ title = "Title2"
+ awaitIdle()
+ assertThat(window?.title).isEqualTo(title)
+
+ isOpen = false
+ }
+
+ @Test
+ fun `open and close dialog`() = runApplicationTest {
+ var window: ComposeDialog? = null
+
+ launchApplication {
+ Dialog(onCloseRequest = ::exitApplication) {
+ window = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+ }
+ }
+
+ awaitIdle()
+ assertThat(window?.isShowing).isTrue()
+
+ window?.dispatchEvent(WindowEvent(window, WindowEvent.WINDOW_CLOSING))
+ }
+
+ @Test
+ fun `disable closing dialog`() = runApplicationTest {
+ var isOpen by mutableStateOf(true)
+ var isCloseCalled by mutableStateOf(false)
+ var window: ComposeDialog? = null
+
+ launchApplication {
+ if (isOpen) {
+ Dialog(
+ onCloseRequest = {
+ isCloseCalled = true
+ }
+ ) {
+ window = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+ }
+ }
+ }
+
+ awaitIdle()
+
+ window?.dispatchEvent(WindowEvent(window, WindowEvent.WINDOW_CLOSING))
+ awaitIdle()
+ assertThat(isCloseCalled).isTrue()
+ assertThat(window?.isShowing).isTrue()
+
+ isOpen = false
+ awaitIdle()
+ assertThat(window?.isShowing).isFalse()
+ }
+
+ @Test
+ fun `show splash screen`() = runApplicationTest {
+ var window1: ComposeDialog? = null
+ var window2: ComposeDialog? = null
+
+ var isOpen by mutableStateOf(true)
+ var isLoading by mutableStateOf(true)
+
+ launchApplication {
+ if (isOpen) {
+ if (isLoading) {
+ Dialog(onCloseRequest = {}) {
+ window1 = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+ }
+ } else {
+ Dialog(onCloseRequest = {}) {
+ window2 = this.window
+ Box(Modifier.size(32.dp).background(Color.Blue))
+ }
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2).isNull()
+
+ isLoading = false
+ awaitIdle()
+ assertThat(window1?.isShowing).isFalse()
+ assertThat(window2?.isShowing).isTrue()
+
+ isOpen = false
+ awaitIdle()
+ assertThat(window1?.isShowing).isFalse()
+ assertThat(window2?.isShowing).isFalse()
+ }
+
+ @Test
+ fun `open two dialogs`() = runApplicationTest {
+ var window1: ComposeDialog? = null
+ var window2: ComposeDialog? = null
+
+ var isOpen by mutableStateOf(true)
+
+ launchApplication {
+ if (isOpen) {
+ Dialog(onCloseRequest = {}) {
+ window1 = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+ }
+
+ Dialog(onCloseRequest = {}) {
+ window2 = this.window
+ Box(Modifier.size(32.dp).background(Color.Blue))
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2?.isShowing).isTrue()
+
+ isOpen = false
+ awaitIdle()
+ assertThat(window1?.isShowing).isFalse()
+ assertThat(window2?.isShowing).isFalse()
+ }
+
+ @Test
+ fun `open nested dialog`() = runApplicationTest {
+ var window1: ComposeDialog? = null
+ var window2: ComposeDialog? = null
+
+ var isOpen by mutableStateOf(true)
+ var isNestedOpen by mutableStateOf(true)
+
+ launchApplication {
+ if (isOpen) {
+ Dialog(
+ onCloseRequest = {},
+ state = rememberDialogState(
+ size = WindowSize(600.dp, 600.dp),
+ )
+ ) {
+ window1 = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+
+ if (isNestedOpen) {
+ Dialog(
+ onCloseRequest = {},
+ state = rememberDialogState(
+ size = WindowSize(300.dp, 300.dp),
+ )
+ ) {
+ window2 = this.window
+ Box(Modifier.size(32.dp).background(Color.Blue))
+ }
+ }
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2?.isShowing).isTrue()
+
+ isNestedOpen = false
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2?.isShowing).isFalse()
+
+ isNestedOpen = true
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2?.isShowing).isTrue()
+
+ isOpen = false
+ awaitIdle()
+ assertThat(window1?.isShowing).isFalse()
+ assertThat(window2?.isShowing).isFalse()
+ }
+
+ @Test
+ fun `pass composition local to dialogs`() = runApplicationTest {
+ var actualValue1: Int? = null
+ var actualValue2: Int? = null
+
+ var isOpen by mutableStateOf(true)
+ var testValue by mutableStateOf(0)
+ val localTestValue = compositionLocalOf { testValue }
+
+ launchApplication {
+ if (isOpen) {
+ CompositionLocalProvider(localTestValue provides testValue) {
+ Dialog(
+ onCloseRequest = {},
+ state = rememberDialogState(
+ size = WindowSize(600.dp, 600.dp),
+ )
+ ) {
+ actualValue1 = localTestValue.current
+ Box(Modifier.size(32.dp).background(Color.Red))
+
+ Dialog(
+ onCloseRequest = {},
+ state = rememberDialogState(
+ size = WindowSize(300.dp, 300.dp),
+ )
+ ) {
+ actualValue2 = localTestValue.current
+ Box(Modifier.size(32.dp).background(Color.Blue))
+ }
+ }
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(actualValue1).isEqualTo(0)
+ assertThat(actualValue2).isEqualTo(0)
+
+ testValue = 42
+ awaitIdle()
+ assertThat(actualValue1).isEqualTo(42)
+ assertThat(actualValue2).isEqualTo(42)
+
+ isOpen = false
+ }
+
+ @Test
+ fun `DisposableEffect call order`() = runApplicationTest {
+ var initCount = 0
+ var disposeCount = 0
+
+ var isOpen by mutableStateOf(true)
+
+ launchApplication {
+ if (isOpen) {
+ Dialog(onCloseRequest = {}) {
+ DisposableEffect(Unit) {
+ initCount++
+ onDispose {
+ disposeCount++
+ }
+ }
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(initCount).isEqualTo(1)
+ assertThat(disposeCount).isEqualTo(0)
+
+ isOpen = false
+ awaitIdle()
+ assertThat(initCount).isEqualTo(1)
+ assertThat(disposeCount).isEqualTo(1)
+ }
+
+ @Test
+ fun `catch key handlers`() = runApplicationTest {
+ var window: ComposeDialog? = null
+ val onKeyEventKeys = mutableSetOf<Key>()
+ val onPreviewKeyEventKeys = mutableSetOf<Key>()
+
+ fun clear() {
+ onKeyEventKeys.clear()
+ onPreviewKeyEventKeys.clear()
+ }
+
+ launchApplication {
+ Dialog(
+ onCloseRequest = ::exitApplication,
+ onPreviewKeyEvent = {
+ onPreviewKeyEventKeys.add(it.key)
+ it.key == Key.Q
+ },
+ onKeyEvent = {
+ onKeyEventKeys.add(it.key)
+ it.key == Key.W
+ }
+ ) {
+ window = this.window
+ }
+ }
+
+ awaitIdle()
+
+ window?.sendKey(KeyEvent.VK_Q)
+ awaitIdle()
+ assertThat(onPreviewKeyEventKeys).isEqualTo(setOf(Key.Q))
+ assertThat(onKeyEventKeys).isEqualTo(emptySet<Key>())
+
+ clear()
+ window?.sendKey(KeyEvent.VK_W)
+ awaitIdle()
+ assertThat(onPreviewKeyEventKeys).isEqualTo(setOf(Key.W))
+ assertThat(onKeyEventKeys).isEqualTo(setOf(Key.W))
+
+ clear()
+ window?.sendKey(KeyEvent.VK_E)
+ awaitIdle()
+ assertThat(onPreviewKeyEventKeys).isEqualTo(setOf(Key.E))
+ assertThat(onKeyEventKeys).isEqualTo(setOf(Key.E))
+
+ exitApplication()
+ }
+
+ @Test
+ fun `catch key handlers with focused node`() = runApplicationTest {
+ var window: ComposeDialog? = null
+ val onWindowKeyEventKeys = mutableSetOf<Key>()
+ val onWindowPreviewKeyEventKeys = mutableSetOf<Key>()
+ val onNodeKeyEventKeys = mutableSetOf<Key>()
+ val onNodePreviewKeyEventKeys = mutableSetOf<Key>()
+
+ fun clear() {
+ onWindowKeyEventKeys.clear()
+ onWindowPreviewKeyEventKeys.clear()
+ onNodeKeyEventKeys.clear()
+ onNodePreviewKeyEventKeys.clear()
+ }
+
+ launchApplication {
+ Dialog(
+ onCloseRequest = ::exitApplication,
+ onPreviewKeyEvent = {
+ onWindowPreviewKeyEventKeys.add(it.key)
+ it.key == Key.Q
+ },
+ onKeyEvent = {
+ onWindowKeyEventKeys.add(it.key)
+ it.key == Key.W
+ },
+ ) {
+ window = this.window
+
+ val focusRequester = remember(::FocusRequester)
+ LaunchedEffect(Unit) {
+ focusRequester.requestFocus()
+ }
+
+ Box(
+ Modifier
+ .focusRequester(focusRequester)
+ .focusTarget()
+ .onPreviewKeyEvent {
+ onNodePreviewKeyEventKeys.add(it.key)
+ it.key == Key.E
+ }
+ .onKeyEvent {
+ onNodeKeyEventKeys.add(it.key)
+ it.key == Key.R
+ }
+ )
+ }
+ }
+
+ awaitIdle()
+
+ window?.sendKey(KeyEvent.VK_Q)
+ awaitIdle()
+ assertThat(onWindowPreviewKeyEventKeys).isEqualTo(setOf(Key.Q))
+ assertThat(onNodePreviewKeyEventKeys).isEqualTo(emptySet<Key>())
+ assertThat(onNodeKeyEventKeys).isEqualTo(emptySet<Key>())
+ assertThat(onWindowKeyEventKeys).isEqualTo(emptySet<Key>())
+
+ clear()
+ window?.sendKey(KeyEvent.VK_W)
+ awaitIdle()
+ assertThat(onWindowPreviewKeyEventKeys).isEqualTo(setOf(Key.W))
+ assertThat(onNodePreviewKeyEventKeys).isEqualTo(setOf(Key.W))
+ assertThat(onNodeKeyEventKeys).isEqualTo(setOf(Key.W))
+ assertThat(onWindowKeyEventKeys).isEqualTo(setOf(Key.W))
+
+ clear()
+ window?.sendKey(KeyEvent.VK_E)
+ awaitIdle()
+ assertThat(onWindowPreviewKeyEventKeys).isEqualTo(setOf(Key.E))
+ assertThat(onNodePreviewKeyEventKeys).isEqualTo(setOf(Key.E))
+ assertThat(onNodeKeyEventKeys).isEqualTo(emptySet<Key>())
+ assertThat(onWindowKeyEventKeys).isEqualTo(emptySet<Key>())
+
+ clear()
+ window?.sendKey(KeyEvent.VK_R)
+ awaitIdle()
+ assertThat(onWindowPreviewKeyEventKeys).isEqualTo(setOf(Key.R))
+ assertThat(onNodePreviewKeyEventKeys).isEqualTo(setOf(Key.R))
+ assertThat(onNodeKeyEventKeys).isEqualTo(setOf(Key.R))
+ assertThat(onWindowKeyEventKeys).isEqualTo(emptySet<Key>())
+
+ clear()
+ window?.sendKey(KeyEvent.VK_T)
+ awaitIdle()
+ assertThat(onWindowPreviewKeyEventKeys).isEqualTo(setOf(Key.T))
+ assertThat(onNodePreviewKeyEventKeys).isEqualTo(setOf(Key.T))
+ assertThat(onNodeKeyEventKeys).isEqualTo(setOf(Key.T))
+ assertThat(onWindowKeyEventKeys).isEqualTo(setOf(Key.T))
+
+ exitApplication()
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowParameterTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowParameterTest.kt
index 7095516..1c60660 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowParameterTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowParameterTest.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.window.window
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
@@ -25,6 +24,7 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.readFirstPixel
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowStateTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowStateTest.kt
index 1724a80..ba00bdf 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowStateTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowStateTest.kt
@@ -15,7 +15,6 @@
package androidx.compose.ui.window.window
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
@@ -27,6 +26,7 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.isLinux
import androidx.compose.ui.isWindows
import androidx.compose.ui.unit.Dp
@@ -40,6 +40,8 @@
import androidx.compose.ui.window.rememberWindowState
import androidx.compose.ui.window.runApplicationTest
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.consumeEach
import org.junit.Assume.assumeTrue
import org.junit.Test
import java.awt.Dimension
@@ -718,6 +720,55 @@
exitApplication()
}
+ @Test
+ fun `change visible`() = runApplicationTest {
+ lateinit var window: ComposeWindow
+
+ var visible by mutableStateOf(false)
+
+ launchApplication {
+ Window(onCloseRequest = ::exitApplication, visible = visible) {
+ window = this.window
+ }
+ }
+
+ awaitIdle()
+ assertThat(window.isVisible).isEqualTo(false)
+
+ visible = true
+ awaitIdle()
+ assertThat(window.isVisible).isEqualTo(true)
+
+ exitApplication()
+ }
+
+ @Test
+ fun `invisible window should be active`() = runApplicationTest {
+ val receivedNumbers = mutableListOf<Int>()
+
+ val sendChannel = Channel<Int>(Channel.UNLIMITED)
+
+ launchApplication {
+ Window(onCloseRequest = ::exitApplication, visible = false) {
+ LaunchedEffect(Unit) {
+ sendChannel.consumeEach {
+ receivedNumbers.add(it)
+ }
+ }
+ }
+ }
+
+ sendChannel.send(1)
+ awaitIdle()
+ assertThat(receivedNumbers).isEqualTo(listOf(1))
+
+ sendChannel.send(2)
+ awaitIdle()
+ assertThat(receivedNumbers).isEqualTo(listOf(1, 2))
+
+ exitApplication()
+ }
+
private val Window.contentSize get() = Dimension(
size.width - insets.left - insets.right,
size.height - insets.top - insets.bottom,
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt
index 31e4b9e..160912c 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.window.window
-import androidx.compose.desktop.ComposeWindow
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
@@ -30,6 +29,7 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusTarget
@@ -38,6 +38,7 @@
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.onPreviewKeyEvent
+import androidx.compose.ui.sendKey
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowSize
@@ -48,7 +49,6 @@
import org.junit.Test
import java.awt.Dimension
import java.awt.event.KeyEvent
-import java.awt.event.KeyEvent.KEY_LOCATION_STANDARD
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
@@ -248,8 +248,63 @@
}
@Test
+ fun `open nested window`() = runApplicationTest {
+ var window1: ComposeWindow? = null
+ var window2: ComposeWindow? = null
+
+ var isOpen by mutableStateOf(true)
+ var isNestedOpen by mutableStateOf(true)
+
+ launchApplication {
+ if (isOpen) {
+ Window(
+ onCloseRequest = {},
+ state = rememberWindowState(
+ size = WindowSize(600.dp, 600.dp),
+ )
+ ) {
+ window1 = this.window
+ Box(Modifier.size(32.dp).background(Color.Red))
+
+ if (isNestedOpen) {
+ Window(
+ onCloseRequest = {},
+ state = rememberWindowState(
+ size = WindowSize(300.dp, 300.dp),
+ )
+ ) {
+ window2 = this.window
+ Box(Modifier.size(32.dp).background(Color.Blue))
+ }
+ }
+ }
+ }
+ }
+
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2?.isShowing).isTrue()
+
+ isNestedOpen = false
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2?.isShowing).isFalse()
+
+ isNestedOpen = true
+ awaitIdle()
+ assertThat(window1?.isShowing).isTrue()
+ assertThat(window2?.isShowing).isTrue()
+
+ isOpen = false
+ awaitIdle()
+ assertThat(window1?.isShowing).isFalse()
+ assertThat(window2?.isShowing).isFalse()
+ }
+
+ @Test
fun `pass composition local to windows`() = runApplicationTest {
var actualValue1: Int? = null
+ var actualValue2: Int? = null
var isOpen by mutableStateOf(true)
var testValue by mutableStateOf(0)
@@ -266,6 +321,16 @@
) {
actualValue1 = localTestValue.current
Box(Modifier.size(32.dp).background(Color.Red))
+
+ Window(
+ onCloseRequest = {},
+ state = rememberWindowState(
+ size = WindowSize(300.dp, 300.dp),
+ )
+ ) {
+ actualValue2 = localTestValue.current
+ Box(Modifier.size(32.dp).background(Color.Blue))
+ }
}
}
}
@@ -273,10 +338,12 @@
awaitIdle()
assertThat(actualValue1).isEqualTo(0)
+ assertThat(actualValue2).isEqualTo(0)
testValue = 42
awaitIdle()
assertThat(actualValue1).isEqualTo(42)
+ assertThat(actualValue2).isEqualTo(42)
isOpen = false
}
@@ -453,16 +520,4 @@
exitApplication()
}
-
- private fun ComposeWindow.sendKey(code: Int) = layer.owners.onKeyPressed(
- KeyEvent(
- layer.wrapped,
- KeyEvent.KEY_PRESSED,
- 0,
- 0,
- code,
- code.toChar(),
- KEY_LOCATION_STANDARD
- )
- )
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/main/res/color/vector_tint_color.xml b/compose/ui/ui/src/main/res/color/vector_tint_color.xml
new file mode 100644
index 0000000..fe88a39
--- /dev/null
+++ b/compose/ui/ui/src/main/res/color/vector_tint_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:color="#0000FF" />
+</selector>
\ No newline at end of file
diff --git a/compose/ui/ui/src/main/res/color/vector_tint_theme_color.xml b/compose/ui/ui/src/main/res/color/vector_tint_theme_color.xml
new file mode 100644
index 0000000..3e8775d
--- /dev/null
+++ b/compose/ui/ui/src/main/res/color/vector_tint_theme_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:color="?android:colorAccent" />
+</selector>
\ No newline at end of file
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
index 95c1c79..6518162 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
@@ -1894,6 +1894,8 @@
override var measureIteration: Long = 0
override val viewConfiguration: ViewConfiguration
get() = TODO("Not yet implemented")
+
+ override val sharedDrawScope = LayoutNodeDrawScope()
}
private fun LayoutNode(x: Int, y: Int, x2: Int, y2: Int, modifier: Modifier = Modifier) =
diff --git a/core/OWNERS b/core/OWNERS
index 37b3e14..cb02012 100644
--- a/core/OWNERS
+++ b/core/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 460834
+alanv@google.com
aurimas@google.com
cinek@google.com
clarabayarri@google.com
diff --git a/core/core-appdigest/build.gradle b/core/core-appdigest/build.gradle
index c9f7302..12a4a92 100644
--- a/core/core-appdigest/build.gradle
+++ b/core/core-appdigest/build.gradle
@@ -25,7 +25,7 @@
dependencies {
api("androidx.annotation:annotation:1.0.0")
- api("androidx.core:core:1.0.0")
+ implementation(project(":core:core"))
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRunner)
diff --git a/core/core-appdigest/lint-baseline.xml b/core/core-appdigest/lint-baseline.xml
index f787484e..425cdb0 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.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
+<issues format="6" by="lint 7.1.0-alpha03" type="baseline" client="gradle" name="AGP (7.1.0-alpha03)" variant="all" version="7.1.0-alpha03">
<issue
id="NewApi"
@@ -8,7 +8,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java"
- line="379"
+ line="621"
column="31"/>
</issue>
@@ -19,8 +19,216 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java"
- line="395"
+ line="637"
column="35"/>
</issue>
+ <issue
+ id="WrongConstant"
+ message="Must be one or more of: Checksum.TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, Checksum.TYPE_WHOLE_MD5, Checksum.TYPE_WHOLE_SHA1, Checksum.TYPE_WHOLE_SHA256, Checksum.TYPE_WHOLE_SHA512, Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512"
+ errorLine1=" apkChecksum.getType(), apkChecksum.getValue(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="204"
+ column="45"/>
+ </issue>
+ <issue
+ id="NewApi"
+ message="Field requires API level S (current min is 14): `android.content.pm.PackageManager#TRUST_ALL`"
+ errorLine1=" trustedInstallers = PackageManager.TRUST_ALL;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="180"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level S (current min is 14): `android.content.pm.PackageManager#TRUST_NONE`"
+ errorLine1=" trustedInstallers = PackageManager.TRUST_NONE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="182"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 14): `android.content.pm.PackageManager#requestChecksums`"
+ errorLine1=" context.getPackageManager().requestChecksums(packageName, includeSplits, required,"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="189"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast to `OnChecksumsReadyListener` requires API level 31 (current min is 14)"
+ errorLine1=" trustedInstallers, new PackageManager.OnChecksumsReadyListener() {"
+ errorLine2=" ^">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="190"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level S (current min is 14): `android.content.pm.PackageManager.OnChecksumsReadyListener`"
+ errorLine1=" trustedInstallers, new PackageManager.OnChecksumsReadyListener() {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="190"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 14): `android.content.pm.ApkChecksum#getSplitName`"
+ errorLine1=" checksums[i] = new Checksum(apkChecksum.getSplitName(),"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="203"
+ column="77"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 14): `android.content.pm.ApkChecksum#getType`"
+ errorLine1=" apkChecksum.getType(), apkChecksum.getValue(),"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="204"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 14): `android.content.pm.ApkChecksum#getValue`"
+ errorLine1=" apkChecksum.getType(), apkChecksum.getValue(),"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="204"
+ column="80"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 14): `android.content.pm.ApkChecksum#getInstallerPackageName`"
+ errorLine1=" apkChecksum.getInstallerPackageName(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="205"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 14): `android.content.pm.ApkChecksum#getInstallerCertificate`"
+ errorLine1=" apkChecksum.getInstallerCertificate());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="206"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 29 (current min is 24): `android.app.UiAutomation#adoptShellPermissionIdentity`"
+ errorLine1=" getUiAutomation().adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGES);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java"
+ line="621"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 29 (current min is 24): `android.app.UiAutomation#dropShellPermissionIdentity`"
+ errorLine1=" getUiAutomation().dropShellPermissionIdentity();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java"
+ line="637"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 31; however, the containing class androidx.core.appdigest.Checksums.ApiSImpl is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" context.getPackageManager().requestChecksums(packageName, includeSplits, required,"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="189"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 31; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" checksums[i] = new Checksum(apkChecksum.getSplitName(),"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="203"
+ column="77"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 31; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" apkChecksum.getType(), apkChecksum.getValue(),"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="204"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 31; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" apkChecksum.getType(), apkChecksum.getValue(),"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="204"
+ column="80"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 31; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" apkChecksum.getInstallerPackageName(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="205"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 31; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" apkChecksum.getInstallerCertificate());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/appdigest/Checksums.java"
+ line="206"
+ column="57"/>
+ </issue>
+
</issues>
diff --git a/core/core-appdigest/src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java b/core/core-appdigest/src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java
index 6d09208..16eff3c 100644
--- a/core/core-appdigest/src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java
+++ b/core/core-appdigest/src/androidTest/java/androidx/core/appdigest/ChecksumsTest.java
@@ -27,6 +27,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.Manifest;
@@ -43,6 +44,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.os.BuildCompat;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
@@ -90,6 +92,8 @@
private static final String TEST_FIXED_APK_VERITY = "CtsPkgInstallTinyAppV2V3V4-Verity.apk";
private static final String TEST_FIXED_APK_MD5 = "c19868da017dc01467169f8ea7c5bc57";
+ private static final String TEST_FIXED_APK_V2_SHA256 =
+ "1eec9e86e322b8d7e48e255fc3f2df2dbc91036e63982ff9850597c6a37bbeb3";
private static final String TEST_FIXED_APK_SHA256 =
"91aa30c1ce8d0474052f71cb8210691d41f534989c5521e27e794ec4f754c5ef";
private static final String TEST_FIXED_APK_SHA512 =
@@ -100,7 +104,8 @@
TYPE_WHOLE_MERKLE_ROOT_4K_SHA256 | TYPE_WHOLE_MD5 | TYPE_WHOLE_SHA1 | TYPE_WHOLE_SHA256
| TYPE_WHOLE_SHA512
| TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256 | TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512;
-
+ private static final char[] HEX_LOWER_CASE_DIGITS =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private Context mContext;
private Executor mExecutor;
@@ -109,225 +114,6 @@
uninstallPackageSilently(FIXED_PACKAGE_NAME);
}
- @Before
- public void onBefore() throws Exception {
- mContext = ApplicationProvider.getApplicationContext();
- mExecutor = Executors.newCachedThreadPool();
- }
-
- @After
- public void onAfter() throws Exception {
- uninstallPackageSilently(V4_PACKAGE_NAME);
- assertFalse(isAppInstalled(V4_PACKAGE_NAME));
- uninstallPackageSilently(FIXED_PACKAGE_NAME);
- assertFalse(isAppInstalled(FIXED_PACKAGE_NAME));
- }
-
- @SmallTest
- @Test
- public void testDefaultChecksums() throws Exception {
- Checksum[] checksums = getChecksums(V2V3_PACKAGE_NAME, true, 0, Checksums.TRUST_NONE);
- assertNotNull(checksums);
- assertEquals(0, checksums.length);
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testSplitsSha256() throws Exception {
- installSplits(new String[]{TEST_V4_APK, TEST_V4_SPLIT0, TEST_V4_SPLIT1, TEST_V4_SPLIT2,
- TEST_V4_SPLIT3, TEST_V4_SPLIT4});
- assertTrue(isAppInstalled(V4_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(V4_PACKAGE_NAME, true, TYPE_WHOLE_SHA256,
- Checksums.TRUST_NONE);
- assertNotNull(checksums);
- assertEquals(6, checksums.length);
- assertEquals(checksums[0].getSplitName(), null);
- assertEquals(checksums[0].getType(), TYPE_WHOLE_SHA256);
- assertEquals(bytesToHexString(checksums[0].getValue()),
- "ce4ad41be1191ab3cdfef09ab6fb3c5d057e15cb3553661b393f770d9149f1cc");
- assertEquals(checksums[1].getSplitName(), "config.hdpi");
- assertEquals(checksums[1].getType(), TYPE_WHOLE_SHA256);
- assertEquals(bytesToHexString(checksums[1].getValue()),
- "336a47c278f6b6c22abffefa6a62971fd0bd718d6947143e6ed1f6f6126a8196");
- assertEquals(checksums[2].getSplitName(), "config.mdpi");
- assertEquals(checksums[2].getType(), TYPE_WHOLE_SHA256);
- assertEquals(bytesToHexString(checksums[2].getValue()),
- "17fe9f85e6f29a7354932002c8bc4cb829e1f4acf7f30626bd298c810bb13215");
- assertEquals(checksums[3].getSplitName(), "config.xhdpi");
- assertEquals(checksums[3].getType(), TYPE_WHOLE_SHA256);
- assertEquals(bytesToHexString(checksums[3].getValue()),
- "71a0b0ac5970def7ad80071c909be1e446174a9b39ea5cbf3004db05f87bcc4b");
- assertEquals(checksums[4].getSplitName(), "config.xxhdpi");
- assertEquals(checksums[4].getType(), TYPE_WHOLE_SHA256);
- assertEquals(bytesToHexString(checksums[4].getValue()),
- "cf6eaee309cf906df5519b9a449ab136841cec62857e283fb4fd20dcd2ea14aa");
- assertEquals(checksums[5].getSplitName(), "config.xxxhdpi");
- assertEquals(checksums[5].getType(), TYPE_WHOLE_SHA256);
- assertEquals(bytesToHexString(checksums[5].getValue()),
- "e7c51a01794d33e13d005b62e5ae96a39215bc588e0a2ef8f6161e1e360a17cc");
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedDefaultChecksums() throws Exception {
- installPackage(TEST_FIXED_APK);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
- Checksums.TRUST_NONE);
- assertNotNull(checksums);
- assertEquals(0, checksums.length);
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedV1DefaultChecksums() throws Exception {
- installPackage(TEST_FIXED_APK_V1);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
- Checksums.TRUST_NONE);
- assertNotNull(checksums);
- assertEquals(0, checksums.length);
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedSha512DefaultChecksums() throws Exception {
- installPackage(TEST_FIXED_APK_V2_SHA512);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
- Checksums.TRUST_NONE);
- assertNotNull(checksums);
- assertEquals(0, checksums.length);
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedVerityDefaultChecksums() throws Exception {
- installPackage(TEST_FIXED_APK_VERITY);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
- Checksums.TRUST_NONE);
- assertNotNull(checksums);
- // No usable hashes as verity-in-v2-signature does not cover the whole file.
- assertEquals(0, checksums.length);
- }
-
- @LargeTest
- @Test
- public void testAllChecksums() throws Exception {
- Checksum[] checksums = getChecksums(V2V3_PACKAGE_NAME, true, ALL_CHECKSUMS,
- Checksums.TRUST_NONE);
- assertNotNull(checksums);
- assertEquals(5, checksums.length);
- assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums[0].getType());
- assertEquals(TYPE_WHOLE_MD5, checksums[1].getType());
- assertEquals(TYPE_WHOLE_SHA1, checksums[2].getType());
- assertEquals(TYPE_WHOLE_SHA256, checksums[3].getType());
- assertEquals(TYPE_WHOLE_SHA512, checksums[4].getType());
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedAllChecksums() throws Exception {
- installPackage(TEST_FIXED_APK);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS,
- Checksums.TRUST_NONE);
- validateFixedAllChecksums(checksums);
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedAllChecksumsDirectExecutor() throws Exception {
- installPackage(TEST_FIXED_APK);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(mContext, new Executor() {
- @Override
- public void execute(Runnable command) {
- command.run();
- }
- }, FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS, Checksums.TRUST_NONE);
- validateFixedAllChecksums(checksums);
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedAllChecksumsSingleThread() throws Exception {
- installPackage(TEST_FIXED_APK);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(mContext, Executors.newSingleThreadExecutor(),
- FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS, Checksums.TRUST_NONE);
- validateFixedAllChecksums(checksums);
- }
-
- private void validateFixedAllChecksums(Checksum[] checksums) {
- assertNotNull(checksums);
- assertEquals(5, checksums.length);
- assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums[0].getType());
- assertEquals("90553b8d221ab1b900b242a93e4cc659ace3a2ff1d5c62e502488b385854e66a",
- bytesToHexString(checksums[0].getValue()));
- assertEquals(TYPE_WHOLE_MD5, checksums[1].getType());
- assertEquals(TEST_FIXED_APK_MD5, bytesToHexString(checksums[1].getValue()));
- assertEquals(TYPE_WHOLE_SHA1, checksums[2].getType());
- assertEquals("331eef6bc57671de28cbd7e32089d047285ade6a",
- bytesToHexString(checksums[2].getValue()));
- assertEquals(TYPE_WHOLE_SHA256, checksums[3].getType());
- assertEquals(TEST_FIXED_APK_SHA256, bytesToHexString(checksums[3].getValue()));
- assertEquals(TYPE_WHOLE_SHA512, checksums[4].getType());
- assertEquals(TEST_FIXED_APK_SHA512, bytesToHexString(checksums[4].getValue()));
- }
-
- @SdkSuppress(minSdkVersion = 29)
- @LargeTest
- @Test
- public void testFixedV1AllChecksums() throws Exception {
- installPackage(TEST_FIXED_APK_V1);
- assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
-
- Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS,
- Checksums.TRUST_NONE);
- assertNotNull(checksums);
- assertEquals(5, checksums.length);
- assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums[0].getType());
- assertEquals("1e8f831ef35257ca30d11668520aaafc6da243e853531caabc3b7867986f8886",
- bytesToHexString(checksums[0].getValue()));
- assertEquals(TYPE_WHOLE_MD5, checksums[1].getType());
- assertEquals(bytesToHexString(checksums[1].getValue()), "78e51e8c51e4adc6870cd71389e0f3db");
- assertEquals(TYPE_WHOLE_SHA1, checksums[2].getType());
- assertEquals("f6654505f2274fd9bfc098b660cdfdc2e4da6d53",
- bytesToHexString(checksums[2].getValue()));
- assertEquals(TYPE_WHOLE_SHA256, checksums[3].getType());
- assertEquals("43755d36ec944494f6275ee92662aca95079b3aa6639f2d35208c5af15adff78",
- bytesToHexString(checksums[3].getValue()));
- assertEquals(TYPE_WHOLE_SHA512, checksums[4].getType());
- assertEquals("030fc815a4957c163af2bc6f30dd5b48ac09c94c25a824a514609e1476f91421"
- + "e2c8b6baa16ef54014ad6c5b90c37b26b0f5c8aeb01b63a1db2eca133091c8d1",
- bytesToHexString(checksums[4].getValue()));
- }
-
- private Checksum[] getChecksums(@NonNull String packageName, boolean includeSplits,
- @Checksum.Type int required, @NonNull List<Certificate> trustedInstallers)
- throws Exception {
- return getChecksums(mContext, mExecutor, packageName, includeSplits, required,
- trustedInstallers);
- }
-
private static Checksum[] getChecksums(@NonNull Context context, @NonNull Executor executor,
@NonNull String packageName,
boolean includeSplits,
@@ -357,111 +143,6 @@
return checksums;
}
- private void installPackage(String baseName) throws Exception {
- installSplits(new String[]{baseName});
- }
-
- void installSplits(String[] names) throws Exception {
- if (Build.VERSION.SDK_INT >= 24) {
- new InstallerApi24(mContext).installSplits(names);
- }
- }
-
- @RequiresApi(24)
- static class InstallerApi24 {
- private Context mContext;
-
- InstallerApi24(Context context) {
- mContext = context;
- }
-
- void installSplits(String[] names) throws Exception {
- getUiAutomation().adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGES);
- try {
- final PackageInstaller installer =
- mContext.getPackageManager().getPackageInstaller();
- final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-
- final int sessionId = installer.createSession(params);
- PackageInstaller.Session session = installer.openSession(sessionId);
-
- for (String name : names) {
- writeFileToSession(session, name, name);
- }
-
- commitSession(session);
- } finally {
- getUiAutomation().dropShellPermissionIdentity();
- }
- }
-
- private static void writeFileToSession(PackageInstaller.Session session, String name,
- String apk) throws IOException {
- try (OutputStream os = session.openWrite(name, 0, -1);
- InputStream is = getResourceAsStream(apk)) {
- assertNotNull(name, is);
- writeFullStream(is, os, -1);
- }
- }
-
- private void commitSession(PackageInstaller.Session session) throws Exception {
- final ResolvableFuture<Intent> result = ResolvableFuture.create();
-
- // Create a single-use broadcast receiver
- BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- context.unregisterReceiver(this);
- result.set(intent);
- }
- };
-
- // Create a matching intent-filter and register the receiver
- final int resultId = result.hashCode();
- final String action = "androidx.core.appdigest.COMMIT_COMPLETE." + resultId;
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(action);
- mContext.registerReceiver(broadcastReceiver, intentFilter);
-
- Intent intent = new Intent(action);
- PendingIntent sender = PendingIntent.getBroadcast(mContext, resultId, intent,
- PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
-
- session.commit(sender.getIntentSender());
-
- Intent commitResult = result.get();
- final int status = commitResult.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- assertEquals(commitResult.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + " OR "
- + commitResult.getExtras().get(Intent.EXTRA_INTENT),
- PackageInstaller.STATUS_SUCCESS, status);
- }
-
- static UiAutomation getUiAutomation() {
- return InstrumentationRegistry.getInstrumentation().getUiAutomation();
- }
-
- static String executeShellCommand(String command) throws IOException {
- final ParcelFileDescriptor stdout = getUiAutomation().executeShellCommand(command);
- try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) {
- return readFullStream(inputStream);
- }
- }
-
- static boolean isAppInstalled(final String packageName) throws IOException {
- final String commandResult = executeShellCommand("pm list packages");
- final int prefixLength = "package:".length();
- return Arrays.stream(commandResult.split("\\r?\\n"))
- .anyMatch(new Predicate<String>() {
- @Override
- public boolean test(String line) {
- return line.substring(prefixLength).equals(packageName);
- }
- });
- }
- }
-
public static InputStream getResourceAsStream(String name) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
}
@@ -498,16 +179,6 @@
executeShellCommand("pm uninstall " + packageName);
}
- private boolean isAppInstalled(String packageName) throws IOException {
- if (Build.VERSION.SDK_INT >= 24) {
- return InstallerApi24.isAppInstalled(packageName);
- }
- return false;
- }
-
- private static final char[] HEX_LOWER_CASE_DIGITS =
- {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
@NonNull
private static String bytesToHexString(byte[] array) {
int offset = 0;
@@ -536,4 +207,468 @@
}
return data;
}
+
+ @Before
+ public void onBefore() throws Exception {
+ mContext = ApplicationProvider.getApplicationContext();
+ mExecutor = Executors.newCachedThreadPool();
+ }
+
+ @After
+ public void onAfter() throws Exception {
+ uninstallPackageSilently(V4_PACKAGE_NAME);
+ assertFalse(isAppInstalled(V4_PACKAGE_NAME));
+ uninstallPackageSilently(FIXED_PACKAGE_NAME);
+ assertFalse(isAppInstalled(FIXED_PACKAGE_NAME));
+ }
+
+ @SmallTest
+ @Test
+ public void testDefaultChecksums() throws Exception {
+ Checksum[] checksums = getChecksums(V2V3_PACKAGE_NAME, true, 0, Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ if (BuildCompat.isAtLeastS()) {
+ assertEquals(1, checksums.length);
+ assertEquals(checksums[0].getType(),
+ android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256);
+ } else {
+ assertEquals(0, checksums.length);
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testSplitsDefaultChecksums() throws Exception {
+ installSplits(new String[]{TEST_V4_APK, TEST_V4_SPLIT0, TEST_V4_SPLIT1, TEST_V4_SPLIT2,
+ TEST_V4_SPLIT3, TEST_V4_SPLIT4});
+ assertTrue(isAppInstalled(V4_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(V4_PACKAGE_NAME, true, 0, Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ if (BuildCompat.isAtLeastS()) {
+ assertEquals(checksums.length, 6);
+ // v2/v3 signature use 1M merkle tree.
+ assertEquals(null, checksums[0].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[0].getType());
+ assertEquals("config.hdpi", checksums[1].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[1].getType());
+ assertEquals("config.mdpi", checksums[2].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[2].getType());
+ assertEquals("config.xhdpi", checksums[3].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[3].getType());
+ assertEquals("config.xxhdpi", checksums[4].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[4].getType());
+ assertEquals("config.xxxhdpi", checksums[5].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[5].getType());
+ } else {
+ assertEquals(0, checksums.length);
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testSplitsSha256() throws Exception {
+ installSplits(new String[]{TEST_V4_APK, TEST_V4_SPLIT0, TEST_V4_SPLIT1, TEST_V4_SPLIT2,
+ TEST_V4_SPLIT3, TEST_V4_SPLIT4});
+ assertTrue(isAppInstalled(V4_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(V4_PACKAGE_NAME, true, TYPE_WHOLE_SHA256,
+ Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ if (BuildCompat.isAtLeastS()) {
+ assertEquals(checksums.length, 12);
+ // v2/v3 signature use 1M merkle tree.
+ assertEquals(null, checksums[0].getSplitName());
+ assertEquals(TYPE_WHOLE_SHA256, checksums[0].getType());
+ assertEquals(bytesToHexString(checksums[0].getValue()),
+ "ce4ad41be1191ab3cdfef09ab6fb3c5d057e15cb3553661b393f770d9149f1cc");
+ assertEquals(null, checksums[1].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[1].getType());
+ assertEquals(checksums[2].getSplitName(), "config.hdpi");
+ assertEquals(checksums[2].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[2].getValue()),
+ "336a47c278f6b6c22abffefa6a62971fd0bd718d6947143e6ed1f6f6126a8196");
+ assertEquals("config.hdpi", checksums[3].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[3].getType());
+ assertEquals(checksums[4].getSplitName(), "config.mdpi");
+ assertEquals(checksums[4].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[4].getValue()),
+ "17fe9f85e6f29a7354932002c8bc4cb829e1f4acf7f30626bd298c810bb13215");
+ assertEquals("config.mdpi", checksums[5].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[5].getType());
+ assertEquals(checksums[6].getSplitName(), "config.xhdpi");
+ assertEquals(checksums[6].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[6].getValue()),
+ "71a0b0ac5970def7ad80071c909be1e446174a9b39ea5cbf3004db05f87bcc4b");
+ assertEquals("config.xhdpi", checksums[7].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[7].getType());
+ assertEquals(checksums[8].getSplitName(), "config.xxhdpi");
+ assertEquals(checksums[8].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[8].getValue()),
+ "cf6eaee309cf906df5519b9a449ab136841cec62857e283fb4fd20dcd2ea14aa");
+ assertEquals("config.xxhdpi", checksums[9].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[9].getType());
+ assertEquals(checksums[10].getSplitName(), "config.xxxhdpi");
+ assertEquals(checksums[10].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[10].getValue()),
+ "e7c51a01794d33e13d005b62e5ae96a39215bc588e0a2ef8f6161e1e360a17cc");
+ assertEquals("config.xxxhdpi", checksums[11].getSplitName());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[11].getType());
+ } else {
+ assertEquals(6, checksums.length);
+ assertEquals(checksums[0].getSplitName(), null);
+ assertEquals(checksums[0].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[0].getValue()),
+ "ce4ad41be1191ab3cdfef09ab6fb3c5d057e15cb3553661b393f770d9149f1cc");
+ assertEquals(checksums[1].getSplitName(), "config.hdpi");
+ assertEquals(checksums[1].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[1].getValue()),
+ "336a47c278f6b6c22abffefa6a62971fd0bd718d6947143e6ed1f6f6126a8196");
+ assertEquals(checksums[2].getSplitName(), "config.mdpi");
+ assertEquals(checksums[2].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[2].getValue()),
+ "17fe9f85e6f29a7354932002c8bc4cb829e1f4acf7f30626bd298c810bb13215");
+ assertEquals(checksums[3].getSplitName(), "config.xhdpi");
+ assertEquals(checksums[3].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[3].getValue()),
+ "71a0b0ac5970def7ad80071c909be1e446174a9b39ea5cbf3004db05f87bcc4b");
+ assertEquals(checksums[4].getSplitName(), "config.xxhdpi");
+ assertEquals(checksums[4].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[4].getValue()),
+ "cf6eaee309cf906df5519b9a449ab136841cec62857e283fb4fd20dcd2ea14aa");
+ assertEquals(checksums[5].getSplitName(), "config.xxxhdpi");
+ assertEquals(checksums[5].getType(), TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[5].getValue()),
+ "e7c51a01794d33e13d005b62e5ae96a39215bc588e0a2ef8f6161e1e360a17cc");
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedDefaultChecksums() throws Exception {
+ installPackage(TEST_FIXED_APK);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
+ Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ if (BuildCompat.isAtLeastS()) {
+ assertEquals(1, checksums.length);
+ // v2/v3 signature use 1M merkle tree.
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[0].getType());
+ assertEquals(TEST_FIXED_APK_V2_SHA256, bytesToHexString(checksums[0].getValue()));
+ assertNull(checksums[0].getInstallerCertificate());
+ } else {
+ assertEquals(0, checksums.length);
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedV1DefaultChecksums() throws Exception {
+ installPackage(TEST_FIXED_APK_V1);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
+ Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ assertEquals(0, checksums.length);
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedSha512DefaultChecksums() throws Exception {
+ installPackage(TEST_FIXED_APK_V2_SHA512);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
+ Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ if (BuildCompat.isAtLeastS()) {
+ assertEquals(1, checksums.length);
+ // v2/v3 signature use 1M merkle tree.
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512, checksums[0].getType());
+ assertEquals(bytesToHexString(checksums[0].getValue()),
+ "6b866e8a54a3e358dfc20007960fb96123845f6c6d6c45f5fddf88150d71677f"
+ + "4c3081a58921c88651f7376118aca312cf764b391cdfb8a18c6710f9f27916a0");
+ assertNull(checksums[0].getInstallerCertificate());
+ } else {
+ assertEquals(0, checksums.length);
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedVerityDefaultChecksums() throws Exception {
+ installPackage(TEST_FIXED_APK_VERITY);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, 0,
+ Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ // No usable hashes as verity-in-v2-signature does not cover the whole file.
+ assertEquals(0, checksums.length);
+ }
+
+ @LargeTest
+ @Test
+ public void testAllChecksums() throws Exception {
+ Checksum[] checksums = getChecksums(V2V3_PACKAGE_NAME, true, ALL_CHECKSUMS,
+ Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ if (BuildCompat.isAtLeastS()) {
+ assertEquals(checksums.length, 7);
+ assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums[0].getType());
+ assertEquals(TYPE_WHOLE_MD5, checksums[1].getType());
+ assertEquals(TYPE_WHOLE_SHA1, checksums[2].getType());
+ assertEquals(TYPE_WHOLE_SHA256, checksums[3].getType());
+ assertEquals(TYPE_WHOLE_SHA512, checksums[4].getType());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums[5].getType());
+ assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512, checksums[6].getType());
+ } else {
+ assertEquals(5, checksums.length);
+ assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums[0].getType());
+ assertEquals(TYPE_WHOLE_MD5, checksums[1].getType());
+ assertEquals(TYPE_WHOLE_SHA1, checksums[2].getType());
+ assertEquals(TYPE_WHOLE_SHA256, checksums[3].getType());
+ assertEquals(TYPE_WHOLE_SHA512, checksums[4].getType());
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedAllChecksums() throws Exception {
+ installPackage(TEST_FIXED_APK);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS,
+ Checksums.TRUST_NONE);
+ validateFixedAllChecksums(checksums);
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedAllChecksumsDirectExecutor() throws Exception {
+ installPackage(TEST_FIXED_APK);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(mContext, new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ command.run();
+ }
+ }, FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS, Checksums.TRUST_NONE);
+ validateFixedAllChecksums(checksums);
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedAllChecksumsSingleThread() throws Exception {
+ installPackage(TEST_FIXED_APK);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(mContext, Executors.newSingleThreadExecutor(),
+ FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS, Checksums.TRUST_NONE);
+ validateFixedAllChecksums(checksums);
+ }
+
+ @SdkSuppress(minSdkVersion = 29)
+ @LargeTest
+ @Test
+ public void testFixedV1AllChecksums() throws Exception {
+ installPackage(TEST_FIXED_APK_V1);
+ assertTrue(isAppInstalled(FIXED_PACKAGE_NAME));
+
+ Checksum[] checksums = getChecksums(FIXED_PACKAGE_NAME, true, ALL_CHECKSUMS,
+ Checksums.TRUST_NONE);
+ assertNotNull(checksums);
+ assertEquals(5, checksums.length);
+ assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums[0].getType());
+ assertEquals("1e8f831ef35257ca30d11668520aaafc6da243e853531caabc3b7867986f8886",
+ bytesToHexString(checksums[0].getValue()));
+ assertEquals(TYPE_WHOLE_MD5, checksums[1].getType());
+ assertEquals(bytesToHexString(checksums[1].getValue()), "78e51e8c51e4adc6870cd71389e0f3db");
+ assertEquals(TYPE_WHOLE_SHA1, checksums[2].getType());
+ assertEquals("f6654505f2274fd9bfc098b660cdfdc2e4da6d53",
+ bytesToHexString(checksums[2].getValue()));
+ assertEquals(TYPE_WHOLE_SHA256, checksums[3].getType());
+ assertEquals("43755d36ec944494f6275ee92662aca95079b3aa6639f2d35208c5af15adff78",
+ bytesToHexString(checksums[3].getValue()));
+ assertEquals(TYPE_WHOLE_SHA512, checksums[4].getType());
+ assertEquals("030fc815a4957c163af2bc6f30dd5b48ac09c94c25a824a514609e1476f91421"
+ + "e2c8b6baa16ef54014ad6c5b90c37b26b0f5c8aeb01b63a1db2eca133091c8d1",
+ bytesToHexString(checksums[4].getValue()));
+ }
+
+ private void validateFixedAllChecksums(Checksum[] checksums) {
+ assertNotNull(checksums);
+ if (BuildCompat.isAtLeastR()) {
+ assertEquals(checksums.length, 7);
+ assertEquals(checksums[0].getType(),
+ android.content.pm.Checksum.TYPE_WHOLE_MERKLE_ROOT_4K_SHA256);
+ assertEquals(bytesToHexString(checksums[0].getValue()),
+ "90553b8d221ab1b900b242a93e4cc659ace3a2ff1d5c62e502488b385854e66a");
+ assertEquals(checksums[1].getType(), android.content.pm.Checksum.TYPE_WHOLE_MD5);
+ assertEquals(bytesToHexString(checksums[1].getValue()), TEST_FIXED_APK_MD5);
+ assertEquals(checksums[2].getType(), android.content.pm.Checksum.TYPE_WHOLE_SHA1);
+ assertEquals(bytesToHexString(checksums[2].getValue()),
+ "331eef6bc57671de28cbd7e32089d047285ade6a");
+ assertEquals(checksums[3].getType(), android.content.pm.Checksum.TYPE_WHOLE_SHA256);
+ assertEquals(bytesToHexString(checksums[3].getValue()), TEST_FIXED_APK_SHA256);
+ assertEquals(checksums[4].getType(), android.content.pm.Checksum.TYPE_WHOLE_SHA512);
+ assertEquals(bytesToHexString(checksums[4].getValue()),
+ "b59467fe578ebc81974ab3aaa1e0d2a76fef3e4ea7212a6f2885cec1af5253571"
+ + "1e2e94496224cae3eba8dc992144ade321540ebd458ec5b9e6a4cc51170e018");
+ assertEquals(checksums[5].getType(),
+ android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256);
+ assertEquals(bytesToHexString(checksums[5].getValue()), TEST_FIXED_APK_V2_SHA256);
+ assertEquals(checksums[6].getType(),
+ android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512);
+ assertEquals(bytesToHexString(checksums[6].getValue()),
+ "ef80a8630283f60108e8557c924307d0ccdfb6bbbf2c0176bd49af342f43bc84"
+ + "5f2888afcb71524196dda0d6dd16a6a3292bb75b431b8ff74fb60d796e882f80");
+ } else {
+ assertEquals(5, checksums.length);
+ assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums[0].getType());
+ assertEquals("90553b8d221ab1b900b242a93e4cc659ace3a2ff1d5c62e502488b385854e66a",
+ bytesToHexString(checksums[0].getValue()));
+ assertEquals(TYPE_WHOLE_MD5, checksums[1].getType());
+ assertEquals(TEST_FIXED_APK_MD5, bytesToHexString(checksums[1].getValue()));
+ assertEquals(TYPE_WHOLE_SHA1, checksums[2].getType());
+ assertEquals("331eef6bc57671de28cbd7e32089d047285ade6a",
+ bytesToHexString(checksums[2].getValue()));
+ assertEquals(TYPE_WHOLE_SHA256, checksums[3].getType());
+ assertEquals(TEST_FIXED_APK_SHA256, bytesToHexString(checksums[3].getValue()));
+ assertEquals(TYPE_WHOLE_SHA512, checksums[4].getType());
+ assertEquals(TEST_FIXED_APK_SHA512, bytesToHexString(checksums[4].getValue()));
+ }
+ }
+
+ private Checksum[] getChecksums(@NonNull String packageName, boolean includeSplits,
+ @Checksum.Type int required, @NonNull List<Certificate> trustedInstallers)
+ throws Exception {
+ return getChecksums(mContext, mExecutor, packageName, includeSplits, required,
+ trustedInstallers);
+ }
+
+ private void installPackage(String baseName) throws Exception {
+ installSplits(new String[]{baseName});
+ }
+
+ void installSplits(String[] names) throws Exception {
+ if (Build.VERSION.SDK_INT >= 24) {
+ new InstallerApi24(mContext).installSplits(names);
+ }
+ }
+
+ private boolean isAppInstalled(String packageName) throws IOException {
+ if (Build.VERSION.SDK_INT >= 24) {
+ return InstallerApi24.isAppInstalled(packageName);
+ }
+ return false;
+ }
+
+ @RequiresApi(24)
+ static class InstallerApi24 {
+ private Context mContext;
+
+ InstallerApi24(Context context) {
+ mContext = context;
+ }
+
+ private static void writeFileToSession(PackageInstaller.Session session, String name,
+ String apk) throws IOException {
+ try (OutputStream os = session.openWrite(name, 0, -1);
+ InputStream is = getResourceAsStream(apk)) {
+ assertNotNull(name, is);
+ writeFullStream(is, os, -1);
+ }
+ }
+
+ static UiAutomation getUiAutomation() {
+ return InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ }
+
+ static String executeShellCommand(String command) throws IOException {
+ final ParcelFileDescriptor stdout = getUiAutomation().executeShellCommand(command);
+ try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) {
+ return readFullStream(inputStream);
+ }
+ }
+
+ static boolean isAppInstalled(final String packageName) throws IOException {
+ final String commandResult = executeShellCommand("pm list packages");
+ final int prefixLength = "package:".length();
+ return Arrays.stream(commandResult.split("\\r?\\n"))
+ .anyMatch(new Predicate<String>() {
+ @Override
+ public boolean test(String line) {
+ return line.substring(prefixLength).equals(packageName);
+ }
+ });
+ }
+
+ void installSplits(String[] names) throws Exception {
+ getUiAutomation().adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGES);
+ try {
+ final PackageInstaller installer =
+ mContext.getPackageManager().getPackageInstaller();
+ final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+
+ final int sessionId = installer.createSession(params);
+ PackageInstaller.Session session = installer.openSession(sessionId);
+
+ for (String name : names) {
+ writeFileToSession(session, name, name);
+ }
+
+ commitSession(session);
+ } finally {
+ getUiAutomation().dropShellPermissionIdentity();
+ }
+ }
+
+ private void commitSession(PackageInstaller.Session session) throws Exception {
+ final ResolvableFuture<Intent> result = ResolvableFuture.create();
+
+ // Create a single-use broadcast receiver
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ context.unregisterReceiver(this);
+ result.set(intent);
+ }
+ };
+
+ // Create a matching intent-filter and register the receiver
+ final int resultId = result.hashCode();
+ final String action = "androidx.core.appdigest.COMMIT_COMPLETE." + resultId;
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(action);
+ mContext.registerReceiver(broadcastReceiver, intentFilter);
+
+ Intent intent = new Intent(action);
+ PendingIntent sender = PendingIntent.getBroadcast(mContext, resultId, intent,
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+
+ session.commit(sender.getIntentSender());
+
+ Intent commitResult = result.get();
+ final int status = commitResult.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ assertEquals(commitResult.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + " OR "
+ + commitResult.getExtras().get(Intent.EXTRA_INTENT),
+ PackageInstaller.STATUS_SUCCESS, status);
+ }
+ }
}
diff --git a/core/core-appdigest/src/main/java/androidx/core/appdigest/Checksums.java b/core/core-appdigest/src/main/java/androidx/core/appdigest/Checksums.java
index 2046117..ff05b32 100644
--- a/core/core-appdigest/src/main/java/androidx/core/appdigest/Checksums.java
+++ b/core/core-appdigest/src/main/java/androidx/core/appdigest/Checksums.java
@@ -23,6 +23,7 @@
import static androidx.core.appdigest.Checksum.TYPE_WHOLE_SHA512;
import android.content.Context;
+import android.content.pm.ApkChecksum;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
@@ -30,8 +31,10 @@
import android.util.Pair;
import android.util.SparseArray;
+import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.NonNull;
import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.os.BuildCompat;
import androidx.core.util.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
@@ -115,6 +118,11 @@
Preconditions.checkNotNull(trustedInstallers);
Preconditions.checkNotNull(executor);
+ if (BuildCompat.isAtLeastS()) {
+ return ApiSImpl.getChecksums(context, packageName, includeSplits, required,
+ trustedInstallers, executor);
+ }
+
final ApplicationInfo applicationInfo =
context.getPackageManager().getApplicationInfo(packageName, 0);
if (applicationInfo == null) {
@@ -158,6 +166,56 @@
return result;
}
+ private static class ApiSImpl {
+ private ApiSImpl() {}
+
+ @ChecksSdkIntAtLeast(codename = "S") static
+ @NonNull ListenableFuture<Checksum[]> getChecksums(@NonNull Context context,
+ @NonNull String packageName, boolean includeSplits, @Checksum.Type int required,
+ @NonNull List<Certificate> trustedInstallers, @NonNull Executor executor)
+ throws CertificateEncodingException, PackageManager.NameNotFoundException {
+ final ResolvableFuture<Checksum[]> result = ResolvableFuture.create();
+
+ if (trustedInstallers == TRUST_ALL) {
+ trustedInstallers = PackageManager.TRUST_ALL;
+ } else if (trustedInstallers == TRUST_NONE) {
+ trustedInstallers = PackageManager.TRUST_NONE;
+ } else if (trustedInstallers.isEmpty()) {
+ throw new IllegalArgumentException(
+ "trustedInstallers has to be one of TRUST_ALL/TRUST_NONE or a non-empty "
+ + "list of certificates.");
+ }
+
+ context.getPackageManager().requestChecksums(packageName, includeSplits, required,
+ trustedInstallers, new PackageManager.OnChecksumsReadyListener() {
+ @Override
+ public void onChecksumsReady(List<ApkChecksum> apkChecksums) {
+ if (apkChecksums == null) {
+ result.setException(
+ new IllegalStateException("Checksums missing."));
+ return;
+ }
+
+ try {
+ Checksum[] checksums = new Checksum[apkChecksums.size()];
+ for (int i = 0, size = apkChecksums.size(); i < size; ++i) {
+ ApkChecksum apkChecksum = apkChecksums.get(i);
+ checksums[i] = new Checksum(apkChecksum.getSplitName(),
+ apkChecksum.getType(), apkChecksum.getValue(),
+ apkChecksum.getInstallerPackageName(),
+ apkChecksum.getInstallerCertificate());
+ }
+ result.set(checksums);
+ } catch (Throwable e) {
+ result.setException(e);
+ }
+ }
+ });
+
+ return result;
+ }
+ }
+
private static void getChecksumsSync(@NonNull List<Pair<String, File>> filesToChecksum,
@Checksum.Type int required, ResolvableFuture<Checksum[]> result) {
List<Checksum> allChecksums = new ArrayList<>();
diff --git a/core/core-google-shortcuts/build.gradle b/core/core-google-shortcuts/build.gradle
index 2608196..e27488b 100644
--- a/core/core-google-shortcuts/build.gradle
+++ b/core/core-google-shortcuts/build.gradle
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.LibraryType
diff --git a/core/core-ktx/lint-baseline.xml b/core/core-ktx/lint-baseline.xml
index 35e7c08..1d0ea88 100644
--- a/core/core-ktx/lint-baseline.xml
+++ b/core/core-ktx/lint-baseline.xml
@@ -333,6 +333,17 @@
<issue
id="NewApi"
+ message="Call requires API level S (current min is 14): `android.util.SparseArray#set`"
+ errorLine1=" array[1] = "one""
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="src/androidTest/java/androidx/core/util/SparseArrayTest.kt"
+ line="61"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="NewApi"
message="Call requires API level 17 (current min is 14): `updatePaddingRelative`"
errorLine1=" view.updatePaddingRelative(start = 10, end = 20)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
diff --git a/core/core-ktx/src/main/java/androidx/core/util/SparseArray.kt b/core/core-ktx/src/main/java/androidx/core/util/SparseArray.kt
index f2f373e..5d922f5 100644
--- a/core/core-ktx/src/main/java/androidx/core/util/SparseArray.kt
+++ b/core/core-ktx/src/main/java/androidx/core/util/SparseArray.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+@file:Suppress("NOTHING_TO_INLINE", "EXTENSION_SHADOWED_BY_MEMBER")
package androidx.core.util
diff --git a/core/core-remoteviews/api/current.txt b/core/core-remoteviews/api/current.txt
new file mode 100644
index 0000000..6d78713
--- /dev/null
+++ b/core/core-remoteviews/api/current.txt
@@ -0,0 +1,28 @@
+// Signature format: 4.0
+package androidx.core.widget {
+
+ public final class RemoteViewsCompat {
+ method public static void setRemoteAdapter(android.content.Context context, android.widget.RemoteViews remoteViews, int appWidgetId, @IdRes int viewId, androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems items);
+ field public static final androidx.core.widget.RemoteViewsCompat INSTANCE;
+ }
+
+ public static final class RemoteViewsCompat.RemoteCollectionItems {
+ method public int getItemCount();
+ method public long getItemId(int position);
+ method public android.widget.RemoteViews getItemView(int position);
+ method public int getViewTypeCount();
+ method public boolean hasStableIds();
+ property public final int itemCount;
+ property public final int viewTypeCount;
+ }
+
+ public static final class RemoteViewsCompat.RemoteCollectionItems.Builder {
+ ctor public RemoteViewsCompat.RemoteCollectionItems.Builder();
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder addItem(long id, android.widget.RemoteViews view);
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems build();
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder setHasStableIds(boolean hasStableIds);
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder setViewTypeCount(int viewTypeCount);
+ }
+
+}
+
diff --git a/core/core-remoteviews/api/public_plus_experimental_current.txt b/core/core-remoteviews/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..6d78713
--- /dev/null
+++ b/core/core-remoteviews/api/public_plus_experimental_current.txt
@@ -0,0 +1,28 @@
+// Signature format: 4.0
+package androidx.core.widget {
+
+ public final class RemoteViewsCompat {
+ method public static void setRemoteAdapter(android.content.Context context, android.widget.RemoteViews remoteViews, int appWidgetId, @IdRes int viewId, androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems items);
+ field public static final androidx.core.widget.RemoteViewsCompat INSTANCE;
+ }
+
+ public static final class RemoteViewsCompat.RemoteCollectionItems {
+ method public int getItemCount();
+ method public long getItemId(int position);
+ method public android.widget.RemoteViews getItemView(int position);
+ method public int getViewTypeCount();
+ method public boolean hasStableIds();
+ property public final int itemCount;
+ property public final int viewTypeCount;
+ }
+
+ public static final class RemoteViewsCompat.RemoteCollectionItems.Builder {
+ ctor public RemoteViewsCompat.RemoteCollectionItems.Builder();
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder addItem(long id, android.widget.RemoteViews view);
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems build();
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder setHasStableIds(boolean hasStableIds);
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder setViewTypeCount(int viewTypeCount);
+ }
+
+}
+
diff --git a/slice/slice-builders/ktx/api/res-current.txt b/core/core-remoteviews/api/res-current.txt
similarity index 100%
copy from slice/slice-builders/ktx/api/res-current.txt
copy to core/core-remoteviews/api/res-current.txt
diff --git a/core/core-remoteviews/api/restricted_current.txt b/core/core-remoteviews/api/restricted_current.txt
new file mode 100644
index 0000000..a081062
--- /dev/null
+++ b/core/core-remoteviews/api/restricted_current.txt
@@ -0,0 +1,32 @@
+// Signature format: 4.0
+package androidx.core.widget {
+
+ public final class RemoteViewsCompat {
+ method public static void setRemoteAdapter(android.content.Context context, android.widget.RemoteViews remoteViews, int appWidgetId, @IdRes int viewId, androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems items);
+ field public static final androidx.core.widget.RemoteViewsCompat INSTANCE;
+ }
+
+ public static final class RemoteViewsCompat.RemoteCollectionItems {
+ method public int getItemCount();
+ method public long getItemId(int position);
+ method public android.widget.RemoteViews getItemView(int position);
+ method public int getViewTypeCount();
+ method public boolean hasStableIds();
+ property public final int itemCount;
+ property public final int viewTypeCount;
+ }
+
+ public static final class RemoteViewsCompat.RemoteCollectionItems.Builder {
+ ctor public RemoteViewsCompat.RemoteCollectionItems.Builder();
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder addItem(long id, android.widget.RemoteViews view);
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems build();
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder setHasStableIds(boolean hasStableIds);
+ method public androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems.Builder setViewTypeCount(int viewTypeCount);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class RemoteViewsCompatService extends android.widget.RemoteViewsService {
+ method public android.widget.RemoteViewsService.RemoteViewsFactory onGetViewFactory(android.content.Intent intent);
+ }
+
+}
+
diff --git a/core/core-remoteviews/build.gradle b/core/core-remoteviews/build.gradle
new file mode 100644
index 0000000..12fd727
--- /dev/null
+++ b/core/core-remoteviews/build.gradle
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import androidx.build.LibraryType
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ api("androidx.annotation:annotation:1.2.0")
+ implementation(project(":core:core"))
+
+ androidTestImplementation(libs.kotlinStdlib)
+ androidTestImplementation(libs.kotlinTest)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
+}
+
+androidx {
+ name = "AndroidX RemoteViews Support"
+ type = LibraryType.PUBLISHED_LIBRARY
+ mavenVersion = LibraryVersions.CORE
+ mavenGroup = LibraryGroups.CORE
+ inceptionYear = "2021"
+ description = "AndroidX RemoteViews Support"
+}
diff --git a/core/core-remoteviews/lint-baseline.xml b/core/core-remoteviews/lint-baseline.xml
new file mode 100644
index 0000000..d145d5e
--- /dev/null
+++ b/core/core-remoteviews/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 16 (current min is 14): `android.appwidget.AppWidgetManager#bindAppWidgetIdIfAllowed`"
+ errorLine1=" val wasBound = appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, componentName)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidTest/java/androidx/core/widget/AppWidgetHostTestActivity.kt"
+ line="56"
+ column="41"/>
+ </issue>
+
+</issues>
diff --git a/core/core-remoteviews/src/androidTest/AndroidManifest.xml b/core/core-remoteviews/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..fc5bef8
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.core.remoteviews.test">
+
+ <application>
+ <activity
+ android:name="androidx.core.widget.AppWidgetHostTestActivity"
+ android:exported="true" />
+
+ <receiver
+ android:name="androidx.core.widget.TestAppWidgetProvider"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data
+ android:name="android.appwidget.provider"
+ android:resource="@xml/app_widget_info" />
+ </receiver>
+
+ </application>
+ <uses-permission android:name="android.permission.BIND_APPWIDGET" />
+</manifest>
diff --git a/core/core-remoteviews/src/androidTest/java/androidx/core/widget/AppWidgetHostTestActivity.kt b/core/core-remoteviews/src/androidTest/java/androidx/core/widget/AppWidgetHostTestActivity.kt
new file mode 100644
index 0000000..c5124cb
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/java/androidx/core/widget/AppWidgetHostTestActivity.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget
+
+import android.app.Activity
+import android.appwidget.AppWidgetHost
+import android.appwidget.AppWidgetHostView
+import android.appwidget.AppWidgetManager
+import android.content.ComponentName
+import android.os.Bundle
+import android.view.WindowManager
+import android.widget.FrameLayout
+import androidx.core.remoteviews.test.R
+import org.junit.Assert.fail
+
+/** Test activity that contains an [AppWidgetHost]. */
+public class AppWidgetHostTestActivity : Activity() {
+ private var mHost: AppWidgetHost? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ setContentView(R.layout.app_widget_host_activity)
+
+ mHost = AppWidgetHost(this, 1).also { it.startListening() }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ mHost?.stopListening()
+ mHost?.deleteHost()
+ mHost = null
+ }
+
+ public fun bindAppWidget(): AppWidgetHostView {
+ val host = mHost ?: error("App widgets can only be bound while the activity is created")
+
+ val appWidgetManager = AppWidgetManager.getInstance(this)
+ val appWidgetId = host.allocateAppWidgetId()
+ val componentName = ComponentName(this, TestAppWidgetProvider::class.java)
+
+ val wasBound = appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, componentName)
+ if (!wasBound) {
+ fail("Failed to bind the app widget")
+ }
+
+ val info = appWidgetManager.getAppWidgetInfo(appWidgetId)
+ val hostView = host.createView(this, appWidgetId, info)
+ val contentFrame = findViewById<FrameLayout>(R.id.content)
+ contentFrame.addView(
+ hostView,
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT
+ )
+ )
+
+ return hostView
+ }
+}
diff --git a/core/core-remoteviews/src/androidTest/java/androidx/core/widget/RemoteViewsCompatTest.kt b/core/core-remoteviews/src/androidTest/java/androidx/core/widget/RemoteViewsCompatTest.kt
new file mode 100644
index 0000000..6afde6e
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/java/androidx/core/widget/RemoteViewsCompatTest.kt
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget
+
+import android.Manifest.permission
+import android.app.PendingIntent
+import android.app.UiAutomation
+import android.appwidget.AppWidgetHostView
+import android.appwidget.AppWidgetManager
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Parcel
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver.OnDrawListener
+import android.widget.Adapter
+import android.widget.ListView
+import android.widget.RemoteViews
+import android.widget.TextView
+import androidx.core.os.BuildCompat
+import androidx.core.remoteviews.test.R
+import androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertFailsWith
+import kotlin.test.fail
+
+@SdkSuppress(minSdkVersion = 29)
+@MediumTest
+public class RemoteViewsCompatTest {
+ private val mUsingBackport = !BuildCompat.isAtLeastS()
+ private val mContext = ApplicationProvider.getApplicationContext<Context>()
+ private val mPackageName = mContext.packageName
+ private val mAppWidgetManager = AppWidgetManager.getInstance(mContext)
+
+ @Rule
+ @JvmField
+ public val mActivityTestRule: ActivityScenarioRule<AppWidgetHostTestActivity> =
+ ActivityScenarioRule(AppWidgetHostTestActivity::class.java)
+
+ private lateinit var mRemoteViews: RemoteViews
+ private lateinit var mHostView: AppWidgetHostView
+ private var mAppWidgetId = 0
+
+ private val mUiAutomation: UiAutomation
+ get() = InstrumentationRegistry.getInstrumentation().uiAutomation
+
+ private val mListView: ListView
+ get() = mHostView.getChildAt(0) as ListView
+
+ @Before
+ public fun setUp() {
+ mUiAutomation.adoptShellPermissionIdentity(permission.BIND_APPWIDGET)
+
+ mActivityTestRule.scenario.onActivity { activity ->
+ mHostView = activity.bindAppWidget()
+ }
+
+ mAppWidgetId = mHostView.appWidgetId
+ mRemoteViews = RemoteViews(mPackageName, R.layout.remote_views_list)
+ mAppWidgetManager.updateAppWidget(mAppWidgetId, mRemoteViews)
+
+ // Wait until the remote views has been added to the host view.
+ observeDrawUntil { mHostView.childCount > 0 }
+ }
+
+ @After
+ public fun tearDown() {
+ mUiAutomation.dropShellPermissionIdentity()
+ }
+
+ @Test
+ public fun testParcelingAndUnparceling() {
+ val items = RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .setViewTypeCount(10)
+ .addItem(id = 3, RemoteViews(mPackageName, R.layout.list_view_row))
+ .addItem(id = 5, RemoteViews(mPackageName, R.layout.list_view_row2))
+ .build()
+
+ val parcel = Parcel.obtain()
+ val unparceled = try {
+ items.writeToParcel(parcel, /* flags= */ 0)
+ parcel.setDataPosition(0)
+ RemoteCollectionItems(parcel)
+ } finally {
+ parcel.recycle()
+ }
+
+ assertThat(unparceled.itemCount).isEqualTo(2)
+ assertThat(unparceled.getItemId(0)).isEqualTo(3)
+ assertThat(unparceled.getItemId(1)).isEqualTo(5)
+ assertThat(unparceled.getItemView(0).layoutId).isEqualTo(R.layout.list_view_row)
+ assertThat(unparceled.getItemView(1).layoutId).isEqualTo(R.layout.list_view_row2)
+ assertThat(unparceled.hasStableIds()).isTrue()
+ assertThat(unparceled.viewTypeCount).isEqualTo(10)
+ }
+
+ @Test
+ public fun testBuilder_empty() {
+ val items = RemoteCollectionItems.Builder().build()
+
+ assertThat(items.itemCount).isEqualTo(0)
+ assertThat(items.viewTypeCount).isEqualTo(1)
+ assertThat(items.hasStableIds()).isFalse()
+ }
+
+ @Test
+ public fun testBuilder_viewTypeCountUnspecified() {
+ val firstItem = RemoteViews(mPackageName, R.layout.list_view_row)
+ val secondItem = RemoteViews(mPackageName, R.layout.list_view_row2)
+ val items = RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .addItem(id = 3, firstItem)
+ .addItem(id = 5, secondItem)
+ .build()
+
+ assertThat(items.itemCount).isEqualTo(2)
+ assertThat(items.getItemId(0)).isEqualTo(3)
+ assertThat(items.getItemId(1)).isEqualTo(5)
+ assertThat(items.getItemView(0).layoutId).isEqualTo(R.layout.list_view_row)
+ assertThat(items.getItemView(1).layoutId).isEqualTo(R.layout.list_view_row2)
+ assertThat(items.hasStableIds()).isTrue()
+ // The view type count should be derived from the number of different layout ids if
+ // unspecified.
+ assertThat(items.viewTypeCount).isEqualTo(2)
+ }
+
+ @Test
+ public fun testBuilder_viewTypeCountSpecified() {
+ val firstItem = RemoteViews(mPackageName, R.layout.list_view_row)
+ val secondItem = RemoteViews(mPackageName, R.layout.list_view_row2)
+ val items = RemoteCollectionItems.Builder()
+ .addItem(id = 3, firstItem)
+ .addItem(id = 5, secondItem)
+ .setViewTypeCount(15)
+ .build()
+
+ assertThat(items.viewTypeCount).isEqualTo(15)
+ }
+
+ @Test
+ public fun testBuilder_repeatedIdsAndLayouts() {
+ val firstItem = RemoteViews(mPackageName, R.layout.list_view_row)
+ val secondItem = RemoteViews(mPackageName, R.layout.list_view_row)
+ val thirdItem = RemoteViews(mPackageName, R.layout.list_view_row)
+ val items = RemoteCollectionItems.Builder()
+ .setHasStableIds(false)
+ .addItem(id = 42, firstItem)
+ .addItem(id = 42, secondItem)
+ .addItem(id = 42, thirdItem)
+ .build()
+
+ assertThat(items.itemCount).isEqualTo(3)
+ assertThat(items.getItemId(0)).isEqualTo(42)
+ assertThat(items.getItemId(1)).isEqualTo(42)
+ assertThat(items.getItemId(2)).isEqualTo(42)
+ assertThat(items.getItemView(0)).isSameInstanceAs(firstItem)
+ assertThat(items.getItemView(1)).isSameInstanceAs(secondItem)
+ assertThat(items.getItemView(2)).isSameInstanceAs(thirdItem)
+ assertThat(items.hasStableIds()).isFalse()
+ assertThat(items.viewTypeCount).isEqualTo(1)
+ }
+
+ @Test
+ public fun testBuilder_viewTypeCountLowerThanLayoutCount() {
+ assertFailsWith(IllegalArgumentException::class) {
+ RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .setViewTypeCount(1)
+ .addItem(3, RemoteViews(mPackageName, R.layout.list_view_row))
+ .addItem(5, RemoteViews(mPackageName, R.layout.list_view_row2))
+ .build()
+ }
+ }
+
+ @Test
+ public fun testServiceIntent_hasSameUriForSameIds() {
+ val intent1 = RemoteViewsCompatService.createIntent(mContext, appWidgetId = 1, viewId = 42)
+ val intent2 = RemoteViewsCompatService.createIntent(mContext, appWidgetId = 1, viewId = 42)
+
+ assertThat(intent1.data).isEqualTo(intent2.data)
+ }
+
+ @Test
+ public fun testServiceIntent_hasDifferentUriForDifferentWidgetIds() {
+ val intent1 = RemoteViewsCompatService.createIntent(mContext, appWidgetId = 1, viewId = 42)
+ val intent2 = RemoteViewsCompatService.createIntent(mContext, appWidgetId = 2, viewId = 42)
+
+ assertThat(intent1.data).isNotEqualTo(intent2.data)
+ }
+
+ @Test
+ public fun testServiceIntent_hasDifferentUriForDifferentViewIds() {
+ val intent1 = RemoteViewsCompatService.createIntent(mContext, appWidgetId = 1, viewId = 42)
+ val intent2 = RemoteViewsCompatService.createIntent(mContext, appWidgetId = 1, viewId = 43)
+
+ assertThat(intent1.data).isNotEqualTo(intent2.data)
+ }
+
+ @Test
+ public fun testSetRemoteAdapter_emptyCollection() {
+ val items = RemoteCollectionItems.Builder().build()
+
+ RemoteViewsCompat.setRemoteAdapter(
+ mContext,
+ mRemoteViews,
+ mAppWidgetId,
+ R.id.list_view,
+ items
+ )
+ mAppWidgetManager.updateAppWidget(mAppWidgetId, mRemoteViews)
+
+ observeDrawUntil { mListView.adapter != null }
+
+ assertThat(mListView.childCount).isEqualTo(0)
+ assertThat(mListView.adapter.count).isEqualTo(0)
+ assertThat(mListView.adapter.viewTypeCount).isAtLeast(1)
+ assertThat(mListView.adapter.hasStableIds()).isFalse()
+ }
+
+ @Test
+ public fun testSetRemoteAdapter_withItems() {
+ val items = RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .addItem(id = 10, createTextRow("Hello"))
+ .addItem(id = 11, createTextRow("World"))
+ .build()
+
+ RemoteViewsCompat.setRemoteAdapter(
+ mContext,
+ mRemoteViews,
+ mAppWidgetId,
+ R.id.list_view,
+ items
+ )
+ mAppWidgetManager.updateAppWidget(mAppWidgetId, mRemoteViews)
+
+ observeDrawUntil { mListView.adapter != null && mListView.childCount == 2 }
+
+ val adapter = mListView.adapter
+ assertThat(adapter.count).isEqualTo(2)
+ assertThat(adapter.getItemViewType(1)).isEqualTo(adapter.getItemViewType(0))
+ assertThat(adapter.getItemId(0)).isEqualTo(10)
+ assertThat(adapter.getItemId(1)).isEqualTo(11)
+
+ assertThat(mListView.adapter.hasStableIds()).isTrue()
+ assertThat(mListView.childCount).isEqualTo(2)
+ assertThat(getListChildAt<TextView>(0).text.toString()).isEqualTo("Hello")
+ assertThat(getListChildAt<TextView>(1).text.toString()).isEqualTo("World")
+ }
+
+ @Test
+ public fun testSetRemoteAdapter_clickListener() {
+ val action = "my-action"
+ val receiver = TestBroadcastReceiver()
+ mContext.registerReceiver(receiver, IntentFilter(action))
+ val pendingIntent = PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ Intent(action).setPackage(mPackageName),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
+ )
+ mRemoteViews.setPendingIntentTemplate(R.id.list_view, pendingIntent)
+
+ val item2 = RemoteViews(mPackageName, R.layout.list_view_row2)
+ item2.setTextViewText(R.id.text, "Clickable")
+ item2.setOnClickFillInIntent(R.id.text, Intent().putExtra("my-extra", 42))
+
+ val items = RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .addItem(id = 10, createTextRow("Hello"))
+ .addItem(id = 11, createTextRow("World"))
+ .addItem(id = 12, item2)
+ .build()
+ RemoteViewsCompat.setRemoteAdapter(
+ mContext,
+ mRemoteViews,
+ mAppWidgetId,
+ R.id.list_view,
+ items
+ )
+ mAppWidgetManager.updateAppWidget(mAppWidgetId, mRemoteViews)
+ observeDrawUntil { mListView.adapter != null && mListView.childCount == 3 }
+
+ val adapter: Adapter = mListView.adapter
+ assertThat(adapter.count).isEqualTo(3)
+ assertThat(adapter.getItemViewType(0)).isEqualTo(adapter.getItemViewType(1))
+ assertThat(adapter.getItemViewType(0)).isNotEqualTo(adapter.getItemViewType(2))
+ assertThat(adapter.getItemId(0)).isEqualTo(10)
+ assertThat(adapter.getItemId(1)).isEqualTo(11)
+ assertThat(adapter.getItemId(2)).isEqualTo(12)
+ assertThat(adapter.hasStableIds()).isTrue()
+
+ assertThat(mListView.childCount).isEqualTo(3)
+ val textView2 = getListChildAt<ViewGroup>(2).getChildAt(0) as TextView
+ assertThat(getListChildAt<TextView>(0).text.toString()).isEqualTo("Hello")
+ assertThat(getListChildAt<TextView>(1).text.toString()).isEqualTo("World")
+ assertThat(textView2.text.toString()).isEqualTo("Clickable")
+
+ // View being clicked should launch the intent.
+ val receiverIntent = receiver.runAndAwaitIntentReceived {
+ textView2.performClick()
+ }
+ assertThat(receiverIntent.getIntExtra("my-extra", 0)).isEqualTo(42)
+ mContext.unregisterReceiver(receiver)
+ }
+
+ @Test
+ public fun testSetRemoteAdapter_multipleCalls() {
+ var items = RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .addItem(id = 10, createTextRow("Hello"))
+ .addItem(id = 11, createTextRow("World"))
+ .build()
+ RemoteViewsCompat.setRemoteAdapter(
+ mContext,
+ mRemoteViews,
+ mAppWidgetId,
+ R.id.list_view,
+ items
+ )
+ mAppWidgetManager.updateAppWidget(mAppWidgetId, mRemoteViews)
+ observeDrawUntil { mListView.adapter != null && mListView.childCount == 2 }
+
+ items = RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .addItem(id = 20, createTextRow("Bonjour"))
+ .addItem(id = 21, createTextRow("le"))
+ .addItem(id = 22, createTextRow("monde"))
+ .build()
+ RemoteViewsCompat.setRemoteAdapter(
+ mContext,
+ mRemoteViews,
+ mAppWidgetId,
+ R.id.list_view,
+ items
+ )
+ mAppWidgetManager.updateAppWidget(mAppWidgetId, mRemoteViews)
+ observeDrawUntil { mListView.childCount == 3 }
+
+ val adapter: Adapter = mListView.adapter
+ assertThat(adapter.count).isEqualTo(3)
+ assertThat(adapter.getItemId(0)).isEqualTo(20)
+ assertThat(adapter.getItemId(1)).isEqualTo(21)
+ assertThat(adapter.getItemId(2)).isEqualTo(22)
+
+ assertThat(mListView.childCount).isEqualTo(3)
+ assertThat(getListChildAt<TextView>(0).text.toString()).isEqualTo("Bonjour")
+ assertThat(getListChildAt<TextView>(1).text.toString()).isEqualTo("le")
+ assertThat(getListChildAt<TextView>(2).text.toString()).isEqualTo("monde")
+ }
+
+ private fun createTextRow(text: String): RemoteViews {
+ return RemoteViews(mPackageName, R.layout.list_view_row)
+ .also { it.setTextViewText(R.id.text, text) }
+ }
+
+ private fun observeDrawUntil(test: () -> Boolean) {
+ val latch = CountDownLatch(1)
+ val onDrawListener = OnDrawListener {
+ if (test()) latch.countDown()
+ }
+
+ mActivityTestRule.scenario.onActivity {
+ mHostView.viewTreeObserver.addOnDrawListener(onDrawListener)
+ }
+
+ val countedDown = latch.await(5, TimeUnit.SECONDS)
+
+ mActivityTestRule.scenario.onActivity {
+ mHostView.viewTreeObserver.removeOnDrawListener(onDrawListener)
+ }
+
+ if (!countedDown && !test()) {
+ fail("Expected condition to be met within 5 seconds")
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ private fun <V : View> getListChildAt(position: Int): V {
+ return if (mUsingBackport) {
+ // When using RemoteViewsAdapter, an extra wrapper FrameLayout is added.
+ (mListView.getChildAt(position) as ViewGroup).getChildAt(0) as V
+ } else {
+ mListView.getChildAt(position) as V
+ }
+ }
+
+ private inner class TestBroadcastReceiver : BroadcastReceiver() {
+ private lateinit var mCountDownLatch: CountDownLatch
+
+ private var mIntent: Intent? = null
+
+ override fun onReceive(context: Context, intent: Intent) {
+ mIntent = intent
+ mCountDownLatch.countDown()
+ }
+
+ fun runAndAwaitIntentReceived(runnable: () -> Unit): Intent {
+ mCountDownLatch = CountDownLatch(1)
+
+ mActivityTestRule.scenario.onActivity { runnable() }
+
+ mCountDownLatch.await(5, TimeUnit.SECONDS)
+
+ return mIntent ?: fail("Expected intent to be received within five seconds")
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/core-remoteviews/src/androidTest/java/androidx/core/widget/TestAppWidgetProvider.kt b/core/core-remoteviews/src/androidTest/java/androidx/core/widget/TestAppWidgetProvider.kt
new file mode 100644
index 0000000..551595e
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/java/androidx/core/widget/TestAppWidgetProvider.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget
+
+import android.appwidget.AppWidgetProvider
+
+public class TestAppWidgetProvider : AppWidgetProvider()
\ No newline at end of file
diff --git a/core/core-remoteviews/src/androidTest/res/layout/app_widget_host_activity.xml b/core/core-remoteviews/src/androidTest/res/layout/app_widget_host_activity.xml
new file mode 100644
index 0000000..4ad8573
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/res/layout/app_widget_host_activity.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/core/core-remoteviews/src/androidTest/res/layout/list_view_row.xml b/core/core-remoteviews/src/androidTest/res/layout/list_view_row.xml
new file mode 100644
index 0000000..c7fda32
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/res/layout/list_view_row.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"/>
\ No newline at end of file
diff --git a/core/core-remoteviews/src/androidTest/res/layout/list_view_row2.xml b/core/core-remoteviews/src/androidTest/res/layout/list_view_row2.xml
new file mode 100644
index 0000000..2da2e68
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/res/layout/list_view_row2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"/>
+</FrameLayout>
diff --git a/core/core-remoteviews/src/androidTest/res/layout/remote_views_list.xml b/core/core-remoteviews/src/androidTest/res/layout/remote_views_list.xml
new file mode 100644
index 0000000..e6ce819
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/res/layout/remote_views_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/core/core-remoteviews/src/androidTest/res/xml/app_widget_info.xml b/core/core-remoteviews/src/androidTest/res/xml/app_widget_info.xml
new file mode 100644
index 0000000..a1f8eae
--- /dev/null
+++ b/core/core-remoteviews/src/androidTest/res/xml/app_widget_info.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="40dp"
+ android:minHeight="40dp"
+ android:initialLayout="@layout/remote_views_list"
+ android:resizeMode="horizontal|vertical"
+ android:widgetCategory="home_screen">
+</appwidget-provider>
\ No newline at end of file
diff --git a/core/core-remoteviews/src/main/AndroidManifest.xml b/core/core-remoteviews/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9a694b6
--- /dev/null
+++ b/core/core-remoteviews/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest package="androidx.core.remoteviews" xmlns:android="http://schemas.android.com/apk/res/android">
+ <application>
+ <service android:name="androidx.core.widget.RemoteViewsCompatService"
+ android:permission="android.permission.BIND_REMOTEVIEWS"/>
+ </application>
+</manifest>
diff --git a/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompat.kt b/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompat.kt
new file mode 100644
index 0000000..0cf7f8e
--- /dev/null
+++ b/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompat.kt
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget
+
+import android.annotation.SuppressLint
+import android.appwidget.AppWidgetManager
+import android.content.Context
+import android.os.Parcel
+import android.os.Parcelable
+import android.widget.RemoteViews
+import androidx.annotation.DoNotInline
+import androidx.annotation.IdRes
+import androidx.annotation.RequiresApi
+import androidx.core.os.BuildCompat
+
+/**
+ * Helper for accessing features in [RemoteViews].
+ */
+public object RemoteViewsCompat {
+ /**
+ * Creates a simple Adapter for the widgetId and viewId specified. The viewId must point to an
+ * AdapterView, ie. [android.widget.ListView], [android.widget.GridView],
+ * [android.widget.StackView], or [android.widget.AdapterViewAnimator].
+ *
+ * This is a simpler but less flexible approach to populating collection widgets. Its use is
+ * encouraged for most scenarios, as long as the total memory within the list of RemoteViews
+ * is relatively small (ie. doesn't contain large or numerous Bitmaps, see
+ * [RemoteViews.setImageViewBitmap]). In the case of numerous images, the use of API is
+ * still possible by setting image URIs instead of Bitmaps, see [RemoteViews.setImageViewUri].
+ *
+ * If you use this API, you should not call
+ * [AppWidgetManager.notifyAppWidgetViewDataChanged] and should instead update
+ * your app widget, calling this method with the new [RemoteCollectionItems].
+ *
+ * @param context The [Context] of the app providing the widget.
+ * @param remoteViews The [RemoteViews] to receive the adapter.
+ * @param appWidgetId the id of the widget for which the adapter is being set.
+ * @param viewId The id of the [android.widget.AdapterView].
+ * @param items The items to display in the [android.widget.AdapterView].
+ */
+ @JvmStatic
+ public fun setRemoteAdapter(
+ context: Context,
+ remoteViews: RemoteViews,
+ appWidgetId: Int,
+ @IdRes viewId: Int,
+ items: RemoteCollectionItems
+ ) {
+ if (BuildCompat.isAtLeastS()) {
+ try {
+ Api31Impl.setRemoteAdapter(remoteViews, viewId, items)
+ return
+ } catch (e: LinkageError) {
+ // This will occur if the API doesn't exist yet on this version of S. We can simply
+ // fall back to the approach we use on pre-S devices.
+ }
+ }
+ val intent = RemoteViewsCompatService.createIntent(context, appWidgetId, viewId)
+ check(context.packageManager.resolveService(intent, /* flags= */ 0) != null) {
+ "RemoteViewsCompatService could not be resolved, ensure that you have declared it in " +
+ "your app manifest."
+ }
+ remoteViews.setRemoteAdapter(viewId, intent)
+ RemoteViewsCompatService.saveItems(context, appWidgetId, viewId, items)
+ AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(appWidgetId, viewId)
+ }
+
+ /** Representation of a fixed list of items to be displayed in a RemoteViews collection. */
+ public class RemoteCollectionItems {
+ private val mIds: LongArray
+ private val mViews: Array<RemoteViews>
+ private val mHasStableIds: Boolean
+ private val mViewTypeCount: Int
+
+ internal constructor(
+ ids: LongArray,
+ views: Array<RemoteViews>,
+ hasStableIds: Boolean,
+ viewTypeCount: Int
+ ) {
+ mIds = ids
+ mViews = views
+ mHasStableIds = hasStableIds
+ mViewTypeCount = viewTypeCount
+
+ require(ids.size == views.size) {
+ "RemoteCollectionItems has different number of ids and views"
+ }
+ require(viewTypeCount >= 1) { "View type count must be >= 1" }
+
+ val layoutIdCount = views.map { it.layoutId }.distinct().count()
+ require(layoutIdCount <= viewTypeCount) {
+ "View type count is set to $viewTypeCount, but the collection contains " +
+ "$layoutIdCount different layout ids"
+ }
+ }
+
+ /** @hide */
+ internal constructor(parcel: Parcel) {
+ val length = parcel.readInt()
+ mIds = LongArray(length)
+ parcel.readLongArray(mIds)
+ mViews = parcel.readNonNullTypedArray(length, RemoteViews.CREATOR)
+ mHasStableIds = parcel.readInt() == 1
+ mViewTypeCount = parcel.readInt()
+ }
+
+ /** @hide */
+ internal fun writeToParcel(dest: Parcel, flags: Int) {
+ dest.writeInt(mIds.size)
+ dest.writeLongArray(mIds)
+ dest.writeTypedArray(mViews, flags)
+ dest.writeInt(if (mHasStableIds) 1 else 0)
+ dest.writeInt(mViewTypeCount)
+ }
+
+ /**
+ * Returns the id for [position]. See [hasStableIds] for whether this id should be
+ * considered meaningful across collection updates.
+ *
+ * @return Id for the position.
+ */
+ public fun getItemId(position: Int): Long = mIds[position]
+
+ /**
+ * Returns the [RemoteViews] to display at [position].
+ *
+ * @return RemoteViews for the position.
+ */
+ public fun getItemView(position: Int): RemoteViews = mViews[position]
+
+ /**
+ * Returns the number of elements in the collection.
+ *
+ * @return Count of items.
+ */
+ public val itemCount: Int
+ get() = mIds.size
+
+ /**
+ * Returns the view type count for the collection when used in an adapter
+ *
+ * @return Count of view types for the collection when used in an adapter.
+ * @see android.widget.Adapter.getViewTypeCount
+ */
+ public val viewTypeCount: Int
+ get() = mViewTypeCount
+
+ /**
+ * Indicates whether the item ids are stable across changes to the underlying data.
+ *
+ * @return True if the same id always refers to the same object.
+ * @see android.widget.Adapter.hasStableIds
+ */
+ public fun hasStableIds(): Boolean = mHasStableIds
+
+ /** Builder class for [RemoteCollectionItems] objects. */
+ public class Builder {
+ private val mIds = arrayListOf<Long>()
+ private val mViews = arrayListOf<RemoteViews>()
+ private var mHasStableIds = false
+ private var mViewTypeCount = 0
+
+ /**
+ * Adds a [RemoteViews] to the collection.
+ *
+ * @param id Id to associate with the row. Use [.setHasStableIds] to
+ * indicate that ids are stable across changes to the collection.
+ * @param view RemoteViews to display for the row.
+ */
+ // Covered by getItemId, getItemView, getItemCount.
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public fun addItem(id: Long, view: RemoteViews): Builder {
+ mIds.add(id)
+ mViews.add(view)
+ return this
+ }
+
+ /**
+ * Sets whether the item ids are stable across changes to the underlying data.
+ *
+ * @see android.widget.Adapter.hasStableIds
+ */
+ public fun setHasStableIds(hasStableIds: Boolean): Builder {
+ mHasStableIds = hasStableIds
+ return this
+ }
+
+ /**
+ * Sets the view type count for the collection when used in an adapter. This can be set
+ * to the maximum number of different layout ids that will be used by RemoteViews in
+ * this collection.
+ *
+ * If this value is not set, then a value will be inferred from the provided items. As
+ * a result, the adapter may need to be recreated when the list is updated with
+ * previously unseen RemoteViews layouts for new items.
+ *
+ * @see android.widget.Adapter.getViewTypeCount
+ */
+ public fun setViewTypeCount(viewTypeCount: Int): Builder {
+ mViewTypeCount = viewTypeCount
+ return this
+ }
+
+ /** Creates the [RemoteCollectionItems] defined by this builder. */
+ public fun build(): RemoteCollectionItems {
+ if (mViewTypeCount < 1) {
+ // If a view type count wasn't specified, set it to be the number of distinct
+ // layout ids used in the items.
+ mViewTypeCount = mViews.map { it.layoutId }.distinct().count()
+ }
+ return RemoteCollectionItems(
+ mIds.toLongArray(),
+ mViews.toTypedArray(),
+ mHasStableIds,
+ maxOf(mViewTypeCount, 1)
+ )
+ }
+ }
+
+ private companion object {
+ /** Reads a non-null array of [T] of [size] from the [Parcel]. */
+ inline fun <reified T : Any> Parcel.readNonNullTypedArray(
+ size: Int,
+ creator: Parcelable.Creator<T>
+ ): Array<T> {
+ val array = arrayOfNulls<T?>(size)
+ readTypedArray(array, creator)
+ return array.requireNoNulls()
+ }
+ }
+ }
+
+ /**
+ * Version-specific static inner class to avoid verification errors that negatively affect
+ * run-time performance.
+ */
+ @RequiresApi(31)
+ private object Api31Impl {
+ @DoNotInline
+ fun setRemoteAdapter(remoteViews: RemoteViews, viewId: Int, items: RemoteCollectionItems) {
+ remoteViews.setRemoteAdapter(viewId, toPlatformCollectionItems(items))
+ }
+
+ /**
+ * Returns a [RemoteViews.RemoteCollectionItems] equivalent to this [RemoteCollectionItems].
+ */
+ @DoNotInline
+ private fun toPlatformCollectionItems(
+ items: RemoteCollectionItems
+ ): RemoteViews.RemoteCollectionItems {
+ return RemoteViews.RemoteCollectionItems.Builder()
+ .setHasStableIds(items.hasStableIds())
+ .setViewTypeCount(items.viewTypeCount)
+ .also { builder ->
+ repeat(items.itemCount) { index ->
+ builder.addItem(items.getItemId(index), items.getItemView(index))
+ }
+ }
+ .build()
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompatService.kt b/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompatService.kt
new file mode 100644
index 0000000..46b257b
--- /dev/null
+++ b/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompatService.kt
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget
+
+import android.appwidget.AppWidgetManager
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.Base64
+import android.util.Log
+import android.widget.RemoteViews
+import android.widget.RemoteViewsService
+import androidx.annotation.RestrictTo
+import androidx.core.content.pm.PackageInfoCompat
+import androidx.core.widget.RemoteViewsCompat.RemoteCollectionItems
+
+/**
+ * [RemoteViewsService] to provide [RemoteViews] set using [RemoteViewsCompat.setRemoteAdapter].
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class RemoteViewsCompatService : RemoteViewsService() {
+ override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
+ val appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
+ check(appWidgetId != -1) { "No app widget id was present in the intent" }
+
+ val viewId = intent.getIntExtra(EXTRA_VIEW_ID, -1)
+ check(viewId != -1) { "No view id was present in the intent" }
+
+ return RemoteViewsCompatServiceViewFactory(this, appWidgetId, viewId)
+ }
+
+ private class RemoteViewsCompatServiceViewFactory(
+ private val mContext: Context,
+ private val mAppWidgetId: Int,
+ private val mViewId: Int
+ ) : RemoteViewsFactory {
+ private var mItems = EMPTY
+
+ override fun onCreate() = loadData()
+
+ override fun onDataSetChanged() = loadData()
+
+ private fun loadData() {
+ mItems = RemoteViewsCompatServiceData.load(mContext, mAppWidgetId, mViewId) ?: EMPTY
+ }
+
+ override fun onDestroy() {}
+
+ override fun getCount() = mItems.itemCount
+
+ override fun getViewAt(position: Int) = mItems.getItemView(position)
+
+ override fun getLoadingView() = null
+
+ override fun getViewTypeCount() = mItems.viewTypeCount
+
+ override fun getItemId(position: Int): Long {
+ return mItems.getItemId(position)
+ }
+
+ override fun hasStableIds() = mItems.hasStableIds()
+
+ companion object {
+ private val EMPTY = RemoteCollectionItems(
+ ids = longArrayOf(),
+ views = emptyArray(),
+ hasStableIds = false,
+ viewTypeCount = 1
+ )
+ }
+ }
+
+ /**
+ * Wrapper around a serialized [RemoteCollectionItems] with metadata about the versions
+ * of Android and the app when the items were created.
+ *
+ * Our method of serialization and deserialization is to marshall and unmarshall the items to
+ * a byte array using their [Parcelable] implementation. As Parcelable definitions can change
+ * over time, it is not safe to do this across different versions of a package or Android
+ * itself. However, as app widgets are recreated on reboot or when a package is updated, this
+ * is not a problem for the approach used here.
+ *
+ * This data wrapper stores the current build of Android and the provider app at the time of
+ * serialization and deserialization is only attempted in [load] if both are the same as at
+ * the time of serialization.
+ */
+ private class RemoteViewsCompatServiceData {
+ private val mItemsBytes: ByteArray
+ private val mBuildVersion: String
+ private val mAppVersion: Long
+
+ private constructor(
+ itemsBytes: ByteArray,
+ buildVersion: String,
+ appVersion: Long
+ ) {
+ mItemsBytes = itemsBytes
+ mBuildVersion = buildVersion
+ mAppVersion = appVersion
+ }
+
+ constructor(parcel: Parcel) {
+ val length = parcel.readInt()
+ mItemsBytes = ByteArray(length)
+ parcel.readByteArray(mItemsBytes)
+ mBuildVersion = parcel.readString()!!
+ mAppVersion = parcel.readLong()
+ }
+
+ fun writeToParcel(dest: Parcel) {
+ dest.writeInt(mItemsBytes.size)
+ dest.writeByteArray(mItemsBytes)
+ dest.writeString(mBuildVersion)
+ dest.writeLong(mAppVersion)
+ }
+
+ fun save(context: Context, appWidgetId: Int, viewId: Int) {
+ getPrefs(context)
+ .edit()
+ .putString(
+ getKey(appWidgetId, viewId),
+ serializeToHexString { parcel, _ -> writeToParcel(parcel) }
+ )
+ .apply()
+ }
+
+ companion object {
+ private const val PREFS_FILENAME = "androidx.core.widget.prefs.RemoteViewsCompat"
+
+ internal fun getKey(appWidgetId: Int, viewId: Int): String {
+ return "$appWidgetId:$viewId"
+ }
+
+ internal fun getPrefs(context: Context): SharedPreferences {
+ return context.getSharedPreferences(PREFS_FILENAME, MODE_PRIVATE)
+ }
+
+ fun create(
+ context: Context,
+ items: RemoteCollectionItems
+ ): RemoteViewsCompatServiceData {
+ val versionCode = getVersionCode(context)
+ check(versionCode != null) { "Couldn't obtain version code for app" }
+ return RemoteViewsCompatServiceData(
+ itemsBytes = serializeToBytes(items::writeToParcel),
+ buildVersion = Build.VERSION.INCREMENTAL,
+ appVersion = versionCode
+ )
+ }
+
+ /**
+ * Returns the stored [RemoteCollectionItems] for the widget/view id, or null if
+ * it couldn't be retrieved for any reason.
+ */
+ internal fun load(
+ context: Context,
+ appWidgetId: Int,
+ viewId: Int
+ ): RemoteCollectionItems? {
+ val prefs = getPrefs(context)
+ val hexString = prefs.getString(getKey(appWidgetId, viewId), /* defValue= */ null)
+ if (hexString == null) {
+ Log.w(TAG, "No collection items were stored for widget $appWidgetId")
+ return null
+ }
+ val data = deserializeFromHexString(hexString) { RemoteViewsCompatServiceData(it) }
+ if (Build.VERSION.INCREMENTAL != data.mBuildVersion) {
+ Log.w(
+ TAG,
+ "Android version code has changed, not using stored collection items for " +
+ "widget $appWidgetId"
+ )
+ return null
+ }
+ val versionCode = getVersionCode(context)
+ if (versionCode == null) {
+ Log.w(
+ TAG,
+ "Couldn't get version code, not using stored collection items for widget " +
+ appWidgetId
+ )
+ return null
+ }
+ if (versionCode != data.mAppVersion) {
+ Log.w(
+ TAG,
+ "App version code has changed, not using stored collection items for " +
+ "widget $appWidgetId"
+ )
+ return null
+ }
+ return try {
+ deserializeFromBytes(data.mItemsBytes) { RemoteCollectionItems(it) }
+ } catch (t: Throwable) {
+ Log.e(
+ TAG,
+ "Unable to deserialize stored collection items for widget $appWidgetId",
+ t
+ )
+ null
+ }
+ }
+
+ internal fun getVersionCode(context: Context): Long? {
+ val packageManager = context.packageManager
+ val packageInfo = try {
+ packageManager.getPackageInfo(context.packageName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(TAG, "Couldn't retrieve version code for " + context.packageManager, e)
+ return null
+ }
+ return PackageInfoCompat.getLongVersionCode(packageInfo)
+ }
+
+ internal fun serializeToHexString(parcelable: (Parcel, Int) -> Unit): String {
+ return Base64.encodeToString(serializeToBytes(parcelable), Base64.DEFAULT)
+ }
+
+ internal fun serializeToBytes(parcelable: (Parcel, Int) -> Unit): ByteArray {
+ val parcel = Parcel.obtain()
+ return try {
+ parcel.setDataPosition(0)
+ parcelable(parcel, 0)
+ parcel.marshall()
+ } finally {
+ parcel.recycle()
+ }
+ }
+
+ internal fun <P> deserializeFromHexString(
+ hexString: String,
+ creator: (Parcel) -> P,
+ ): P {
+ return deserializeFromBytes(Base64.decode(hexString, Base64.DEFAULT), creator)
+ }
+
+ internal fun <P> deserializeFromBytes(
+ bytes: ByteArray,
+ creator: (Parcel) -> P,
+ ): P {
+ val parcel = Parcel.obtain()
+ return try {
+ parcel.unmarshall(bytes, 0, bytes.size)
+ parcel.setDataPosition(0)
+ creator(parcel)
+ } finally {
+ parcel.recycle()
+ }
+ }
+ }
+ }
+
+ internal companion object {
+ private const val TAG = "RemoteViewsCompatServic"
+ private const val EXTRA_VIEW_ID = "androidx.core.widget.extra.view_id"
+
+ /**
+ * Returns an intent use with [RemoteViews.setRemoteAdapter]. These intents
+ * are uniquely identified by the [appWidgetId] and [viewId].
+ */
+ fun createIntent(
+ context: Context,
+ appWidgetId: Int,
+ viewId: Int
+ ): Intent {
+ return Intent(context, RemoteViewsCompatService::class.java)
+ .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
+ .putExtra(EXTRA_VIEW_ID, viewId)
+ .also { intent ->
+ // Set a data Uri to disambiguate Intents for different widget/view ids.
+ intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))
+ }
+ }
+
+ /**
+ * Stores [items] to the disk to be used by a [RemoteViewsCompatService] for the same
+ * [appWidgetId] and [viewId].
+ */
+ fun saveItems(
+ context: Context,
+ appWidgetId: Int,
+ viewId: Int,
+ items: RemoteCollectionItems
+ ) {
+ RemoteViewsCompatServiceData.create(context, items).save(context, appWidgetId, viewId)
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/core-role/src/main/java/androidx/core/role/RoleManagerCompat.java b/core/core-role/src/main/java/androidx/core/role/RoleManagerCompat.java
index 38f250a..d739e9b 100644
--- a/core/core-role/src/main/java/androidx/core/role/RoleManagerCompat.java
+++ b/core/core-role/src/main/java/androidx/core/role/RoleManagerCompat.java
@@ -56,6 +56,14 @@
* </activity>
* }</pre>
* The application will be able to handle that intent by default.
+ * <p>
+ * Apps that hold this role are allowed to start activities in response to notification clicks
+ * or notification action clicks when targeting {@link android.os.Build.VERSION_CODES#S} to give
+ * browsers time to adapt. This is temporary and browsers will be subjected to the same
+ * trampoline restrictions at some point in future releases. For more details on those
+ * restrictions see {@link android.app.Notification.Builder#setContentIntent(PendingIntent)} and
+ * {@link android.app.Notification.Action.Builder#Builder(android.graphics.drawable.Icon,
+ * java.lang.CharSequence, android.app.PendingIntent)}.
*
* @see android.content.Intent#CATEGORY_APP_BROWSER
*/
diff --git a/core/core-splashscreen/OWNERS b/core/core-splashscreen/OWNERS
new file mode 100644
index 0000000..831d512
--- /dev/null
+++ b/core/core-splashscreen/OWNERS
@@ -0,0 +1,8 @@
+caen@google.com
+jjaggi@google.com
+cinek@google.com
+yaraki@google.com
+chrisbanes@google.com
+wilsonshih@google.com
+
+
diff --git a/core/core-splashscreen/api/current.txt b/core/core-splashscreen/api/current.txt
new file mode 100644
index 0000000..898f855
--- /dev/null
+++ b/core/core-splashscreen/api/current.txt
@@ -0,0 +1,36 @@
+// Signature format: 4.0
+package androidx.core.splashscreen {
+
+ public final class SplashScreen {
+ method public static androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+ method public void setKeepVisibleCondition(androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition condition);
+ method public void setOnExitAnimationListener(androidx.core.splashscreen.SplashScreen.OnExitAnimationListener listener);
+ field public static final androidx.core.splashscreen.SplashScreen.Companion Companion;
+ }
+
+ public static final class SplashScreen.Companion {
+ method public androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+ }
+
+ public static fun interface SplashScreen.KeepOnScreenCondition {
+ method @MainThread public boolean shouldKeepOnScreen();
+ }
+
+ public static fun interface SplashScreen.OnExitAnimationListener {
+ method @MainThread public void onSplashScreenExit(androidx.core.splashscreen.SplashScreenViewProvider splashScreenViewProvider);
+ }
+
+ public final class SplashScreenViewProvider {
+ method public long getIconAnimationDurationMillis();
+ method public long getIconAnimationStartMillis();
+ method public android.view.View getIconView();
+ method public android.view.View getView();
+ method public void remove();
+ property public final long iconAnimationDurationMillis;
+ property public final long iconAnimationStartMillis;
+ property public final android.view.View iconView;
+ property public final android.view.View view;
+ }
+
+}
+
diff --git a/core/core-splashscreen/api/public_plus_experimental_current.txt b/core/core-splashscreen/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..898f855
--- /dev/null
+++ b/core/core-splashscreen/api/public_plus_experimental_current.txt
@@ -0,0 +1,36 @@
+// Signature format: 4.0
+package androidx.core.splashscreen {
+
+ public final class SplashScreen {
+ method public static androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+ method public void setKeepVisibleCondition(androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition condition);
+ method public void setOnExitAnimationListener(androidx.core.splashscreen.SplashScreen.OnExitAnimationListener listener);
+ field public static final androidx.core.splashscreen.SplashScreen.Companion Companion;
+ }
+
+ public static final class SplashScreen.Companion {
+ method public androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+ }
+
+ public static fun interface SplashScreen.KeepOnScreenCondition {
+ method @MainThread public boolean shouldKeepOnScreen();
+ }
+
+ public static fun interface SplashScreen.OnExitAnimationListener {
+ method @MainThread public void onSplashScreenExit(androidx.core.splashscreen.SplashScreenViewProvider splashScreenViewProvider);
+ }
+
+ public final class SplashScreenViewProvider {
+ method public long getIconAnimationDurationMillis();
+ method public long getIconAnimationStartMillis();
+ method public android.view.View getIconView();
+ method public android.view.View getView();
+ method public void remove();
+ property public final long iconAnimationDurationMillis;
+ property public final long iconAnimationStartMillis;
+ property public final android.view.View iconView;
+ property public final android.view.View view;
+ }
+
+}
+
diff --git a/core/core-splashscreen/api/res-current.txt b/core/core-splashscreen/api/res-current.txt
new file mode 100644
index 0000000..f751c82
--- /dev/null
+++ b/core/core-splashscreen/api/res-current.txt
@@ -0,0 +1,5 @@
+attr postSplashScreenTheme
+attr windowSplashScreenAnimatedIcon
+attr windowSplashScreenAnimationDuration
+attr windowSplashScreenBackground
+style Theme_SplashScreen
diff --git a/core/core-splashscreen/api/restricted_current.txt b/core/core-splashscreen/api/restricted_current.txt
new file mode 100644
index 0000000..898f855
--- /dev/null
+++ b/core/core-splashscreen/api/restricted_current.txt
@@ -0,0 +1,36 @@
+// Signature format: 4.0
+package androidx.core.splashscreen {
+
+ public final class SplashScreen {
+ method public static androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+ method public void setKeepVisibleCondition(androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition condition);
+ method public void setOnExitAnimationListener(androidx.core.splashscreen.SplashScreen.OnExitAnimationListener listener);
+ field public static final androidx.core.splashscreen.SplashScreen.Companion Companion;
+ }
+
+ public static final class SplashScreen.Companion {
+ method public androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+ }
+
+ public static fun interface SplashScreen.KeepOnScreenCondition {
+ method @MainThread public boolean shouldKeepOnScreen();
+ }
+
+ public static fun interface SplashScreen.OnExitAnimationListener {
+ method @MainThread public void onSplashScreenExit(androidx.core.splashscreen.SplashScreenViewProvider splashScreenViewProvider);
+ }
+
+ public final class SplashScreenViewProvider {
+ method public long getIconAnimationDurationMillis();
+ method public long getIconAnimationStartMillis();
+ method public android.view.View getIconView();
+ method public android.view.View getView();
+ method public void remove();
+ property public final long iconAnimationDurationMillis;
+ property public final long iconAnimationStartMillis;
+ property public final android.view.View iconView;
+ property public final android.view.View view;
+ }
+
+}
+
diff --git a/core/core-splashscreen/build.gradle b/core/core-splashscreen/build.gradle
new file mode 100644
index 0000000..70b0d81
--- /dev/null
+++ b/core/core-splashscreen/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+import androidx.build.LibraryVersions
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 21
+ testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner")
+ }
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+
+ implementation("androidx.annotation:annotation:1.2.0")
+
+ androidTestImplementation(project(":test:screenshot:test-screenshot"))
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.testUiautomator)
+ androidTestImplementation(libs.truth)
+ androidTestImplementation(project(":appcompat:appcompat"))
+}
+
+androidx {
+ name = "SplashScreen"
+ type = LibraryType.PUBLISHED_LIBRARY
+ mavenVersion = LibraryVersions.CORE_SPLASHSCREEN
+ mavenGroup = LibraryGroups.CORE
+ inceptionYear = "2021"
+ description = "This library provides the compatibility APIs for SplashScreen " +
+ "and helper method to enable a splashscreen on devices prior Android 12"
+}
diff --git a/core/core-splashscreen/samples/build.gradle b/core/core-splashscreen/samples/build.gradle
new file mode 100644
index 0000000..05baf9f
--- /dev/null
+++ b/core/core-splashscreen/samples/build.gradle
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+ id("kotlin-android")
+}
+
+android {
+ defaultConfig {
+ applicationId "androidx.core.splashscreen.samples"
+ minSdkVersion 21
+ }
+}
+
+dependencies {
+ implementation(project(":appcompat:appcompat"))
+ implementation project(":annotation:annotation")
+ implementation(project(":core:core-splashscreen"))
+ implementation(project(":core:core-ktx"))
+ compileOnly(project(":annotation:annotation-sampled"))
+}
+
+androidx {
+ name = "AndroidX Splashscreen Samples"
+ type = LibraryType.SAMPLES
+ mavenVersion = LibraryVersions.CORE_SPLASHSCREEN
+ mavenGroup = LibraryGroups.CORE
+ inceptionYear = "2021"
+ description = "Sample for the AndoridX Splashscreen library"
+}
diff --git a/core/core-splashscreen/samples/src/main/AndroidManifest.xml b/core/core-splashscreen/samples/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..935b220
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.core.splashscreen.sample">
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/Theme.App.Starting"
+ android:label="@string/app_name">
+ <activity android:name=".SplashScreenSampleActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/java/androidx/core/splashscreen/sample/SplashScreenSampleActivity.kt b/core/core-splashscreen/samples/src/main/java/androidx/core/splashscreen/sample/SplashScreenSampleActivity.kt
new file mode 100644
index 0000000..2cc239c
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/java/androidx/core/splashscreen/sample/SplashScreenSampleActivity.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.core.splashscreen.sample
+
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.Process
+import android.view.View
+import android.view.animation.DecelerateInterpolator
+import android.widget.Button
+import android.widget.LinearLayout
+import androidx.annotation.RequiresApi
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.animation.doOnEnd
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import androidx.core.splashscreen.SplashScreenViewProvider
+import androidx.core.view.WindowCompat
+import androidx.core.view.postDelayed
+import androidx.interpolator.view.animation.FastOutLinearInInterpolator
+
+@RequiresApi(21)
+class SplashScreenSampleActivity : AppCompatActivity() {
+
+ private var appReady = false
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // This activity will be handling the splash screen transition
+ val splashScreen = installSplashScreen()
+
+ // The splashscreen goes edge to edge, so for a smooth transition to our app, we also
+ // want to draw edge to edge.
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+
+ // The content view needs to set before calling setOnExitAnimationListener
+ // to ensure that the SplashScreenView is attach to the right view root.
+ setContentView(R.layout.main_activity)
+
+ // (Optional) We can keep the splash screen visible until our app is ready.
+ splashScreen.setKeepVisibleCondition { !appReady }
+
+ // (Optional) Setting an OnExitAnimationListener on the SplashScreen indicates
+ // to the system that the application will handle the exit animation.
+ // The listener will be called once the app is ready.
+ splashScreen.setOnExitAnimationListener { splashScreenViewProvider ->
+ onSplashScreenExit(splashScreenViewProvider)
+ }
+
+ /* The code below is only for demo purposes */
+ // Create some artificial delay to simulate some local database fetch for example
+ Handler(Looper.getMainLooper())
+ .postDelayed({ appReady = true }, (MOCK_DELAY).toLong())
+
+ // Just a convenient button in our App to kill its process so we can play with the
+ // splashscreen again and again.
+ setupKillButton()
+ }
+
+ /**
+ * Handles the transition from the splash screen to the application
+ */
+ private fun onSplashScreenExit(splashScreenViewProvider: SplashScreenViewProvider) {
+ val accelerateInterpolator = FastOutLinearInInterpolator()
+ val splashScreenView = splashScreenViewProvider.view
+ val iconView = splashScreenViewProvider.iconView
+
+ // We'll change the alpha of the main view
+ val alpha = ObjectAnimator.ofFloat(splashScreenView, View.ALPHA, 1f, 0f)
+ alpha.duration = SPLASHSCREEN_ALPHA_ANIMATION_DURATION.toLong()
+ alpha.interpolator = accelerateInterpolator
+
+ // And we translate the icon down
+ val translationY = ObjectAnimator.ofFloat(
+ iconView,
+ View.TRANSLATION_Y,
+ iconView.translationY,
+ splashScreenView.height.toFloat()
+ )
+ translationY.duration = SPLASHSCREEN_TY_ANIMATION_DURATION.toLong()
+ translationY.interpolator = accelerateInterpolator
+
+ // To get fancy, we'll also animate our content
+ val marginAnimator = createContentAnimation()
+
+ // And we play all of the animation together
+ val animatorSet = AnimatorSet()
+ animatorSet.playTogether(translationY, alpha, marginAnimator)
+
+ // Once the application is finished, we remove the splash screen from our view
+ // hierarchy.
+ animatorSet.doOnEnd { splashScreenViewProvider.remove() }
+
+ if (WAIT_FOR_AVD_TO_FINISH) {
+ waitForAnimatedIconToFinish(splashScreenViewProvider, splashScreenView, animatorSet)
+ } else {
+ animatorSet.start()
+ }
+ }
+
+ /**
+ * Wait until the AVD animation is finished before starting the splash screen dismiss animation
+ */
+ private fun waitForAnimatedIconToFinish(
+ splashScreenViewProvider: SplashScreenViewProvider,
+ view: View,
+ animatorSet: AnimatorSet
+ ) {
+ // If we want to wait for our Animated Vector Drawable to finish animating, we can compute
+ // the remaining time to delay the start of the exit animation
+ val delayMillis: Long = (
+ splashScreenViewProvider.iconAnimationStartMillis +
+ splashScreenViewProvider.iconAnimationDurationMillis
+ ) - System.currentTimeMillis()
+ view.postDelayed(delayMillis) { animatorSet.start() }
+ }
+
+ /**
+ * Animates the content of the app in sync with the splash screen
+ */
+ private fun createContentAnimation(): ValueAnimator {
+ val marginStart = resources.getDimension(R.dimen.content_animation_margin_start)
+ val marginEnd = resources.getDimension(R.dimen.content_animation_margin_end)
+ val marginAnimator = ValueAnimator.ofFloat(marginStart, marginEnd)
+ marginAnimator.addUpdateListener { valueAnimator: ValueAnimator ->
+ val container = findViewById<LinearLayout>(R.id.container)
+ val marginTop = (valueAnimator.animatedValue as Float)
+ for (i in 0 until container.childCount) {
+ val child = container.getChildAt(i)
+ child.translationY = marginTop * (i + 1)
+ }
+ }
+ marginAnimator.interpolator = DecelerateInterpolator()
+ marginAnimator.duration = MARGIN_ANIMATION_DURATION.toLong()
+ return marginAnimator
+ }
+
+ private fun setupKillButton() {
+ findViewById<Button>(R.id.close_app).setOnClickListener {
+ finishAndRemoveTask()
+
+ // Don't do that in real life.
+ // For the sake of this demo app, we kill the process so the next time the app is
+ // launched, it will be a cold start and the splash screen will be visible.
+ Process.killProcess(Process.myPid())
+ }
+ }
+
+ private companion object {
+ const val MOCK_DELAY = 200
+ const val MARGIN_ANIMATION_DURATION = 800
+ const val SPLASHSCREEN_ALPHA_ANIMATION_DURATION = 500
+ const val SPLASHSCREEN_TY_ANIMATION_DURATION = 500
+ const val WAIT_FOR_AVD_TO_FINISH = false
+ }
+}
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/drawable-v26/ic_launcher.xml b/core/core-splashscreen/samples/src/main/res/drawable-v26/ic_launcher.xml
new file mode 100644
index 0000000..d4d3966
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/drawable-v26/ic_launcher.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/logo_background" />
+ <foreground android:drawable="@drawable/foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/drawable-v31/splashscreen_icon.xml b/core/core-splashscreen/samples/src/main/res/drawable-v31/splashscreen_icon.xml
new file mode 100644
index 0000000..f37aee7
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/drawable-v31/splashscreen_icon.xml
@@ -0,0 +1,74 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="1200"
+ android:viewportWidth="1200">
+
+ <group
+ android:translateX="200"
+ android:translateY="200">
+ <clip-path android:pathData="m596.328,310.906c22.484,-39.699 46.513,-78.699 68.084,-118.812 4.258,-14.364 -17.654,-23.707 -25.102,-10.703 -22.603,38.973 -45.139,77.986 -67.716,116.974 -107.224,-48.772 -235.192,-48.772 -342.415,0 -23.491,-39.715 -45.567,-80.447 -69.895,-119.56 -10.384,-10.813 -29.373,3.556 -21.753,16.461 22.277,38.562 44.614,77.091 66.914,115.64C88.641,372.042 9.442,494.721 0,625c266.667,0 533.333,0 800,0C790.261,494.557 711.967,372.81 596.328,310.906ZM216.039,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.056,51.902 -27.872,51.263zM584.348,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.055,51.902 -27.872,51.263z" />
+ <path
+ android:fillColor="#3ddc84"
+ android:pathData="m596.328,310.906c22.484,-39.699 46.513,-78.699 68.084,-118.812 4.258,-14.364 -17.654,-23.707 -25.102,-10.703 -22.603,38.973 -45.139,77.986 -67.716,116.974 -107.224,-48.772 -235.192,-48.772 -342.415,0 -23.491,-39.715 -45.567,-80.447 -69.895,-119.56 -10.384,-10.813 -29.373,3.556 -21.753,16.461 22.277,38.562 44.614,77.091 66.914,115.64C88.641,372.042 9.442,494.721 -0,625c266.667,0 533.333,0 800,0C790.261,494.557 711.967,372.81 596.328,310.906ZM216.039,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.056,51.902 -27.872,51.263zM584.348,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.055,51.902 -27.872,51.263z"
+ android:strokeWidth="1.93078" />
+ <group android:name="anim">
+ <path
+ android:fillAlpha="0.999"
+ android:fillColor="#979797"
+ android:fillType="nonZero"
+ android:pathData="m-365.59,1182.578c0,0 -11.042,-480.188 85.394,-399.752 60.916,50.809 142.292,-121.476 169.542,-86.281 5.022,-14.293 176.01,202.148 258.772,33.247 19.774,-40.355 81.088,-119.424 144.881,-29.933 100.418,140.869 205.377,-186.568 333.041,-33.27 67.395,80.927 178.475,-43.713 274.164,36.831 78.914,66.424 154.012,6.899 203.266,113.15 45.039,97.158 66.468,366.007 66.468,366.007L1169.938,171.976L-365.59,171.976Z"
+ android:strokeAlpha="1"
+ android:strokeColor="#00000000"
+ android:strokeWidth="12" />
+ </group>
+ </group>
+ </vector>
+ </aapt:attr>
+
+
+ <target android:name="anim">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="translateY"
+ android:repeatCount="0"
+ android:valueFrom="0"
+ android:valueTo="-800"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/accelerate_decelerate" />
+ </aapt:attr>
+ </target>
+ <target android:name="anim">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="translateX"
+ android:repeatCount="-1"
+ android:repeatMode="reverse"
+ android:valueFrom="-300"
+ android:valueTo="300"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/accelerate_decelerate" />
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/core/core-splashscreen/samples/src/main/res/drawable/android.xml b/core/core-splashscreen/samples/src/main/res/drawable/android.xml
new file mode 100644
index 0000000..a0207f8
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/drawable/android.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="72dp"
+ android:height="72dp"
+ android:viewportHeight="800"
+ android:viewportWidth="800">
+ <path
+ android:fillColor="#3ddc84"
+ android:pathData="m596.328,310.906c22.484,-39.699 46.513,-78.699 68.084,-118.812 4.258,-14.364 -17.654,-23.707 -25.102,-10.703 -22.603,38.973 -45.139,77.986 -67.716,116.974 -107.224,-48.772 -235.192,-48.772 -342.415,0 -23.491,-39.715 -45.567,-80.447 -69.895,-119.56 -10.384,-10.813 -29.373,3.556 -21.753,16.461 22.277,38.562 44.614,77.091 66.914,115.64C88.641,372.042 9.442,494.721 -0,625c266.667,0 533.333,0 800,0C790.261,494.557 711.967,372.81 596.328,310.906ZM216.039,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.056,51.902 -27.872,51.263zM584.348,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.055,51.902 -27.872,51.263z"
+ android:strokeWidth="1.93078" />
+</vector>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/drawable/foreground.xml b/core/core-splashscreen/samples/src/main/res/drawable/foreground.xml
new file mode 100644
index 0000000..c46194a
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/drawable/foreground.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/android"
+ android:inset="25%">
+</inset>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/drawable/ic_launcher.xml b/core/core-splashscreen/samples/src/main/res/drawable/ic_launcher.xml
new file mode 100644
index 0000000..59296dc
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/drawable/ic_launcher.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/logo_background" />
+ <item android:drawable="@drawable/foreground" />
+</layer-list>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/drawable/splashscreen_icon.xml b/core/core-splashscreen/samples/src/main/res/drawable/splashscreen_icon.xml
new file mode 100644
index 0000000..a8c4e96
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/drawable/splashscreen_icon.xml
@@ -0,0 +1,28 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="800"
+ android:viewportWidth="800">
+
+ <path
+ android:fillColor="#3ddc84"
+ android:pathData="m596.328,310.906c22.484,-39.699 46.513,-78.699 68.084,-118.812 4.258,-14.364 -17.654,-23.707 -25.102,-10.703 -22.603,38.973 -45.139,77.986 -67.716,116.974 -107.224,-48.772 -235.192,-48.772 -342.415,0 -23.491,-39.715 -45.567,-80.447 -69.895,-119.56 -10.384,-10.813 -29.373,3.556 -21.753,16.461 22.277,38.562 44.614,77.091 66.914,115.64C88.641,372.042 9.442,494.721 -0,625c266.667,0 533.333,0 800,0C790.261,494.557 711.967,372.81 596.328,310.906ZM216.039,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.056,51.902 -27.872,51.263zM584.348,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.055,51.902 -27.872,51.263z"
+ android:strokeWidth="2" />
+
+</vector>
+
diff --git a/core/core-splashscreen/samples/src/main/res/layout/main_activity.xml b/core/core-splashscreen/samples/src/main/res/layout/main_activity.xml
new file mode 100644
index 0000000..e170fbe
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/layout/main_activity.xml
@@ -0,0 +1,115 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="70dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SampleItem" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="70dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SampleItem" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="70dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SampleItem" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="70dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SampleItem" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="70dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SampleItem" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="70dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SampleItem" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="70dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SampleItem" />
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/close_app"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:text="Close App">
+ </Button>
+</LinearLayout>
diff --git a/core/core-splashscreen/samples/src/main/res/values/colors.xml b/core/core-splashscreen/samples/src/main/res/values/colors.xml
new file mode 100644
index 0000000..da0c8fc
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <color name="logo_background">#3C3C3C</color>
+ <color name="windowBackground">#CFCFCF</color>
+ <color name="splashScreenBackground">#474747</color>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/values/dimens.xml b/core/core-splashscreen/samples/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..c860cda
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="content_animation_margin_start">30dp</dimen>
+ <dimen name="content_animation_margin_end">10dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/values/strings.xml b/core/core-splashscreen/samples/src/main/res/values/strings.xml
new file mode 100644
index 0000000..ad5d050
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="app_name">AndroidX SplashScreen Sample</string>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/samples/src/main/res/values/styles.xml b/core/core-splashscreen/samples/src/main/res/values/styles.xml
new file mode 100644
index 0000000..fafcea9
--- /dev/null
+++ b/core/core-splashscreen/samples/src/main/res/values/styles.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Theme.App" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="android:windowBackground">@color/windowBackground</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+ </style>
+
+ <style name="Theme.App.Starting" parent="Theme.SplashScreen">
+ <item name="windowSplashScreenBackground">@color/splashScreenBackground</item>
+ <item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_icon</item>
+ <item name="windowSplashScreenAnimationDuration">2000</item>
+ <item name="postSplashScreenTheme">@style/Theme.App</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/androidTest/AndroidManifest.xml b/core/core-splashscreen/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..0253fc4
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.core.splashscreen.test">
+
+ <application>
+ <activity
+ android:name=".SplashScreenTestActivity"
+ android:exported="true"
+ android:theme="@style/Theme.Test.Starting">
+ <intent-filter>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".SplashScreenAppCompatTestActivity"
+ android:exported="true"
+ android:theme="@style/Theme.Test.Starting.AppCompat">
+ <intent-filter>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashScreenTestActivities.kt b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashScreenTestActivities.kt
new file mode 100644
index 0000000..b46d910
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashScreenTestActivities.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.core.splashscreen.test
+
+import android.app.Activity
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+
+public class SplashScreenTestActivity : Activity(), SplashScreenTestControllerHolder {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ controller = SplashScreenTestController(this)
+ controller.onCreate()
+ }
+
+ override lateinit var controller: SplashScreenTestController
+}
+
+public class SplashScreenAppCompatTestActivity :
+ AppCompatActivity(), SplashScreenTestControllerHolder {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ controller = SplashScreenTestController(this)
+ controller.onCreate()
+ }
+
+ override lateinit var controller: SplashScreenTestController
+}
diff --git a/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashScreenTestController.kt b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashScreenTestController.kt
new file mode 100644
index 0000000..453da24
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashScreenTestController.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.splashscreen.test
+
+import android.app.Activity
+import android.graphics.Bitmap
+import android.util.TypedValue
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import androidx.core.splashscreen.R as SR
+import androidx.test.runner.screenshot.Screenshot
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.atomic.AtomicBoolean
+
+internal const val EXTRA_ANIMATION_LISTENER = "AnimationListener"
+internal const val EXTRA_SPLASHSCREEN_WAIT = "splashscreen_wait"
+internal const val EXTRA_SPLASHSCREEN_VIEW_SCREENSHOT = "SplashScreenViewScreenShot"
+
+public interface SplashScreenTestControllerHolder {
+ public var controller: SplashScreenTestController
+}
+
+public class SplashScreenTestController(private val activity: Activity) {
+
+ public var splashScreenViewScreenShot: Bitmap? = null
+ public var splashScreenScreenshot: Bitmap? = null
+ public var splashscreenIconId: Int = 0
+ public var splashscreenBackgroundId: Int = 0
+ public var finalAppTheme: Int = 0
+ public var duration: Int = 0
+ public var exitAnimationListenerLatch: CountDownLatch = CountDownLatch(1)
+ public var drawnLatch: CountDownLatch = CountDownLatch(1)
+ public val isCompatActivity: Boolean
+ get() = activity is AppCompatActivity
+
+ // Wait for at least 3 passes to reduce flakiness
+ public var waitedLatch: CountDownLatch = CountDownLatch(3)
+ public val waitBarrier: AtomicBoolean = AtomicBoolean(true)
+ public var hasDrawn: Boolean = false
+
+ public fun onCreate() {
+ val intent = activity.intent
+ val theme = activity.theme
+
+ val useListener = intent.extras?.getBoolean(EXTRA_ANIMATION_LISTENER) ?: false
+ val takeScreenShot =
+ intent.extras?.getBoolean(EXTRA_SPLASHSCREEN_VIEW_SCREENSHOT) ?: false
+ val waitForSplashscreen = intent.extras?.getBoolean(EXTRA_SPLASHSCREEN_WAIT) ?: false
+
+ val tv = TypedValue()
+ theme.resolveAttribute(SR.attr.windowSplashScreenAnimatedIcon, tv, true)
+ splashscreenIconId = tv.resourceId
+
+ theme.resolveAttribute(SR.attr.windowSplashScreenBackground, tv, true)
+ splashscreenBackgroundId = tv.resourceId
+
+ theme.resolveAttribute(SR.attr.postSplashScreenTheme, tv, true)
+ finalAppTheme = tv.resourceId
+
+ theme.resolveAttribute(SR.attr.windowSplashScreenAnimationDuration, tv, true)
+ duration = tv.data
+
+ val splashScreen = activity.installSplashScreen()
+ activity.setContentView(R.layout.main_activity)
+
+ if (waitForSplashscreen) {
+ splashScreen.setKeepVisibleCondition {
+ waitedLatch.countDown()
+ val shouldWait = waitBarrier.get() || waitedLatch.count > 0L
+ if (!shouldWait && takeScreenShot && splashScreenScreenshot == null) {
+ splashScreenScreenshot = Screenshot.capture().bitmap
+ }
+ shouldWait
+ }
+ }
+
+ if (useListener) {
+ splashScreen.setOnExitAnimationListener { splashScreenViewProvider ->
+ if (takeScreenShot) {
+ splashScreenViewScreenShot = Screenshot.capture().bitmap
+ }
+ exitAnimationListenerLatch.countDown()
+ splashScreenViewProvider.remove()
+ }
+ }
+
+ val view = activity.findViewById<TestView>(R.id.container)
+ view.doOnDraw = { drawnLatch.countDown() }
+ }
+}
diff --git a/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashscreenTest.kt b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashscreenTest.kt
new file mode 100644
index 0000000..f5b5e4e
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashscreenTest.kt
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.splashscreen.test
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.os.Bundle
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.screenshot.matchers.MSSIMMatcher
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import org.hamcrest.core.IsNull.notNullValue
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.util.concurrent.TimeUnit
+import kotlin.reflect.KClass
+
+private const val SPLASH_SCREEN_STYLE_ICON = 1
+private const val KEY_SPLASH_SCREEN_STYLE: String = "android.activity.splashScreenStyle"
+private const val BASIC_SAMPLE_PACKAGE: String = "androidx.core.splashscreen.test"
+private const val LAUNCH_TIMEOUT: Long = 5000
+
+@LargeTest
+@RunWith(Parameterized::class)
+public class SplashscreenTest(
+ public val name: String,
+ public val activityClass: KClass<out SplashScreenTestControllerHolder>
+) {
+
+ private lateinit var device: UiDevice
+
+ public companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ public fun data(): Iterable<Array<Any>> {
+ return listOf(
+ arrayOf("Platform", SplashScreenTestActivity::class),
+ arrayOf("AppCompat", SplashScreenAppCompatTestActivity::class)
+ )
+ }
+ }
+
+ @Before
+ public fun setUp() {
+ device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ }
+
+ @Test
+ public fun compatAttributePopulated() {
+ val activity = startActivityWithSplashScreen()
+ assertEquals(1234, activity.duration)
+ assertEquals(R.color.bg_launcher, activity.splashscreenBackgroundId)
+ val expectedTheme =
+ if (activity.isCompatActivity) R.style.Theme_Test_AppCompat else R.style.Theme_Test
+ assertEquals(expectedTheme, activity.finalAppTheme)
+ assertEquals(R.drawable.android, activity.splashscreenIconId)
+ }
+
+ @Test
+ public fun exitAnimationListenerCalled() {
+ val activity = startActivityWithSplashScreen {
+ // Clear out any previous instances
+ it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ it.putExtra(EXTRA_ANIMATION_LISTENER, true)
+ }
+ assertTrue(activity.exitAnimationListenerLatch.await(2, TimeUnit.SECONDS))
+ }
+
+ @Test
+ public fun splashScreenWaited() {
+ val activity = startActivityWithSplashScreen {
+ // Clear out any previous instances
+ it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ it.putExtra(EXTRA_SPLASHSCREEN_WAIT, true)
+ }
+ assertTrue(
+ "Waiting condition was never checked",
+ activity.waitedLatch.await(2, TimeUnit.SECONDS)
+ )
+ assertFalse(
+ "Activity should not have been drawn", activity.hasDrawn
+ )
+ activity.waitBarrier.set(false)
+ assertTrue(
+ "Activity was never drawn",
+ activity.drawnLatch.await(2, TimeUnit.SECONDS)
+ )
+ }
+
+ @Test
+ public fun exitAnimationListenerCalledAfterWait() {
+ val activity = startActivityWithSplashScreen {
+ // Clear out any previous instances
+ it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ it.putExtra(EXTRA_SPLASHSCREEN_WAIT, true)
+ it.putExtra(EXTRA_ANIMATION_LISTENER, true)
+ }
+ activity.waitBarrier.set(false)
+ assertTrue(
+ "Activity was never drawn",
+ activity.drawnLatch.await(2, TimeUnit.SECONDS)
+ )
+ assertTrue(activity.exitAnimationListenerLatch.await(2, TimeUnit.SECONDS))
+ }
+
+ @Test
+ public fun splashscreenViewScreenshotComparison() {
+ val activity = startActivityWithSplashScreen {
+ // Clear out any previous instances
+ it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ it.putExtra(EXTRA_SPLASHSCREEN_WAIT, true)
+ it.putExtra(EXTRA_ANIMATION_LISTENER, true)
+ it.putExtra(EXTRA_SPLASHSCREEN_VIEW_SCREENSHOT, true)
+ }
+ assertTrue(activity.waitedLatch.await(2, TimeUnit.SECONDS))
+ activity.waitBarrier.set(false)
+ activity.exitAnimationListenerLatch.await(2, TimeUnit.SECONDS)
+
+ compareBitmaps(activity.splashScreenScreenshot!!, activity.splashScreenViewScreenShot!!)
+ }
+
+ private fun compareBitmaps(
+ beforeScreenshot: Bitmap,
+ afterScreenshot: Bitmap
+ ) {
+ val beforeBuffer = IntArray(beforeScreenshot.width * beforeScreenshot.height)
+ beforeScreenshot.getPixels(
+ beforeBuffer, 0, beforeScreenshot.width, 0, 0,
+ beforeScreenshot.width, beforeScreenshot.height
+ )
+
+ val afterBuffer = IntArray(afterScreenshot.width * afterScreenshot.height)
+ afterScreenshot.getPixels(
+ afterBuffer, 0, afterScreenshot.width, 0, 0,
+ afterScreenshot.width, afterScreenshot.height
+ )
+
+ val matcher = MSSIMMatcher(0.90).compareBitmaps(
+ beforeBuffer, afterBuffer, afterScreenshot.width,
+ afterScreenshot.height
+ )
+
+ if (!matcher.matches) {
+ val bundle = Bundle()
+ val diff = matcher.diff?.writeToDevice("diff.png")
+ bundle.putString("splashscreen_diff", diff?.absolutePath)
+ bundle.putString(
+ "splashscreen_before",
+ beforeScreenshot.writeToDevice("before.png").absolutePath
+ )
+ bundle.putString(
+ "splashscreen_after",
+ afterScreenshot.writeToDevice("after.png").absolutePath
+ )
+ val path = diff?.parentFile?.path
+ InstrumentationRegistry.getInstrumentation().sendStatus(2, bundle)
+ fail(
+ "SplashScreenView and SplashScreen don't match\n${matcher.comparisonStatistics}" +
+ "\nResult saved at $path"
+ )
+ }
+ }
+
+ private fun Bitmap.writeToDevice(name: String): File {
+ return writeToDevice(
+ {
+ compress(Bitmap.CompressFormat.PNG, 0 /*ignored for png*/, it)
+ },
+ name
+ )
+ }
+
+ private fun writeToDevice(
+ writeAction: (FileOutputStream) -> Unit,
+ name: String
+ ): File {
+ val deviceOutputDirectory = File(
+ InstrumentationRegistry.getInstrumentation().context.externalCacheDir,
+ "splashscreen_test"
+ )
+ if (!deviceOutputDirectory.exists() && !deviceOutputDirectory.mkdir()) {
+ throw IOException("Could not create folder.")
+ }
+
+ val file = File(deviceOutputDirectory, name)
+ try {
+ FileOutputStream(file).use {
+ writeAction(it)
+ }
+ } catch (e: Exception) {
+ throw IOException(
+ "Could not write file to storage (path: ${file.absolutePath}). " +
+ " Stacktrace: " + e.stackTrace
+ )
+ }
+ return file
+ }
+
+ private fun startActivityWithSplashScreen(
+ intentModifier: ((Intent) -> Unit)? = null
+ ): SplashScreenTestController {
+ // Start from the home screen
+ device.pressHome()
+
+ // Wait for launcher
+ val launcherPackage: String = device.launcherPackageName
+ assertThat(launcherPackage, notNullValue())
+ device.wait(
+ Until.hasObject(By.pkg(launcherPackage).depth(0)),
+ LAUNCH_TIMEOUT
+ )
+
+ // Launch the app
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val baseIntent = context.packageManager.getLaunchIntentForPackage(
+ BASIC_SAMPLE_PACKAGE
+ )
+ val intent = Intent(baseIntent).apply {
+ component = ComponentName(BASIC_SAMPLE_PACKAGE, activityClass.qualifiedName!!)
+ intentModifier?.invoke(this)
+ }
+
+ val monitor = object : Instrumentation.ActivityMonitor(
+ activityClass.qualifiedName!!,
+ Instrumentation.ActivityResult(0, Intent()), false
+ ) {
+ override fun onStartActivity(intent: Intent?): Instrumentation.ActivityResult? {
+ return if (intent?.component?.packageName == BASIC_SAMPLE_PACKAGE) {
+ Instrumentation.ActivityResult(0, Intent())
+ } else {
+ null
+ }
+ }
+ }
+ InstrumentationRegistry.getInstrumentation().addMonitor(monitor)
+
+ context.startActivity(
+ intent,
+ // Force the splash screen to be shown with an icon
+ Bundle().apply { putInt(KEY_SPLASH_SCREEN_STYLE, SPLASH_SCREEN_STYLE_ICON) }
+ )
+ assertTrue(
+ device.wait(
+ Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
+ LAUNCH_TIMEOUT
+ )
+ )
+ val splashScreenTestActivity =
+ monitor.waitForActivityWithTimeout(LAUNCH_TIMEOUT) as SplashScreenTestControllerHolder?
+ if (splashScreenTestActivity == null) {
+ fail(
+ activityClass.simpleName!! + " was not launched after " +
+ "$LAUNCH_TIMEOUT ms"
+ )
+ }
+ return splashScreenTestActivity!!.controller
+ }
+}
\ No newline at end of file
diff --git a/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/TestView.kt b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/TestView.kt
new file mode 100644
index 0000000..6bc6359
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/TestView.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.splashscreen.test
+
+import android.content.Context
+import android.graphics.Canvas
+import android.util.AttributeSet
+import android.widget.FrameLayout
+
+public class TestView(
+ context: Context,
+ attrs: AttributeSet
+) : FrameLayout(context, attrs) {
+
+ public var doOnDraw: (() -> Unit) = {}
+
+ override fun onDraw(canvas: Canvas?) {
+ super.onDraw(canvas)
+ doOnDraw()
+ }
+}
\ No newline at end of file
diff --git a/core/core-splashscreen/src/androidTest/res/drawable/android.xml b/core/core-splashscreen/src/androidTest/res/drawable/android.xml
new file mode 100644
index 0000000..822d8e7
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/res/drawable/android.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="72dp"
+ android:height="72dp"
+ android:viewportHeight="100"
+ android:viewportWidth="100">
+ <path
+ android:fillColor="#3ddc84"
+ android:pathData="m0 0 L 0 100 100 100 100 0z"
+ android:strokeWidth="1" />
+</vector>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/androidTest/res/layout/main_activity.xml b/core/core-splashscreen/src/androidTest/res/layout/main_activity.xml
new file mode 100644
index 0000000..6570777
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/res/layout/main_activity.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<androidx.core.splashscreen.test.TestView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="#00FF00">
+
+</androidx.core.splashscreen.test.TestView>
diff --git a/core/core-splashscreen/src/androidTest/res/values/colors.xml b/core/core-splashscreen/src/androidTest/res/values/colors.xml
new file mode 100644
index 0000000..306e151
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <color name="bg_launcher">#15FFFF</color>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/androidTest/res/values/styles.xml b/core/core-splashscreen/src/androidTest/res/values/styles.xml
new file mode 100644
index 0000000..743d243
--- /dev/null
+++ b/core/core-splashscreen/src/androidTest/res/values/styles.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Theme.Test" parent="android:Theme.Material.Light.NoActionBar">
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+ <item name="android:fitsSystemWindows">false</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ </style>
+
+ <style name="Theme.Test.Starting" parent="Theme.SplashScreen">
+ <item name="windowSplashScreenBackground">@color/bg_launcher</item>
+ <item name="windowSplashScreenAnimatedIcon">@drawable/android</item>
+ <item name="windowSplashScreenAnimationDuration">1234</item>
+ <item name="postSplashScreenTheme">@style/Theme.Test</item>
+ </style>
+
+ <!-- Themes for AppCompat Tests -->
+ <style name="Theme.Test.AppCompat" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+ <item name="android:fitsSystemWindows">false</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ </style>
+
+ <style name="Theme.Test.Starting.AppCompat" parent="Theme.SplashScreen">
+ <item name="windowSplashScreenBackground">@color/bg_launcher</item>
+ <item name="windowSplashScreenAnimatedIcon">@drawable/android</item>
+ <item name="windowSplashScreenAnimationDuration">1234</item>
+ <item name="postSplashScreenTheme">@style/Theme.Test.AppCompat</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/AndroidManifest.xml b/core/core-splashscreen/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..df15dd4
--- /dev/null
+++ b/core/core-splashscreen/src/main/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.core.splashscreen"/>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/java/androidx/core/splashscreen/SplashScreen.kt b/core/core-splashscreen/src/main/java/androidx/core/splashscreen/SplashScreen.kt
new file mode 100644
index 0000000..94c0b67
--- /dev/null
+++ b/core/core-splashscreen/src/main/java/androidx/core/splashscreen/SplashScreen.kt
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.splashscreen
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.res.Resources
+import android.os.Build.VERSION.PREVIEW_SDK_INT
+import android.os.Build.VERSION.SDK_INT
+import android.util.TypedValue
+import android.view.View
+import android.view.View.OnLayoutChangeListener
+import android.view.ViewTreeObserver.OnPreDrawListener
+import android.widget.ImageView
+import androidx.annotation.MainThread
+import androidx.annotation.RequiresApi
+import androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition
+
+/**
+ * Compatibly class for the SplashScreen API introduced in API 31.
+ *
+ * On API 31+ (Android 12+) this class calls the platform methods.
+ *
+ * Prior API 31, the platform behavior is replicated with the exception of the Animated Vector
+ * Drawable support on the launch screen.
+ *
+ * To use this class, the theme of the starting Activity needs set [R.style.Theme_SplashScreen] as
+ * its parent and the [R.attr.windowSplashScreenAnimatedIcon] and [R.attr.postSplashScreenTheme]`
+ * attribute need to be set.
+ */
+@SuppressLint("CustomSplashScreen")
+public class SplashScreen private constructor(activity: Activity) {
+
+ @SuppressLint("NewApi") // TODO(188897399) Remove once "S" is finalized
+ private val impl = when {
+ SDK_INT >= 31 -> Impl31(activity)
+ SDK_INT == 30 && PREVIEW_SDK_INT > 0 -> Impl31(activity)
+ SDK_INT >= 23 -> Impl23(activity)
+ else -> Impl(activity)
+ }
+
+ public companion object {
+
+ /**
+ * Creates a [SplashScreen] instance associated with this [Activity] and handles
+ * setting the theme to [R.attr.postSplashScreenTheme].
+ *
+ * This needs to be called before [Activity.setContentView] or other view operation on
+ * the root view (e.g setting flags).
+ *
+ * Alternatively, if a [SplashScreen] instance is not required, the them can manually be
+ * set using [Activity.setTheme].
+ */
+ @JvmStatic
+ public fun Activity.installSplashScreen(): SplashScreen {
+ val splashScreen = SplashScreen(this)
+ splashScreen.install()
+ return splashScreen
+ }
+ }
+
+ /**
+ * Sets the condition to keep the splash screen visible.
+ *
+ * The splash will stay visible until the condition isn't met anymore.
+ * The condition is evaluated before each request to draw the application, so it needs to be
+ * fast to avoid blocking the UI.
+ *
+ * @param condition The condition evaluated to decide whether to keep the splash screen on
+ * screen
+ */
+ public fun setKeepVisibleCondition(condition: KeepOnScreenCondition) {
+ impl.setKeepVisibleCondition(condition)
+ }
+
+ /**
+ * Sets a listener that will be called when the splashscreen is ready to be removed.
+ *
+ * If a listener is set, the splashscreen won't be automatically removed and the application
+ * needs to manually call [SplashScreenViewProvider.remove].
+ *
+ * IF no listener is set, the splashscreen will be automatically removed once the app is
+ * ready to draw.
+ *
+ * The listener will be called on the ui thread.
+ *
+ * @param listener The [OnExitAnimationListener] that will be called when the splash screen
+ * is ready to be dismissed.
+ *
+ * @see setKeepVisibleCondition
+ * @see OnExitAnimationListener
+ * @see SplashScreenViewProvider
+ */
+ @SuppressWarnings("ExecutorRegistration") // Always runs on the MainThread
+ public fun setOnExitAnimationListener(listener: OnExitAnimationListener) {
+ impl.setOnExitAnimationListener(listener)
+ }
+
+ private fun install() {
+ impl.install()
+ }
+
+ /**
+ * Listener to be passed in [SplashScreen.setOnExitAnimationListener].
+ *
+ * The listener will be called once the splash screen is ready to be removed and provides a
+ * reference to a [SplashScreenViewProvider] that can be used to customize the exit
+ * animation of the splash screen.
+ */
+ public fun interface OnExitAnimationListener {
+
+ /**
+ * Callback called when the splash screen is ready to be dismissed. The caller is
+ * responsible for animating and removing splash screen using the provided
+ * [splashScreenViewProvider].
+ *
+ * The caller **must** call [SplashScreenViewProvider.remove] once it's done with the
+ * splash screen.
+ *
+ * @param splashScreenViewProvider An object holding a reference to the displayed splash
+ * screen.
+ */
+ @MainThread
+ public fun onSplashScreenExit(splashScreenViewProvider: SplashScreenViewProvider)
+ }
+
+ /**
+ * Condition evaluated to check if the splash screen should remain on screen
+ *
+ * The splash screen will stay visible until the condition isn't met anymore.
+ * The condition is evaluated before each request to draw the application, so it needs to be
+ * fast to avoid blocking the UI.
+ */
+ public fun interface KeepOnScreenCondition {
+
+ /**
+ * Callback evaluated before every requests to draw the Activity. If it returns `true`, the
+ * splash screen will be kept visible to hide the Activity below.
+ *
+ * This callback is evaluated in the main thread.
+ */
+ @MainThread
+ public fun shouldKeepOnScreen(): Boolean
+ }
+
+ private open class Impl(val activity: Activity) {
+ var finalThemeId: Int = 0
+ var backgroundResId: Int? = null
+ var backgroundColor: Int? = null
+ var icon: Int = 0
+
+ var splashScreenWaitPredicate = KeepOnScreenCondition { false }
+ private var animationListener: OnExitAnimationListener? = null
+ private var mSplashScreenViewProvider: SplashScreenViewProvider? = null
+
+ open fun install() {
+ val typedValue = TypedValue()
+ val currentTheme = activity.theme
+ if (currentTheme.resolveAttribute(
+ R.attr.windowSplashScreenBackground,
+ typedValue,
+ true
+ )
+ ) {
+ backgroundResId = typedValue.resourceId
+ backgroundColor = typedValue.data
+ }
+ if (currentTheme.resolveAttribute(
+ R.attr.windowSplashScreenAnimatedIcon,
+ typedValue,
+ true
+ )
+ ) {
+ icon = typedValue.resourceId
+ }
+ setPostSplashScreenTheme(currentTheme, typedValue)
+ }
+
+ protected fun setPostSplashScreenTheme(
+ currentTheme: Resources.Theme,
+ typedValue: TypedValue
+ ) {
+ if (currentTheme.resolveAttribute(R.attr.postSplashScreenTheme, typedValue, true)) {
+ finalThemeId = typedValue.resourceId
+ if (finalThemeId != 0) {
+ activity.setTheme(finalThemeId)
+ }
+ } else {
+ throw Resources.NotFoundException(
+ "Cannot set AppTheme. No theme value defined for attribute " +
+ activity.resources.getResourceName(R.attr.postSplashScreenTheme)
+ )
+ }
+ }
+
+ open fun setKeepVisibleCondition(keepOnScreenCondition: KeepOnScreenCondition) {
+ splashScreenWaitPredicate = keepOnScreenCondition
+ val contentView = activity.findViewById<View>(android.R.id.content)
+ val observer = contentView.viewTreeObserver
+ observer.addOnPreDrawListener(object : OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ if (splashScreenWaitPredicate.shouldKeepOnScreen()) {
+ return false
+ }
+ contentView.viewTreeObserver.removeOnPreDrawListener(this)
+ mSplashScreenViewProvider?.let(::dispatchOnExitAnimation)
+ return true
+ }
+ })
+ }
+
+ open fun setOnExitAnimationListener(exitAnimationListener: OnExitAnimationListener) {
+ animationListener = exitAnimationListener
+
+ val splashScreenViewProvider = SplashScreenViewProvider(activity)
+ val finalBackgroundResId = backgroundResId
+ val finalBackgroundColor = backgroundColor
+ if (finalBackgroundResId != null && finalBackgroundResId != Resources.ID_NULL) {
+ splashScreenViewProvider.view.setBackgroundResource(finalBackgroundResId)
+ } else if (finalBackgroundColor != null) {
+ splashScreenViewProvider.view.setBackgroundColor(finalBackgroundColor)
+ } else {
+ splashScreenViewProvider.view.background = activity.window.decorView.background
+ }
+
+ splashScreenViewProvider.view.findViewById<ImageView>(R.id.splashscreen_icon_view)
+ .setBackgroundResource(icon)
+
+ splashScreenViewProvider.view.addOnLayoutChangeListener(
+ object : OnLayoutChangeListener {
+ override fun onLayoutChange(
+ view: View,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ adjustInsets(view, splashScreenViewProvider)
+ if (!view.isAttachedToWindow) {
+ return
+ }
+
+ view.removeOnLayoutChangeListener(this)
+ if (!splashScreenWaitPredicate.shouldKeepOnScreen()) {
+ dispatchOnExitAnimation(splashScreenViewProvider)
+ } else {
+ mSplashScreenViewProvider = splashScreenViewProvider
+ }
+ }
+ })
+ }
+
+ fun dispatchOnExitAnimation(splashScreenViewProvider: SplashScreenViewProvider) {
+ val finalListener = animationListener ?: return
+ animationListener = null
+ splashScreenViewProvider.view.postOnAnimation {
+ finalListener.onSplashScreenExit(splashScreenViewProvider)
+ }
+ }
+
+ /**
+ * Adjust the insets to avoid any jump between the actual splash screen and the
+ * SplashScreen View
+ */
+ open fun adjustInsets(
+ view: View,
+ splashScreenViewProvider: SplashScreenViewProvider
+ ) {
+ // No-op
+ }
+ }
+
+ @Suppress("DEPRECATION")
+ @RequiresApi(23)
+ private class Impl23(activity: Activity) : Impl(activity) {
+ override fun adjustInsets(
+ view: View,
+ splashScreenViewProvider: SplashScreenViewProvider
+ ) {
+ // Offset the icon if the insets have changed
+ val rootWindowInsets = view.rootWindowInsets
+ val ty =
+ rootWindowInsets.systemWindowInsetTop - rootWindowInsets.systemWindowInsetBottom
+ splashScreenViewProvider.iconView.translationY = -ty.toFloat() / 2f
+ }
+ }
+
+ @RequiresApi(31) // TODO(188897399) Update to "S" once finalized
+ private class Impl31(activity: Activity) : Impl(activity) {
+ var preDrawListener: OnPreDrawListener? = null
+
+ override fun install() {
+ setPostSplashScreenTheme(activity.theme, TypedValue())
+ }
+
+ override fun setKeepVisibleCondition(keepOnScreenCondition: KeepOnScreenCondition) {
+ splashScreenWaitPredicate = keepOnScreenCondition
+ val contentView = activity.findViewById<View>(android.R.id.content)
+ val observer = contentView.viewTreeObserver
+
+ if (preDrawListener != null && observer.isAlive) {
+ observer.removeOnPreDrawListener(preDrawListener)
+ }
+ preDrawListener = object : OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ if (splashScreenWaitPredicate.shouldKeepOnScreen()) {
+ return false
+ }
+ contentView.viewTreeObserver.removeOnPreDrawListener(this)
+ return true
+ }
+ }
+ observer.addOnPreDrawListener(preDrawListener)
+ }
+
+ override fun setOnExitAnimationListener(
+ exitAnimationListener: OnExitAnimationListener
+ ) {
+ activity.splashScreen.setOnExitAnimationListener {
+ val splashScreenViewProvider = SplashScreenViewProvider(it, activity)
+ exitAnimationListener.onSplashScreenExit(splashScreenViewProvider)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/java/androidx/core/splashscreen/SplashScreenViewProvider.kt b/core/core-splashscreen/src/main/java/androidx/core/splashscreen/SplashScreenViewProvider.kt
new file mode 100644
index 0000000..11eda6d
--- /dev/null
+++ b/core/core-splashscreen/src/main/java/androidx/core/splashscreen/SplashScreenViewProvider.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.splashscreen
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.os.Build
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.window.SplashScreenView
+import androidx.annotation.RequiresApi
+
+/**
+ * Contains a copy of the splash screen used to create a custom animation from the splash screen
+ * to the application.
+ *
+ * The splashscreen is accessible using [SplashScreenViewProvider.view] and the view
+ * containing the icon using [SplashScreenViewProvider.iconView].
+ *
+ * This class also contains time information about the animated icon (for API 31+).
+ *
+ * The application always needs to call [SplashScreenViewProvider.remove] once it's done
+ * with it.
+ */
+@SuppressLint("ViewConstructor")
+public class SplashScreenViewProvider internal constructor(ctx: Activity) {
+
+ @RequiresApi(31)
+ internal constructor(platformView: SplashScreenView, ctx: Activity) : this(ctx) {
+ (impl as ViewImpl31).platformView = platformView
+ }
+
+ @SuppressLint("NewApi") // TODO(188897399) Remove once "S" is finalized
+ private val impl: ViewImpl = when {
+ Build.VERSION.SDK_INT >= 31 -> ViewImpl31(ctx)
+ Build.VERSION.SDK_INT == 30 && Build.VERSION.PREVIEW_SDK_INT > 0 -> ViewImpl31(ctx)
+ else -> ViewImpl(ctx)
+ }
+
+ /**
+ * The splash screen view, copied into this application process.
+ *
+ * This view can be used to create custom animation from the splash screen to the application
+ */
+ public val view: View get() = impl.splashScreenView
+
+ /**
+ * The view containing the splashscreen icon as defined by
+ * [R.attr.windowSplashScreenAnimatedIcon]
+ */
+ public val iconView: View get() = impl.iconView
+
+ /**
+ * Start time of the icon animation.
+ *
+ * On API 31+, returns the number of millisecond since the Epoch time (1970-1-1T00:00:00Z)
+ *
+ * Below API 31, returns 0 because the icon cannot be animated.
+ */
+ public val iconAnimationStartMillis: Long get() = impl.iconAnimationStartMillis
+
+ /**
+ * Duration of the icon animation as provided in [R.attr.
+ */
+ public val iconAnimationDurationMillis: Long get() = impl.iconAnimationDurationMillis
+
+ /**
+ * Remove the SplashScreen's view from the view hierarchy.
+ *
+ * This always needs to be called when an
+ * [androidx.core.splashscreen.SplashScreen.OnExitAnimationListener]
+ * is set.
+ */
+ public fun remove(): Unit = impl.remove()
+
+ private open class ViewImpl(val activity: Activity) {
+
+ private val _splashScreenView: ViewGroup by lazy {
+ FrameLayout.inflate(
+ activity,
+ R.layout.splash_screen_view,
+ null
+ ) as ViewGroup
+ }
+
+ init {
+ val content = activity.findViewById<ViewGroup>(android.R.id.content)
+ content.addView(_splashScreenView)
+ }
+
+ open val splashScreenView: ViewGroup get() = _splashScreenView
+ open val iconView: View get() = splashScreenView.findViewById(R.id.splashscreen_icon_view)
+ open val iconAnimationStartMillis: Long get() = 0
+ open val iconAnimationDurationMillis: Long get() = 0
+ open fun remove() =
+ activity.findViewById<ViewGroup>(android.R.id.content).removeView(splashScreenView)
+ }
+
+ @RequiresApi(31)
+ private class ViewImpl31(activity: Activity) : ViewImpl(activity) {
+ lateinit var platformView: SplashScreenView
+
+ override val splashScreenView get() = platformView
+
+ override val iconView get() = platformView.iconView!!
+
+ override val iconAnimationStartMillis: Long
+ get() = platformView.iconAnimationStart?.toEpochMilli() ?: 0
+
+ override val iconAnimationDurationMillis: Long
+ get() = platformView.iconAnimationDuration?.toMillis() ?: 0
+
+ override fun remove() = platformView.remove()
+ }
+}
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/java/androidx/core/splashscreen/package-info.java b/core/core-splashscreen/src/main/java/androidx/core/splashscreen/package-info.java
new file mode 100644
index 0000000..904934b
--- /dev/null
+++ b/core/core-splashscreen/src/main/java/androidx/core/splashscreen/package-info.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This Splash Screen library provides compatibility support for the
+ * <code>android.window.SplashScreen</code> APIs down to API 21, with support of the splash
+ * screen icon from API 23.
+ * <p>
+ * It is composed of a compatibility theme
+ * {@link androidx.core.splashscreen.R.style#Theme_SplashScreen}
+ * that needs to be set as the starting theme of the activity and a programmatic API in
+ * {@link androidx.core.splashscreen.SplashScreen}.
+ * <p>
+ * To use it, the theme of the launching Activity must inherit from
+ * <code>Theme.SplashScreen</code>
+ * <p>
+ * <i>AndroidManifest.xml:</i>
+ * <pre class="prettyprint">
+ * <manifest...>
+ * <application>
+ * <activity>
+ * android:name=".MainActivity"
+ * android:theme="@style/Theme.App.Starting"/>
+ * </manifest>
+ * </pre>
+ * <i>res/values/styles.xml:</i>
+ * <pre class="prettyprint">
+ * <resources>
+ * <style name="Theme.App" parent="...">
+ * ...
+ * </style>
+ *
+ * <style name="Theme.App.Starting" parent="Theme.SplashScreen">
+ * <item name="windowSplashScreenBackground">@color/splashScreenBackground</item>
+ * <item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_icon</item>
+ * <item name="windowSplashScreenAnimationDuration">2000</item>
+ * <item name="postSplashScreenTheme">@style/Theme.App</item>
+ * </resources>
+ * </pre>
+ *
+ * <i>MainActivity.java:</i>
+ * <pre class="prettyprint">
+ * class MainActivity : Activity {
+ * fun onCreate() {
+ * super.onCreate()
+ * val splashScreen = installSplashScreen()
+ *
+ * // Set the content view right after installing the splash screen
+ * setContentView(R.layout.main_activity)
+ * }
+ * }
+ * </pre>
+ */
+package androidx.core.splashscreen;
diff --git a/core/core-splashscreen/src/main/res/drawable-v23/compat_splash_screen.xml b/core/core-splashscreen/src/main/res/drawable-v23/compat_splash_screen.xml
new file mode 100644
index 0000000..30562b0
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/drawable-v23/compat_splash_screen.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:gravity="fill">
+ <color android:color="?attr/windowSplashScreenBackground" />
+ </item>
+ <item
+ android:drawable="?attr/windowSplashScreenAnimatedIcon"
+ android:gravity="center"
+ android:width="@dimen/splashscreen_icon_size"
+ android:height="@dimen/splashscreen_icon_size" />
+</layer-list>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/drawable/compat_splash_screen.xml b/core/core-splashscreen/src/main/res/drawable/compat_splash_screen.xml
new file mode 100644
index 0000000..28bd4d5
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/drawable/compat_splash_screen.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?attr/windowSplashScreenBackground" />
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/layout/splash_screen_view.xml b/core/core-splashscreen/src/main/res/layout/splash_screen_view.xml
new file mode 100644
index 0000000..44ab5e19
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/layout/splash_screen_view.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/splashscreen_icon_view"
+ android:layout_width="@dimen/splashscreen_icon_size"
+ android:layout_height="@dimen/splashscreen_icon_size"
+ android:layout_gravity="center" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/values-v27/styles.xml b/core/core-splashscreen/src/main/res/values-v27/styles.xml
new file mode 100644
index 0000000..caa29a6
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/values-v27/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Theme.SplashScreen" parent="Theme.SplashScreenBase">
+ <item name="android:windowLayoutInDisplayCutoutMode">default</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/values-v29/styles.xml b/core/core-splashscreen/src/main/res/values-v29/styles.xml
new file mode 100644
index 0000000..dfc370f
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/values-v29/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Theme.SplashScreen" parent="Theme.SplashScreenBase">
+ <item name="android:enforceStatusBarContrast">false</item>
+ <item name="android:enforceNavigationBarContrast">false</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/values-v31/styles.xml b/core/core-splashscreen/src/main/res/values-v31/styles.xml
new file mode 100644
index 0000000..7f04b15
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/values-v31/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Theme.SplashScreen" parent="android:Theme.DeviceDefault.NoActionBar">
+ <item name="android:windowSplashScreenAnimatedIcon">?windowSplashScreenAnimatedIcon</item>
+ <item name="android:windowSplashScreenBackground">?windowSplashScreenBackground</item>
+ <item name="android:windowSplashScreenAnimationDuration">
+ ?windowSplashScreenAnimationDuration
+ </item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/values/attrs.xml b/core/core-splashscreen/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..5bbfaa3
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/values/attrs.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Icon to set for the splashscreen. <p>
+ On API31+, this can be an animated icon by overriding it in the [res/drawable-v31/]
+ directory Defaults to @drawable/ic_launcher. -->
+ <attr name="windowSplashScreenAnimatedIcon" format="reference" />
+
+ <!-- Background color of the splash screen. Defaults to the theme's windowBackground-->
+ <attr name="windowSplashScreenBackground" format="color" />
+
+ <!-- Duration of the Animated Icon Animation -->
+ <attr name="windowSplashScreenAnimationDuration" format="integer" />
+
+ <!-- Theme to apply to the Activity once the splash screen is dismissed-->
+ <attr name="postSplashScreenTheme" format="reference" />
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/values/dimens.xml b/core/core-splashscreen/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..7c5b998
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="splashscreen_icon_size">160dp</dimen>
+ <integer name="default_icon_animation_duration">10000</integer>
+</resources>
\ No newline at end of file
diff --git a/core/core-splashscreen/src/main/res/values/public.xml b/core/core-splashscreen/src/main/res/values/public.xml
new file mode 100644
index 0000000..f90eec9
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/values/public.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <public name="windowSplashScreenAnimatedIcon" type="attr" />
+ <public name="windowSplashScreenBackground" type="attr" />
+ <public name="windowSplashScreenAnimationDuration" type="attr" />
+ <public name="postSplashScreenTheme" type="attr" />
+ <public name="Theme.SplashScreen" type="style" />
+</resources>
diff --git a/core/core-splashscreen/src/main/res/values/styles.xml b/core/core-splashscreen/src/main/res/values/styles.xml
new file mode 100644
index 0000000..ec205a7
--- /dev/null
+++ b/core/core-splashscreen/src/main/res/values/styles.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Theme.SplashScreenBase" parent="android:Theme.NoTitleBar">
+ <item name="android:windowBackground">@drawable/compat_splash_screen</item>
+ <item name="android:opacity">opaque</item>
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+ <item name="android:fitsSystemWindows">false</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ </style>
+
+ <style name="Theme.SplashScreen" parent="Theme.SplashScreenBase">
+ <item name="postSplashScreenTheme">?android:attr/theme</item>
+ <item name="windowSplashScreenAnimationDuration">
+ @integer/default_icon_animation_duration
+ </item>
+ <item name="windowSplashScreenBackground">@android:color/background_light</item>
+ <item name="windowSplashScreenAnimatedIcon">@android:drawable/sym_def_app_icon</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index d17955a..e120d3b 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -30,6 +30,7 @@
method public static void finishAfterTransition(android.app.Activity);
method public static android.net.Uri? getReferrer(android.app.Activity);
method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
method public static void postponeEnterTransition(android.app.Activity);
method public static void recreate(android.app.Activity);
method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity!, android.view.DragEvent!);
@@ -105,6 +106,7 @@
}
public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
method public static int noteOp(android.content.Context, String, int, String);
method public static int noteOpNoThrow(android.content.Context, String, int, String);
method public static int noteProxyOp(android.content.Context, String, String);
@@ -343,6 +345,9 @@
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
@@ -516,6 +521,7 @@
method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(int);
method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(int);
@@ -1500,16 +1506,52 @@
field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
}
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
public final class LocationManagerCompat {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
method public static String? getGnssHardwareModelName(android.location.LocationManager);
method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
method public static boolean isLocationEnabled(android.location.LocationManager);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, java.util.concurrent.Executor, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, androidx.core.location.LocationListenerCompat, android.os.Looper);
method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
}
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(long);
+ ctor public LocationRequestCompat.Builder(androidx.core.location.LocationRequestCompat);
+ method public androidx.core.location.LocationRequestCompat build();
+ method public androidx.core.location.LocationRequestCompat.Builder clearMinUpdateIntervalMillis();
+ method public androidx.core.location.LocationRequestCompat.Builder setDurationMillis(@IntRange(from=1) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setQuality(int);
+ }
+
}
package androidx.core.math {
@@ -2006,11 +2048,16 @@
method public android.net.Uri? getLinkUri();
method public int getSource();
method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public static android.util.Pair<android.view.ContentInfo!,android.view.ContentInfo!> partition(android.view.ContentInfo, java.util.function.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public android.view.ContentInfo toContentInfo();
+ method @RequiresApi(31) public static androidx.core.view.ContentInfoCompat toContentInfoCompat(android.view.ContentInfo);
field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
field public static final int SOURCE_CLIPBOARD = 1; // 0x1
field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
}
public static final class ContentInfoCompat.Builder {
@@ -2523,7 +2570,7 @@
method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
method public static void setFocusedByDefault(android.view.View, boolean);
method public static void setHasTransientState(android.view.View, boolean);
- method public static void setImportantForAccessibility(android.view.View, int);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
method public static void setImportantForAutofill(android.view.View, int);
method public static void setKeyboardNavigationCluster(android.view.View, boolean);
method public static void setLabelFor(android.view.View, @IdRes int);
@@ -3436,13 +3483,16 @@
public final class EdgeEffectCompat {
ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
method @Deprecated public boolean draw(android.graphics.Canvas!);
method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
method @Deprecated public boolean isFinished();
method @Deprecated public boolean onAbsorb(int);
method @Deprecated public boolean onPull(float);
method @Deprecated public boolean onPull(float, float);
method public static void onPull(android.widget.EdgeEffect, float, float);
+ method public static float onPullDistance(android.widget.EdgeEffect, float, float);
method @Deprecated public boolean onRelease();
method @Deprecated public void setSize(int, int);
}
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index 2f786d1..0f87349 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -30,6 +30,7 @@
method public static void finishAfterTransition(android.app.Activity);
method public static android.net.Uri? getReferrer(android.app.Activity);
method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
method public static void postponeEnterTransition(android.app.Activity);
method public static void recreate(android.app.Activity);
method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity!, android.view.DragEvent!);
@@ -105,6 +106,7 @@
}
public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
method public static int noteOp(android.content.Context, String, int, String);
method public static int noteOpNoThrow(android.content.Context, String, int, String);
method public static int noteProxyOp(android.content.Context, String, String);
@@ -343,6 +345,9 @@
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
@@ -516,6 +521,7 @@
method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(int);
method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(int);
@@ -1500,16 +1506,52 @@
field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
}
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
public final class LocationManagerCompat {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
method public static String? getGnssHardwareModelName(android.location.LocationManager);
method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
method public static boolean isLocationEnabled(android.location.LocationManager);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, java.util.concurrent.Executor, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, androidx.core.location.LocationListenerCompat, android.os.Looper);
method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
}
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(long);
+ ctor public LocationRequestCompat.Builder(androidx.core.location.LocationRequestCompat);
+ method public androidx.core.location.LocationRequestCompat build();
+ method public androidx.core.location.LocationRequestCompat.Builder clearMinUpdateIntervalMillis();
+ method public androidx.core.location.LocationRequestCompat.Builder setDurationMillis(@IntRange(from=1) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setQuality(int);
+ }
+
}
package androidx.core.math {
@@ -2010,11 +2052,16 @@
method public android.net.Uri? getLinkUri();
method public int getSource();
method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public static android.util.Pair<android.view.ContentInfo!,android.view.ContentInfo!> partition(android.view.ContentInfo, java.util.function.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public android.view.ContentInfo toContentInfo();
+ method @RequiresApi(31) public static androidx.core.view.ContentInfoCompat toContentInfoCompat(android.view.ContentInfo);
field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
field public static final int SOURCE_CLIPBOARD = 1; // 0x1
field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
}
public static final class ContentInfoCompat.Builder {
@@ -2527,7 +2574,7 @@
method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
method public static void setFocusedByDefault(android.view.View, boolean);
method public static void setHasTransientState(android.view.View, boolean);
- method public static void setImportantForAccessibility(android.view.View, int);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
method public static void setImportantForAutofill(android.view.View, int);
method public static void setKeyboardNavigationCluster(android.view.View, boolean);
method public static void setLabelFor(android.view.View, @IdRes int);
@@ -3440,13 +3487,16 @@
public final class EdgeEffectCompat {
ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
method @Deprecated public boolean draw(android.graphics.Canvas!);
method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
method @Deprecated public boolean isFinished();
method @Deprecated public boolean onAbsorb(int);
method @Deprecated public boolean onPull(float);
method @Deprecated public boolean onPull(float, float);
method public static void onPull(android.widget.EdgeEffect, float, float);
+ method public static float onPullDistance(android.widget.EdgeEffect, float, float);
method @Deprecated public boolean onRelease();
method @Deprecated public void setSize(int, int);
}
diff --git a/core/core/api/res-current.txt b/core/core/api/res-current.txt
index 36ad356..dd913d3 100644
--- a/core/core/api/res-current.txt
+++ b/core/core/api/res-current.txt
@@ -10,6 +10,7 @@
attr fontStyle
attr fontVariationSettings
attr fontWeight
+attr lStar
attr queryPatterns
attr shortcutMatchRequired
attr ttcIndex
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 6fcfa3f..f788b28 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -44,6 +44,7 @@
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.ActivityCompat.PermissionCompatDelegate! getPermissionCompatDelegate();
method public static android.net.Uri? getReferrer(android.app.Activity);
method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
method public static void postponeEnterTransition(android.app.Activity);
method public static void recreate(android.app.Activity);
method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity!, android.view.DragEvent!);
@@ -123,6 +124,7 @@
}
public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
method public static int noteOp(android.content.Context, String, int, String);
method public static int noteOpNoThrow(android.content.Context, String, int, String);
method public static int noteProxyOp(android.content.Context, String, String);
@@ -388,6 +390,9 @@
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
@@ -548,6 +553,7 @@
method @ColorInt @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getColor();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getContentView();
method public android.os.Bundle getExtras();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getForegroundServiceBehavior();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getHeadsUpContentView();
method @Deprecated public android.app.Notification getNotification();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getPriority();
@@ -573,6 +579,7 @@
method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(@androidx.core.app.NotificationCompat.ServiceNotificationBehavior int);
method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(@androidx.core.app.NotificationCompat.GroupAlertBehavior int);
@@ -700,6 +707,9 @@
@IntDef({androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC, androidx.core.app.NotificationCompat.VISIBILITY_PRIVATE, androidx.core.app.NotificationCompat.VISIBILITY_SECRET}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.NotificationVisibility {
}
+ @IntDef({androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_DEFAULT, androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE, androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_DEFERRED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.ServiceNotificationBehavior {
+ }
+
@IntDef({android.media.AudioManager.STREAM_VOICE_CALL, android.media.AudioManager.STREAM_SYSTEM, android.media.AudioManager.STREAM_RING, android.media.AudioManager.STREAM_MUSIC, android.media.AudioManager.STREAM_ALARM, android.media.AudioManager.STREAM_NOTIFICATION, android.media.AudioManager.STREAM_DTMF, android.media.AudioManager.STREAM_ACCESSIBILITY}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.StreamType {
}
@@ -1821,16 +1831,52 @@
field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
}
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
public final class LocationManagerCompat {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
method public static String? getGnssHardwareModelName(android.location.LocationManager);
method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
method public static boolean isLocationEnabled(android.location.LocationManager);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, java.util.concurrent.Executor, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, androidx.core.location.LocationListenerCompat, android.os.Looper);
method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
}
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(long);
+ ctor public LocationRequestCompat.Builder(androidx.core.location.LocationRequestCompat);
+ method public androidx.core.location.LocationRequestCompat build();
+ method public androidx.core.location.LocationRequestCompat.Builder clearMinUpdateIntervalMillis();
+ method public androidx.core.location.LocationRequestCompat.Builder setDurationMillis(@IntRange(from=1) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setQuality(int);
+ }
+
}
package androidx.core.math {
@@ -2325,7 +2371,11 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class Preconditions {
method public static void checkArgument(boolean);
method public static void checkArgument(boolean, Object);
+ method public static void checkArgument(boolean, String, java.lang.Object!...);
method public static int checkArgumentInRange(int, int, int, String);
+ method public static long checkArgumentInRange(long, long, long, String);
+ method public static float checkArgumentInRange(float, float, float, String);
+ method public static double checkArgumentInRange(double, double, double, String);
method @IntRange(from=0) public static int checkArgumentNonnegative(int, String?);
method @IntRange(from=0) public static int checkArgumentNonnegative(int);
method public static int checkFlagsArgument(int, int);
@@ -2404,11 +2454,16 @@
method public android.net.Uri? getLinkUri();
method @androidx.core.view.ContentInfoCompat.Source public int getSource();
method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public static android.util.Pair<android.view.ContentInfo!,android.view.ContentInfo!> partition(android.view.ContentInfo, java.util.function.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public android.view.ContentInfo toContentInfo();
+ method @RequiresApi(31) public static androidx.core.view.ContentInfoCompat toContentInfoCompat(android.view.ContentInfo);
field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
field public static final int SOURCE_CLIPBOARD = 1; // 0x1
field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
}
public static final class ContentInfoCompat.Builder {
@@ -2425,7 +2480,7 @@
@IntDef(flag=true, value={androidx.core.view.ContentInfoCompat.FLAG_CONVERT_TO_PLAIN_TEXT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Flags {
}
- @IntDef({androidx.core.view.ContentInfoCompat.SOURCE_APP, androidx.core.view.ContentInfoCompat.SOURCE_CLIPBOARD, androidx.core.view.ContentInfoCompat.SOURCE_INPUT_METHOD, androidx.core.view.ContentInfoCompat.SOURCE_DRAG_AND_DROP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Source {
+ @IntDef({androidx.core.view.ContentInfoCompat.SOURCE_APP, androidx.core.view.ContentInfoCompat.SOURCE_CLIPBOARD, androidx.core.view.ContentInfoCompat.SOURCE_INPUT_METHOD, androidx.core.view.ContentInfoCompat.SOURCE_DRAG_AND_DROP, androidx.core.view.ContentInfoCompat.SOURCE_AUTOFILL, androidx.core.view.ContentInfoCompat.SOURCE_PROCESS_TEXT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Source {
}
public final class DisplayCompat {
@@ -2938,7 +2993,7 @@
method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
method public static void setFocusedByDefault(android.view.View, boolean);
method public static void setHasTransientState(android.view.View, boolean);
- method public static void setImportantForAccessibility(android.view.View, int);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
method public static void setImportantForAutofill(android.view.View, int);
method public static void setKeyboardNavigationCluster(android.view.View, boolean);
method public static void setLabelFor(android.view.View, @IdRes int);
@@ -3900,13 +3955,16 @@
public final class EdgeEffectCompat {
ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
method @Deprecated public boolean draw(android.graphics.Canvas!);
method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
method @Deprecated public boolean isFinished();
method @Deprecated public boolean onAbsorb(int);
method @Deprecated public boolean onPull(float);
method @Deprecated public boolean onPull(float, float);
method public static void onPull(android.widget.EdgeEffect, float, float);
+ method public static float onPullDistance(android.widget.EdgeEffect, float, float);
method @Deprecated public boolean onRelease();
method @Deprecated public void setSize(int, int);
}
diff --git a/core/core/build.gradle b/core/core/build.gradle
index 9b0ad01..e45e965 100644
--- a/core/core/build.gradle
+++ b/core/core/build.gradle
@@ -75,6 +75,10 @@
defaultConfig {
multiDexEnabled = true
}
+ // TODO(aurimas): reenable once AGP 7.0-alpha15 lands
+ lintOptions {
+ disable("ClassVerificationFailure", "NewApi")
+ }
}
androidx {
diff --git a/core/core/lint-baseline.xml b/core/core/lint-baseline.xml
index 6ad168e..9f56df7 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.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+<issues format="6" by="lint 7.1.0-alpha06" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-alpha06)" variant="all" version="7.1.0-alpha06">
<issue
id="NewApi"
@@ -113,6 +113,39 @@
<issue
id="NewApi"
+ message="Call requires API level 24 (current min is 14): `java.util.Collection#removeIf`"
+ errorLine1=" transports.removeIf(reference -> reference.get() == null);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/location/LocationManagerCompat.java"
+ line="633"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 19): `toLocationRequest`"
+ errorLine1=" assertEquals(Long.MAX_VALUE, getExpireAt(builder.build().toLocationRequest()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidTest/java/androidx/core/location/LocationRequestCompatTest.java"
+ line="105"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 19): `toLocationRequest`"
+ errorLine1=" assertThat(getExpireAt(builder.build().toLocationRequest())).isIn("
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidTest/java/androidx/core/location/LocationRequestCompatTest.java"
+ line="126"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="NewApi"
message="Call requires API level 26 (current min is 14): `android.app.NotificationChannel#getImportance`"
errorLine1=" boolean equality = nc1.getImportance() == nc2.getImportance()"
errorLine2=" ~~~~~~~~~~~~~">
@@ -569,7 +602,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/androidTest/java/androidx/core/app/NotificationCompatTest.java"
- line="1409"
+ line="1421"
column="68"/>
</issue>
@@ -580,7 +613,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/androidTest/java/androidx/core/app/NotificationCompatTest.java"
- line="1424"
+ line="1436"
column="65"/>
</issue>
@@ -591,7 +624,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/androidTest/java/androidx/core/app/NotificationCompatTest.java"
- line="1440"
+ line="1452"
column="57"/>
</issue>
@@ -602,7 +635,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/androidTest/java/androidx/core/app/NotificationCompatTest.java"
- line="1450"
+ line="1462"
column="54"/>
</issue>
@@ -613,7 +646,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/core/app/NotificationCompatTest.java"
- line="2017"
+ line="2029"
column="17"/>
</issue>
@@ -624,7 +657,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/core/app/NotificationCompatTest.java"
- line="2229"
+ line="2241"
column="36"/>
</issue>
@@ -1152,7 +1185,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4623"
+ line="4707"
column="47"/>
</issue>
@@ -1163,7 +1196,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="6243"
+ line="6327"
column="31"/>
</issue>
@@ -1174,7 +1207,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="7276"
+ line="7360"
column="35"/>
</issue>
@@ -1185,7 +1218,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="384"
+ line="390"
column="49"/>
</issue>
@@ -1300,6 +1333,17 @@
</issue>
<issue
+ id="WrongConstant"
+ message="Must be one of: WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH, WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE, WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, but could be WindowInsetsController.BEHAVIOR_DEFAULT"
+ errorLine1=" return mInsetsController.getSystemBarsBehavior();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/view/WindowInsetsControllerCompat.java"
+ line="723"
+ column="20"/>
+ </issue>
+
+ <issue
id="BanUncheckedReflection"
message="Calling `Method.invoke` without an SDK check"
errorLine1=" requestRelaunchActivityMethod.invoke(activityThread,"
@@ -1471,7 +1515,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="689"
+ line="687"
column="29"/>
</issue>
@@ -1608,10115 +1652,6 @@
</issue>
<issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.AccessibilityDelegateCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Object provider = mOriginalDelegate.getAccessibilityNodeProvider(host);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/AccessibilityDelegateCompat.java"
- line="320"
- column="49"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.AccessibilityDelegateCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" success = mOriginalDelegate.performAccessibilityAction(host, action, args);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/AccessibilityDelegateCompat.java"
- line="355"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityEventCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" event.setContentChangeTypes(changeTypes);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java"
- line="323"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityEventCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return event.getContentChangeTypes();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java"
- line="344"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityEventCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" event.setMovementGranularity(granularity);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java"
- line="359"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityEventCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return event.getMovementGranularity();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java"
- line="370"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityEventCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" event.setAction(action);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java"
- line="395"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityEventCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return event.getAction();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java"
- line="406"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return manager.addTouchExplorationStateChangeListener("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java"
- line="172"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return manager.removeTouchExplorationStateChangeListener("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java"
- line="191"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mAction = new AccessibilityNodeInfo.AccessibilityAction(id, label);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="641"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getId();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="655"
- column="78"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getLabel();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="669"
- column="78"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="780"
- column="86"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="783"
- column="86"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="802"
- column="86"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getColumnCount();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="820"
- column="71"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getRowCount();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="833"
- column="71"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionInfo) mInfo).isHierarchical();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="846"
- column="71"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getSelectionMode();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="864"
- column="71"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="901"
- column="94"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="904"
- column="94"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="926"
- column="94"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnIndex();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="944"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnSpan();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="957"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowIndex();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="970"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowSpan();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="983"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isHeading();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1000"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isSelected();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1013"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current));"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1043"
- column="57"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.RangeInfo) mInfo).getCurrent();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1062"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMax();"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1075"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMin();"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1088"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityNodeInfo.RangeInfo) mInfo).getType();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1105"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo = new TouchDelegateInfo(targetMap);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1125"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getRegionCount();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1147"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getRegionAt(index);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1166"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AccessibilityNodeInfo info = mInfo.getTargetForRegion(region);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1194"
- column="52"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AccessibilityNodeInfo.obtain(root, virtualDescendantId));"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1755"
- column="43"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setSource(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1817"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.findFocus(focus));"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1834"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.focusSearch(direction));"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1856"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.addChild(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1928"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.removeChild(child);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1948"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.removeChild(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="1966"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ArrayList<Integer> list = mInfo.getExtras()"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2004"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().putIntegerArrayList(key, list);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2008"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.addAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2031"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.removeAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2056"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.performAction(action, arguments);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2093"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setMovementGranularities(granularities);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2113"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getMovementGranularities();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2124"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setParent(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2210"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isVisibleToUser();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2380"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setVisibleToUser(visibleToUser);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2400"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isAccessibilityFocused();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2411"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setAccessibilityFocused(focused);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2431"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isImportantForAccessibility();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2589"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setImportantForAccessibility(important);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2608"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().remove(SPANS_START_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2767"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().remove(SPANS_END_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2768"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().remove(SPANS_FLAGS_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2769"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().remove(SPANS_ID_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2770"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getStateDescription();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2813"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getExtras().getCharSequence(STATE_DESCRIPTION_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2815"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setStateDescription(stateDescription);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2848"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().putCharSequence(STATE_DESCRIPTION_KEY, stateDescription);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2850"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setViewIdResourceName(viewId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2878"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getViewIdResourceName();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2896"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getLiveRegion();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2922"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setLiveRegion(mode);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2942"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getDrawingOrder();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2959"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setDrawingOrder(drawingOrderInParent);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2978"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AccessibilityNodeInfo.CollectionInfo info = mInfo.getCollectionInfo();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="2990"
- column="63"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setCollectionInfo((collectionInfo == null) ? null"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3000"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setCollectionItemInfo((collectionItemInfo == null) ? null"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3009"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AccessibilityNodeInfo.CollectionItemInfo info = mInfo.getCollectionItemInfo();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3023"
- column="67"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AccessibilityNodeInfo.RangeInfo info = mInfo.getRangeInfo();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3038"
- column="58"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo.mInfo);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3058"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actions = (List<Object>) (List<?>) mInfo.getActionList();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3076"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setContentInvalid(contentInvalid);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3104"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isContentInvalid();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3116"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isContextClickable();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3129"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setContextClickable(contextClickable);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3148"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getHintText();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3159"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getExtras().getCharSequence(HINT_TEXT_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3161"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setHintText(hintText);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3181"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().putCharSequence(HINT_TEXT_KEY, hintText);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3183"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setError(error);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3202"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getError();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3213"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setLabelFor(labeled);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3227"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setLabelFor(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3247"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabelFor());"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3264"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setLabeledBy(label);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3278"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setLabeledBy(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3303"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabeledBy());"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3320"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.canOpenPopup();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3333"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setCanOpenPopup(opensPopup);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3351"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" List<AccessibilityNodeInfo> nodes = mInfo.findAccessibilityNodeInfosByViewId(viewId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3380"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getExtras();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3406"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getInputType();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3419"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setInputType(inputType);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3440"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setMaxTextLength(max);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3461"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getMaxTextLength();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3473"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTextSelection(start, end);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3494"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getTextSelectionStart();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3505"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getTextSelectionEnd();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3518"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalBefore());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3535"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTraversalBefore(view);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3557"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTraversalBefore(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3584"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalAfter());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3600"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTraversalAfter(view);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3622"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTraversalAfter(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3648"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AccessibilityWindowInfoCompat.wrapNonNullInstance(mInfo.getWindow());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3661"
- column="76"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isDismissable();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3674"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setDismissable(dismissable);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3692"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isEditable();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3703"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setEditable(editable);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3723"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isMultiLine();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3734"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setMultiLine(multiLine);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3752"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getTooltipText();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3764"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getExtras().getCharSequence(TOOLTIP_TEXT_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3766"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTooltipText(tooltipText);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3786"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().putCharSequence(TOOLTIP_TEXT_KEY, tooltipText);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3788"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setPaneTitle(paneTitle);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3806"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().putCharSequence(PANE_TITLE_KEY, paneTitle);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3808"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getPaneTitle();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3820"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getExtras().getCharSequence(PANE_TITLE_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3822"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isScreenReaderFocusable();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3839"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setScreenReaderFocusable(screenReaderFocusable);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3858"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isShowingHintText();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3873"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setShowingHintText(showingHintText);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3893"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isHeading();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3910"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setHeading(isHeading);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3930"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.isTextEntryKey();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3943"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTextEntryKey(isTextEntryKey);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3961"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.refresh();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3978"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mInfo.getExtras().getCharSequence(ROLE_DESCRIPTION_KEY);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="3990"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="4022"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" TouchDelegateInfo delegateInfo = mInfo.getTouchDelegateInfo();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="4044"
- column="52"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.accessibility.AccessibilityNodeInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.setTouchDelegateInfo(delegatedInfo.mInfo);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java"
- line="4071"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.accessibility.AccessibilityRecordCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" record.setSource(root, virtualDescendantId);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java"
- line="140"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.view.accessibility.AccessibilityRecordCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return record.getMaxScrollX();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java"
- line="483"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.view.accessibility.AccessibilityRecordCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" record.setMaxScrollX(maxScrollX);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java"
- line="509"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.view.accessibility.AccessibilityRecordCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return record.getMaxScrollY();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java"
- line="533"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.view.accessibility.AccessibilityRecordCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" record.setMaxScrollY(maxScrollY);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java"
- line="559"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.accessibilityservice.AccessibilityServiceInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return info.loadDescription(packageManager);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java"
- line="199"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.accessibilityservice.AccessibilityServiceInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return info.getCapabilities();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java"
- line="288"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).getType();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="100"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).getLayer();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="114"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ((AccessibilityWindowInfo) mInfo).getRoot());"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="128"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return wrapNonNullInstance(((AccessibilityWindowInfo) mInfo).getParent());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="141"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).getId();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="154"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ((AccessibilityWindowInfo) mInfo).getBoundsInScreen(outBounds);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="167"
- column="47"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).isActive();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="180"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).isFocused();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="193"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).isAccessibilityFocused();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="206"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).getChildCount();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="219"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return wrapNonNullInstance(((AccessibilityWindowInfo) mInfo).getChild(index));"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="233"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((AccessibilityWindowInfo) mInfo).getTitle();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="247"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ((AccessibilityWindowInfo) mInfo).getAnchor());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="261"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return wrapNonNullInstance(AccessibilityWindowInfo.obtain());"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="275"
- column="64"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AccessibilityWindowInfo.obtain((AccessibilityWindowInfo) info.mInfo));"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="294"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.accessibility.AccessibilityWindowInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ((AccessibilityWindowInfo) mInfo).recycle();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java"
- line="310"
- column="47"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.startActivityForResult(intent, requestCode, options);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="237"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="274"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.finishAffinity();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="291"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.finishAfterTransition();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="308"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return activity.getReferrer();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="333"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return activity.requireViewById(id);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="366"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.setEnterSharedElementCallback(frameworkCallback);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="390"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.setExitSharedElementCallback(frameworkCallback);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="409"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.postponeEnterTransition();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="415"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.startPostponedEnterTransition();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="421"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.requestPermissions(permissions, requestCode);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="516"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.ActivityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return activity.shouldShowRequestPermissionRationale(permission);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="553"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" listener.onSharedElementsReady();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="697"
- column="38"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.ActivityManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return activityManager.isLowRamDevice();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityManagerCompat.java"
- line="41"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new ActivityOptionsCompatImpl(ActivityOptions.makeCustomAnimation(context,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="69"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new ActivityOptionsCompatImpl(ActivityOptions.makeScaleUpAnimation("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="99"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new ActivityOptionsCompatImpl(ActivityOptions.makeClipRevealAnimation("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="123"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new ActivityOptionsCompatImpl(ActivityOptions.makeThumbnailScaleUpAnimation("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="152"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new ActivityOptionsCompatImpl(ActivityOptions.makeSceneTransitionAnimation("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="180"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ActivityOptions.makeSceneTransitionAnimation(activity, pairs));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="217"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new ActivityOptionsCompatImpl(ActivityOptions.makeTaskLaunchBehind());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="235"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.ActivityOptionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new ActivityOptionsCompatImpl(ActivityOptions.makeBasic());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="247"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.ActivityOptionsCompat.ActivityOptionsCompatImpl is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mActivityOptions.requestUsageTimeReport(receiver);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="277"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.ActivityOptionsCompat.ActivityOptionsCompatImpl is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mActivityOptions.setLaunchBounds(screenSpacePixelRect));"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="288"
- column="38"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.ActivityOptionsCompat.ActivityOptionsCompatImpl is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mActivityOptions.getLaunchBounds();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ActivityOptionsCompat.java"
- line="296"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.AlarmManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(triggerTime, showIntent),"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AlarmManagerCompat.java"
- line="60"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.AlarmManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(triggerTime, showIntent),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AlarmManagerCompat.java"
- line="60"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.AlarmManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" alarmManager.setAndAllowWhileIdle(type, triggerAtMillis, operation);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AlarmManagerCompat.java"
- line="118"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.AlarmManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" alarmManager.setExact(type, triggerAtMillis, operation);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AlarmManagerCompat.java"
- line="163"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.AlarmManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, operation);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AlarmManagerCompat.java"
- line="223"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.AppOpsManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return AppOpsManager.permissionToOp(permission);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppOpsManagerCompat.java"
- line="76"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.AppOpsManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return appOpsManager.noteOp(op, uid, packageName);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppOpsManagerCompat.java"
- line="107"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.AppOpsManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return appOpsManager.noteOpNoThrow(op, uid, packageName);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppOpsManagerCompat.java"
- line="127"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.AppOpsManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppOpsManagerCompat.java"
- line="157"
- column="51"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.AppOpsManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return appOpsManager.noteProxyOp(op, proxiedPackageName);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppOpsManagerCompat.java"
- line="158"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.AppOpsManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppOpsManagerCompat.java"
- line="176"
- column="51"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.AppOpsManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return appOpsManager.noteProxyOpNoThrow(op, proxiedPackageName);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppOpsManagerCompat.java"
- line="177"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.graphics.BitmapCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return bitmap.hasMipMap();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/BitmapCompat.java"
- line="29"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.graphics.BitmapCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" bitmap.setHasMipMap(hasMipMap);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/BitmapCompat.java"
- line="36"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.BitmapCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return bitmap.getAllocationByteCount();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/BitmapCompat.java"
- line="49"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.graphics.BlendModeColorFilterCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ? new BlendModeColorFilter(color, blendMode) : null;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/BlendModeColorFilterCompat.java"
- line="45"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.app.BundleCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return bundle.getBinder(key);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/BundleCompat.java"
- line="106"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.app.BundleCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" bundle.putBinder(key, binder);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/BundleCompat.java"
- line="122"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.os.CancellationSignal is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ((android.os.CancellationSignal) obj).cancel();"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/os/CancellationSignal.java"
- line="84"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.os.CancellationSignal is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mCancellationSignalObj = new android.os.CancellationSignal();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/CancellationSignal.java"
- line="143"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.os.CancellationSignal is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ((android.os.CancellationSignal) mCancellationSignalObj).cancel();"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/os/CancellationSignal.java"
- line="145"
- column="78"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!Objects.equals(foreground.getModel(), background.getModel())) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="92"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!Objects.equals(foreground.getModel(), background.getModel())) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="92"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!Objects.equals(foreground.getModel(), background.getModel())) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="92"
- column="63"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" "Color models must match (" + foreground.getModel() + " vs. ""
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="94"
- column="62"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" + background.getModel() + ")");"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="95"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Color s = Objects.equals(background.getColorSpace(), foreground.getColorSpace())"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="98"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Color s = Objects.equals(background.getColorSpace(), foreground.getColorSpace())"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="98"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Color s = Objects.equals(background.getColorSpace(), foreground.getColorSpace())"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="98"
- column="73"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" : foreground.convert(background.getColorSpace());"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="100"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" : foreground.convert(background.getColorSpace());"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="100"
- column="49"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" float[] src = s.getComponents();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="102"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" float[] dst = background.getComponents();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="103"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" float sa = s.alpha();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="105"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" float da = background.alpha() * (1.0f - sa);"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="107"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" int ai = background.getComponentCount() - 1;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="111"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Color.valueOf(dst, background.getColorSpace());"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="127"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.ColorUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Color.valueOf(dst, background.getColorSpace());"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/ColorUtils.java"
- line="127"
- column="46"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.CompoundButtonCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" button.setButtonTintList(tint);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/CompoundButtonCompat.java"
- line="58"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.CompoundButtonCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return button.getButtonTintList();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/CompoundButtonCompat.java"
- line="72"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.CompoundButtonCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" button.setButtonTintMode(tintMode);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/CompoundButtonCompat.java"
- line="94"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.CompoundButtonCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return button.getButtonTintMode();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/CompoundButtonCompat.java"
- line="108"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.CompoundButtonCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return button.getButtonDrawable();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/CompoundButtonCompat.java"
- line="124"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.os.ConfigurationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return LocaleListCompat.wrap(configuration.getLocales());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/ConfigurationCompat.java"
- line="42"
- column="56"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.net.ConnectivityManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return cm.isActiveNetworkMetered();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/net/ConnectivityManagerCompat.java"
- line="101"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.net.ConnectivityManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return cm.getRestrictBackgroundStatus();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/net/ConnectivityManagerCompat.java"
- line="160"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.content.ContentResolverCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return resolver.query(uri, projection, selection, selectionArgs, sortOrder,"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/content/ContentResolverCompat.java"
- line="81"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.database.CursorWindowCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CursorWindow(name, windowSizeBytes);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/database/CursorWindowCompat.java"
- line="43"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.database.CursorWindowCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CursorWindow(name);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/database/CursorWindowCompat.java"
- line="45"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.DialogCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return dialog.requireViewById(id);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/DialogCompat.java"
- line="56"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.view.DisplayCompat.ModeCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPhysicalSize = new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight());"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCompat.java"
- line="346"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.view.DisplayCompat.ModeCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPhysicalSize = new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCompat.java"
- line="346"
- column="69"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" this(SDK_INT >= 28 ? new DisplayCutout(safeInsets, boundingRects) : null);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="56"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new DisplayCutout(safeInsets.toPlatformInsets(), boundLeft,"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="85"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new DisplayCutout(safeInsets.toPlatformInsets(), boundLeft,"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="88"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new DisplayCutout(safeInsetRect, boundingRects);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="106"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((DisplayCutout) mDisplayCutout).getSafeInsetTop();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="119"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((DisplayCutout) mDisplayCutout).getSafeInsetBottom();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="128"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((DisplayCutout) mDisplayCutout).getSafeInsetLeft();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="137"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((DisplayCutout) mDisplayCutout).getSafeInsetRight();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="146"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((DisplayCutout) mDisplayCutout).getBoundingRects();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="164"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.view.DisplayCutoutCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Insets.toCompatInsets(((DisplayCutout) mDisplayCutout).getWaterfallInsets());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DisplayCutoutCompat.java"
- line="183"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.hardware.display.DisplayManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .getDisplay(displayId);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java"
- line="86"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.hardware.display.DisplayManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .getDisplays();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java"
- line="106"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.hardware.display.DisplayManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .getDisplays(category);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java"
- line="135"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.DragAndDropPermissionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" activity.requestDragAndDropPermissions(dragEvent);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DragAndDropPermissionsCompat.java"
- line="52"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.DragAndDropPermissionsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ((DragAndDropPermissions) mDragAndDropPermissions).release();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/DragAndDropPermissionsCompat.java"
- line="65"
- column="64"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.setAutoMirrored(mirrored);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="79"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return drawable.isAutoMirrored();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="96"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.setHotspot(x, y);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="111"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.setHotspotBounds(left, top, right, bottom);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="124"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.setTint(tint);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="136"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.setTintList(tint);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="150"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.setTintMode(tintMode);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="164"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return drawable.getAlpha();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="178"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.applyTheme(theme);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="189"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return drawable.canApplyTheme();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="198"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return drawable.getColorFilter();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="211"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" clearColorFilter(((InsetDrawable) drawable).getDrawable());"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="232"
- column="61"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" child = state.getChild(i);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="242"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" drawable.inflate(res, parser, attrs, theme);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="269"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return drawable.setLayoutDirection(layoutDirection);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="355"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.DrawableCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return drawable.getLayoutDirection();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/DrawableCompat.java"
- line="392"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.EdgeEffectCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" edgeEffect.onPull(deltaDistance, displacement);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/EdgeEffectCompat.java"
- line="153"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.os.EnvironmentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Environment.getExternalStorageState(path);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/EnvironmentCompat.java"
- line="60"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.os.EnvironmentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Environment.getStorageState(path);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/EnvironmentCompat.java"
- line="62"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.FileProvider is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" File[] externalMediaDirs = context.getExternalMediaDirs();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/FileProvider.java"
- line="702"
- column="56"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return (fp != null) && fp.hasEnrolledFingerprints();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="68"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return (fp != null) && fp.isHardwareDetected();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="83"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" fp.authenticate("
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="113"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(FingerprintManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="127"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(FingerprintManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="130"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new FingerprintManager.CryptoObject(cryptoObject.getCipher());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="141"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new FingerprintManager.CryptoObject(cryptoObject.getSignature());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="143"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new FingerprintManager.CryptoObject(cryptoObject.getMac());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="145"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" } else if (cryptoObject.getCipher() != null) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="155"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CryptoObject(cryptoObject.getCipher());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="156"
- column="50"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" } else if (cryptoObject.getSignature() != null) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="157"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CryptoObject(cryptoObject.getSignature());"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="158"
- column="50"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" } else if (cryptoObject.getMac() != null) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="159"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.hardware.fingerprint.FingerprintManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new CryptoObject(cryptoObject.getMac());"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="160"
- column="50"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" unwrapCryptoObject(result.getCryptoObject())));"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java"
- line="183"
- column="51"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.provider.FontProvider is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" cursor = context.getContentResolver().query(uri, projection, "query = ?","
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/provider/FontProvider.java"
- line="138"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.res.FontResourcesParserCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return typedArray.getType(index);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/res/FontResourcesParserCompat.java"
- line="254"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric(android.view.FrameMetrics.TOTAL_DURATION));"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="355"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="359"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="364"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric(android.view.FrameMetrics.DRAW_DURATION));"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="369"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric(android.view.FrameMetrics.SYNC_DURATION));"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="373"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="377"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="382"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="387"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class null is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameMetrics.getMetric("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/FrameMetricsAggregator.java"
- line="392"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.location.GnssStatusWrapper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mWrapped.hasCarrierFrequencyHz(satelliteIndex);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/GnssStatusWrapper.java"
- line="89"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.location.GnssStatusWrapper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mWrapped.getCarrierFrequencyHz(satelliteIndex);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/GnssStatusWrapper.java"
- line="98"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.location.GnssStatusWrapper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mWrapped.hasBasebandCn0DbHz(satelliteIndex);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/GnssStatusWrapper.java"
- line="107"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.location.GnssStatusWrapper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mWrapped.getBasebandCn0DbHz(satelliteIndex);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/GnssStatusWrapper.java"
- line="116"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.GravityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Gravity.apply(gravity, w, h, container, outRect, layoutDirection);"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/view/GravityCompat.java"
- line="65"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.GravityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Gravity.apply(gravity, w, h, container, xAdj, yAdj, outRect, layoutDirection);"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/view/GravityCompat.java"
- line="99"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.GravityCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Gravity.applyDisplay(gravity, display, inoutObj, layoutDirection);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/GravityCompat.java"
- line="127"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.HtmlCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Html.fromHtml(source, flags);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/HtmlCompat.java"
- line="148"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.HtmlCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Html.fromHtml(source, flags, imageGetter, tagHandler);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/HtmlCompat.java"
- line="163"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.HtmlCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Html.toHtml(text, options);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/text/HtmlCompat.java"
- line="176"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.ICUCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ULocale uLocale = ULocale.addLikelySubtags(ULocale.forLocale(locale));"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/ICUCompat.java"
- line="90"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.ICUCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ULocale uLocale = ULocale.addLikelySubtags(ULocale.forLocale(locale));"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/ICUCompat.java"
- line="90"
- column="64"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.ICUCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return uLocale.getScript();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/ICUCompat.java"
- line="91"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.ICUCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((Locale) sAddLikelySubtagsMethod.invoke(null, args)).getScript();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/ICUCompat.java"
- line="95"
- column="78"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.ICUCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return locale.getScript();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/ICUCompat.java"
- line="101"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithBitmap((Bitmap) mObj1);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="546"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithAdaptiveBitmap((Bitmap) mObj1);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="550"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithBitmap("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="552"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithResource(getResPackage(), mInt1);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="557"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithData((byte[]) mObj1, mInt1, mInt2);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="560"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithContentUri((String) mObj1);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="563"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithAdaptiveBitmapContentUri(getUri());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="567"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeStream(is));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="580"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon = Icon.createWithBitmap(createLegacyIconFromAdaptiveIcon("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="582"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon.setTintList(mTintList);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="590"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" icon.setTintMode(mTintMode);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="593"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return toIcon(context).loadDrawable(context);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="641"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new AdaptiveIconDrawable(null,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="694"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return icon.getType();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="1101"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return icon.getResPackage();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="1129"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return icon.getResId();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="1158"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.graphics.drawable.IconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return icon.getUri();"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/drawable/IconCompat.java"
- line="1186"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.ImageViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return view.getImageTintList();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ImageViewCompat.java"
- line="38"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.ImageViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.setImageTintList(tintList);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ImageViewCompat.java"
- line="51"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.ImageViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if ((imageViewDrawable != null) && (view.getImageTintList() != null)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ImageViewCompat.java"
- line="57"
- column="58"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.ImageViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return view.getImageTintMode();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ImageViewCompat.java"
- line="75"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.ImageViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.setImageTintMode(mode);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ImageViewCompat.java"
- line="89"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.ImageViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if ((imageViewDrawable != null) && (view.getImageTintList() != null)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ImageViewCompat.java"
- line="95"
- column="58"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.view.inputmethod.InputConnectionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return inputConnection.commitContent("
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java"
- line="157"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.graphics.Insets is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return android.graphics.Insets.of(left, top, right, bottom);"
- errorLine2=" ~~">
- <location
- file="src/main/java/androidx/core/graphics/Insets.java"
- line="198"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.content.IntentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Intent.makeMainSelectorActivity(selectorAction, selectorCategory);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/IntentCompat.java"
- line="118"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.JobIntentService.JobServiceEngineImpl.WrapperWorkItem is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mJobWork.getIntent();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/JobIntentService.java"
- line="265"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.JobIntentService.JobServiceEngineImpl.WrapperWorkItem is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mParams.completeWork(mJobWork);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/JobIntentService.java"
- line="272"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.util.LinkifyCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Linkify.addLinks(text, pattern, defaultScheme, schemes, matchFilter, transformFilter);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/util/LinkifyCompat.java"
- line="258"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.util.LinkifyCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Linkify.addLinks(spannable, pattern, defaultScheme, schemes, matchFilter,"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/util/LinkifyCompat.java"
- line="333"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.widget.ListPopupWindowCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return listPopupWindow.createDragToOpenListener(src);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ListPopupWindowCompat.java"
- line="98"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.widget.ListViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" listView.scrollListBy(y);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ListViewCompat.java"
- line="39"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.widget.ListViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return listView.canScrollList(direction);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/ListViewCompat.java"
- line="69"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.os.LocaleListCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return wrap(new LocaleList(localeList));"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/LocaleListCompat.java"
- line="74"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.os.LocaleListCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ? Locale.forLanguageTag(tags[i])"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/LocaleListCompat.java"
- line="165"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.os.LocaleListCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return LocaleListCompat.wrap(LocaleList.getAdjustedDefault());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/LocaleListCompat.java"
- line="206"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.os.LocaleListCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return LocaleListCompat.wrap(LocaleList.getDefault());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/LocaleListCompat.java"
- line="226"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.os.LocaleListCompatWrapper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final String script = locale.getScript();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/LocaleListCompatWrapper.java"
- line="163"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.location.LocationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (locationManager.registerGnssStatusCallback(executor, transport)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/LocationManagerCompat.java"
- line="281"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.location.LocationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (locationManager.registerGnssStatusCallback(transport, baseHandler)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/LocationManagerCompat.java"
- line="300"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.location.LocationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" locationManager.unregisterGnssStatusCallback(transport);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/LocationManagerCompat.java"
- line="385"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.location.LocationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" locationManager.unregisterGnssStatusCallback(transport);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/location/LocationManagerCompat.java"
- line="394"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return lp.getMarginStart();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="43"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return lp.getMarginEnd();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="62"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" lp.setMarginStart(marginStart);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="81"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" lp.setMarginEnd(marginEnd);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="100"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return lp.isMarginRelative();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="113"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result = lp.getLayoutDirection();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="128"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" lp.setLayoutDirection(layoutDirection);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="151"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.view.MarginLayoutParamsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" lp.resolveLayoutDirection(layoutDirection);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MarginLayoutParamsCompat.java"
- line="162"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.telephony.mbms.MbmsHelper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" LocaleList localeList = context.getResources().getConfiguration().getLocales();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/telephony/mbms/MbmsHelper.java"
- line="60"
- column="75"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.telephony.mbms.MbmsHelper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" int numLanguagesSupportedByService = serviceInfo.getNamedContentLocales().size();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/telephony/mbms/MbmsHelper.java"
- line="62"
- column="58"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.telephony.mbms.MbmsHelper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" for (Locale l : serviceInfo.getNamedContentLocales()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/telephony/mbms/MbmsHelper.java"
- line="69"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.telephony.mbms.MbmsHelper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" supportedLanguages[i] = l.toLanguageTag();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/telephony/mbms/MbmsHelper.java"
- line="70"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.telephony.mbms.MbmsHelper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Locale bestLocale = localeList.getFirstMatch(supportedLanguages);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/telephony/mbms/MbmsHelper.java"
- line="74"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.telephony.mbms.MbmsHelper is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return bestLocale == null ? null : serviceInfo.getNameForLocale(bestLocale);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/telephony/mbms/MbmsHelper.java"
- line="75"
- column="56"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.MenuCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" menu.setGroupDividerEnabled(enabled);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuCompat.java"
- line="49"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" item.setContentDescription(contentDescription);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="325"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return item.getContentDescription();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="339"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" item.setTooltipText(tooltipText);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="354"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return item.getTooltipText();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="368"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" item.setShortcut(numericChar, alphaChar, numericModifiers, alphaModifiers);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="401"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" item.setNumericShortcut(numericChar, numericModifiers);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="421"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return item.getNumericModifiers();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="440"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" item.setAlphabeticShortcut(alphaChar, alphaModifiers);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="466"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return item.getAlphabeticModifiers();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="485"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" item.setIconTintList(tint);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="506"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return item.getIconTintList();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="519"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" item.setIconTintMode(tintMode);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="537"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.MenuItemCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return item.getIconTintMode();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/MenuItemCompat.java"
- line="552"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.os.MessageCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" message.setAsynchronous(async);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/MessageCompat.java"
- line="72"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.os.MessageCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" message.setAsynchronous(async);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/MessageCompat.java"
- line="79"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.os.MessageCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return message.isAsynchronous();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/MessageCompat.java"
- line="98"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.os.MessageCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return message.isAsynchronous();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/MessageCompat.java"
- line="104"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NavUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return sourceActivity.shouldUpRecreateTask(targetIntent);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NavUtils.java"
- line="61"
- column="35"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NavUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sourceActivity.navigateUpTo(upIntent);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NavUtils.java"
- line="109"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NavUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Intent result = sourceActivity.getParentActivityIntent();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NavUtils.java"
- line="132"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.NestedScrollView is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="2008"
- column="77"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.NestedScrollView is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="2012"
- column="78"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.NestedScrollView is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="2029"
- column="77"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.widget.NestedScrollView is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="2033"
- column="78"/>
- </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"
- line="284"
- column="22"/>
- </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"
- line="284"
- column="39"/>
- </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"
- line="286"
- column="25"/>
- </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"
- line="287"
- column="32"/>
- </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"
- line="288"
- column="28"/>
- </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"
- line="289"
- column="30"/>
- </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"
- line="290"
- column="26"/>
- </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"
- line="291"
- column="36"/>
- </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"
- line="292"
- column="27"/>
- </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"
- line="293"
- column="31"/>
- </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"
- line="294"
- column="37"/>
- </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"
- line="295"
- column="37"/>
- </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"
- line="297"
- column="33"/>
- </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"
- line="298"
- column="39"/>
- </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"
- line="301"
- column="30"/>
- </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"
- line="302"
- column="41"/>
- </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"
- line="304"
- column="34"/>
- </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"
- line="307"
- column="46"/>
- </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"
- line="320"
- column="39"/>
- </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"
- line="321"
- column="17"/>
- </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"
- line="322"
- column="17"/>
- </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"
- line="323"
- column="17"/>
- </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"
- line="324"
- column="17"/>
- </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"
- line="325"
- column="17"/>
- </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"
- line="326"
- column="17"/>
- </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"
- line="327"
- column="17"/>
- </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"
- line="328"
- column="17"/>
- </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"
- line="330"
- column="21"/>
- </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"
- line="115"
- column="20"/>
- </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"
- line="117"
- column="23"/>
- </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"
- line="119"
- column="34"/>
- </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"
- line="123"
- column="30"/>
- </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"
- line="124"
- column="49"/>
- </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"
- line="136"
- column="36"/>
- </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"
- line="152"
- column="42"/>
- </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"
- line="154"
- column="19"/>
- </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"
- line="959"
- column="48"/>
- </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"
- line="1466"
- column="49"/>
- </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"
- line="1467"
- column="26"/>
- </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"
- line="1468"
- column="26"/>
- </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"
- line="1469"
- column="26"/>
- </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"
- line="1495"
- column="49"/>
- </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"
- line="1496"
- column="26"/>
- </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"
- line="1497"
- column="26"/>
- </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"
- line="1498"
- column="26"/>
- </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"
- line="2048"
- column="45"/>
- </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"
- line="2049"
- column="26"/>
- </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"
- line="2082"
- column="45"/>
- </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"
- line="2083"
- column="26"/>
- </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"
- line="2117"
- column="46"/>
- </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"
- line="2118"
- column="40"/>
- </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"
- line="2788"
- column="33"/>
- </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"
- line="2792"
- column="29"/>
- </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"
- line="2803"
- column="37"/>
- </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"
- line="2884"
- column="27"/>
- </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"
- line="3002"
- column="25"/>
- </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"
- line="3003"
- column="34"/>
- </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=" .bigPicture(mPicture);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="3004"
- column="34"/>
- </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"
- line="3197"
- column="25"/>
- </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"
- line="3198"
- column="34"/>
- </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"
- line="3199"
- column="34"/>
- </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"
- line="3201"
- column="27"/>
- </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"
- line="3548"
- column="38"/>
- </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"
- line="3550"
- column="38"/>
- </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"
- line="3554"
- column="36"/>
- </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"
- line="3559"
- column="40"/>
- </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"
- line="3571"
- column="36"/>
- </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"
- line="3577"
- column="36"/>
- </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"
- line="3579"
- column="32"/>
- </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"
- line="3612"
- column="21"/>
- </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"
- line="3613"
- column="30"/>
- </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"
- line="3614"
- column="30"/>
- </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"
- line="4000"
- column="40"/>
- </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"
- line="4004"
- column="40"/>
- </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"
- line="4010"
- column="38"/>
- </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"
- line="4101"
- column="25"/>
- </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"
- line="4102"
- column="34"/>
- </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"
- line="4104"
- column="27"/>
- </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"
- line="4107"
- column="27"/>
- </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"
- line="4201"
- column="38"/>
- </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"
- line="4201"
- column="47"/>
- </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"
- line="4319"
- column="24"/>
- </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"
- line="4603"
- column="59"/>
- </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"
- line="4604"
- column="78"/>
- </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"
- line="4612"
- column="69"/>
- </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"
- line="4620"
- column="61"/>
- </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"
- line="4623"
- column="54"/>
- </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"
- line="4626"
- column="50"/>
- </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"
- line="5461"
- column="33"/>
- </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"
- line="5470"
- column="33"/>
- </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"
- line="5482"
- column="31"/>
- </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"
- line="5484"
- column="27"/>
- </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"
- line="5489"
- column="35"/>
- </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"
- line="5492"
- column="34"/>
- </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"
- line="6238"
- column="51"/>
- </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"
- line="6239"
- column="33"/>
- </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"
- line="6240"
- column="33"/>
- </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"
- line="6241"
- column="33"/>
- </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"
- line="6243"
- column="43"/>
- </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"
- line="6245"
- column="33"/>
- </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=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="6271"
- column="25"/>
- </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=" .setLabel(remoteInputCompat.getLabel())"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="6272"
- column="34"/>
- </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=" .setChoices(remoteInputCompat.getChoices())"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="6273"
- column="34"/>
- </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=" .setAllowFreeFormInput(remoteInputCompat.getAllowFreeFormInput())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="6274"
- column="34"/>
- </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=" .addExtras(remoteInputCompat.getExtras())"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="6275"
- column="34"/>
- </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=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="6276"
- column="34"/>
- </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"
- line="7253"
- column="61"/>
- </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"
- line="7263"
- column="59"/>
- </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"
- line="7271"
- column="29"/>
- </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"
- line="7272"
- column="29"/>
- </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"
- line="7273"
- column="29"/>
- </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"
- line="7274"
- column="29"/>
- </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"
- line="7276"
- column="39"/>
- </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"
- line="7278"
- column="29"/>
- </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"
- line="7285"
- column="44"/>
- </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"
- line="7287"
- column="31"/>
- </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"
- line="7289"
- column="44"/>
- </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"
- line="7294"
- column="24"/>
- </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"
- line="7298"
- column="37"/>
- </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"
- line="7300"
- column="37"/>
- </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"
- line="7304"
- column="75"/>
- </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"
- line="7307"
- column="24"/>
- </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"
- line="7309"
- column="32"/>
- </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"
- line="7312"
- column="38"/>
- </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"
- line="7313"
- column="80"/>
- </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"
- line="7314"
- column="79"/>
- </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"
- line="7318"
- column="86"/>
- </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"
- line="7434"
- column="33"/>
- </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"
- line="7542"
- column="33"/>
- </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"
- line="7558"
- column="33"/>
- </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"
- line="7570"
- column="33"/>
- </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"
- line="7583"
- column="33"/>
- </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"
- line="7595"
- column="33"/>
- </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"
- line="7606"
- column="33"/>
- </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"
- line="7622"
- column="44"/>
- </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"
- line="7637"
- column="33"/>
- </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"
- line="7650"
- column="33"/>
- </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=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="72"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setSubText(b.mSubText)"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="101"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setUsesChronometer(b.mUseChronometer)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="102"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setPriority(b.mPriority);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="103"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setShowWhen(b.mShowWhen);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="133"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setLocalOnly(b.mLocalOnly)"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="145"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setGroup(b.mGroupKey)"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="146"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setGroupSummary(b.mGroupSummary)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="147"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setSortKey(b.mSortKey);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="148"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setCategory(b.mCategory)"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="153"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setColor(b.mColor)"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="154"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setVisibility(b.mVisibility)"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="155"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setPublicVersion(b.mPublicVersion)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="156"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setSound(n.sound, n.audioAttributes);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="157"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.addPerson(person);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="168"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setSmallIcon(b.mSmallIcon);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="202"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setExtras(b.mExtras)"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="206"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setRemoteInputHistory(b.mRemoteInputHistory);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="207"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setCustomContentView(b.mContentView);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="209"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setCustomBigContentView(b.mBigContentView);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="212"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setCustomHeadsUpContentView(b.mHeadsUpContentView);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="215"
- column="26"/>
- </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.setBadgeIconType(b.mBadgeIcon)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="219"
- column="22"/>
- </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=" .setSettingsText(b.mSettingsText)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="220"
- column="22"/>
- </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=" .setShortcutId(b.mShortcutId)"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="221"
- column="22"/>
- </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=" .setTimeoutAfter(b.mTimeout)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="222"
- column="22"/>
- </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=" .setGroupAlertBehavior(b.mGroupAlertBehavior);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="223"
- column="22"/>
- </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.setColorized(b.mColorized);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="225"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.addPerson(p.toAndroidPerson());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="237"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setAllowSystemGeneratedContextualActions("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="241"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setBubbleMetadata("
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="244"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setLocusId(b.mLocusId.toLocusId());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="247"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setGroup(NotificationCompat.GROUP_KEY_SILENT);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="266"
- column="30"/>
- </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.setGroupAlertBehavior(mGroupAlertBehavior);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="268"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompatBuilder 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/NotificationCompatBuilder.java"
- line="353"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder 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/NotificationCompatBuilder.java"
- line="358"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder 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/NotificationCompatBuilder.java"
- line="366"
- column="35"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder.setAllowGeneratedReplies(action.getAllowGeneratedReplies());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="378"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder.setSemanticAction(action.getSemanticAction());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="384"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder.setContextual(action.isContextual());"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="388"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder 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/NotificationCompatBuilder.java"
- line="393"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.addAction(actionBuilder.build());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="394"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.addAction(actionBuilder.build());"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="394"
- column="46"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mBuilder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="404"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Notification notification = mBuilder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="406"
- column="51"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (notification.getGroup() != null"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="410"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (notification.getGroup() != null"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="416"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setExtras(mExtras);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="425"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Notification notification = mBuilder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="426"
- column="50"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (notification.getGroup() != null"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="439"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (notification.getGroup() != null"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="445"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setExtras(mExtras);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="453"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Notification notification = mBuilder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="454"
- column="50"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (notification.getGroup() != null"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="464"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (notification.getGroup() != null"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="470"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBuilder.setExtras(mExtras);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="486"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Notification notification = mBuilder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="487"
- column="50"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Notification notification = mBuilder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompatBuilder.java"
- line="496"
- column="50"/>
- </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.areNotificationsEnabled();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"
- line="232"
- column="41"/>
- </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"
- line="263"
- column="41"/>
- </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"
- line="291"
- column="34"/>
- </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"
- line="330"
- column="34"/>
- </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"
- line="357"
- column="34"/>
- </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"
- line="376"
- column="34"/>
- </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"
- line="390"
- column="34"/>
- </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"
- line="409"
- column="34"/>
- </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"
- line="424"
- column="34"/>
- </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"
- line="436"
- column="34"/>
- </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"
- line="451"
- column="69"/>
- </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"
- line="452"
- column="49"/>
- </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"
- line="456"
- column="56"/>
- </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"
- line="459"
- column="38"/>
- </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"
- line="459"
- column="72"/>
- </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"
- line="472"
- column="41"/>
- </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"
- line="505"
- column="41"/>
- </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"
- line="538"
- column="41"/>
- </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"
- line="542"
- column="27"/>
- </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"
- line="580"
- column="41"/>
- </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"
- line="612"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.util.ObjectsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Objects.equals(a, b);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/util/ObjectsCompat.java"
- line="52"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.util.ObjectsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Objects.hash(values);"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/core/util/ObjectsCompat.java"
- line="94"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.content.pm.PackageInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return info.getLongVersionCode();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/PackageInfoCompat.java"
- line="51"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.graphics.PaintCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return paint.hasGlyph(string);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/PaintCompat.java"
- line="52"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.graphics.PaintCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" paint.setBlendMode(blendMode != null ? obtainBlendModeFromCompat(blendMode) : null);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/PaintCompat.java"
- line="127"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.animation.PathInterpolatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new PathInterpolator(path);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/animation/PathInterpolatorCompat.java"
- line="49"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.animation.PathInterpolatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new PathInterpolator(controlX, controlY);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/animation/PathInterpolatorCompat.java"
- line="64"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.animation.PathInterpolatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new PathInterpolator(controlX1, controlY1, controlX2, controlY2);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/animation/PathInterpolatorCompat.java"
- line="82"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.graphics.PathUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" float[] pathData = path.approximate(error);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/PathUtils.java"
- line="60"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.content.pm.PermissionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return permissionInfo.getProtection();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/PermissionInfoCompat.java"
- line="75"
- column="35"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.content.pm.PermissionInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return permissionInfo.getProtectionFlags();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/PermissionInfoCompat.java"
- line="89"
- column="35"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setName(bundle.getString(NAME_KEY))"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="71"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setUri(bundle.getString(URI_KEY))"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="72"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setKey(bundle.getString(KEY_KEY))"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="73"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBot(bundle.getBoolean(IS_BOT_KEY))"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="74"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setImportant(bundle.getBoolean(IS_IMPORTANT_KEY))"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="75"
- column="38"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setName(person.getName())"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="89"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" (person.getIcon() != null)"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="91"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ? IconCompat.createFromIcon(person.getIcon())"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="92"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setUri(person.getUri())"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="94"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setKey(person.getKey())"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="95"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBot(person.isBot())"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="96"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setImportant(person.isImportant())"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="97"
- column="38"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" PersistableBundle result = new PersistableBundle();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="151"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result.putString(NAME_KEY, mName != null ? mName.toString() : null);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="152"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result.putString(URI_KEY, mUri);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="153"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result.putString(KEY_KEY, mKey);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="154"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result.putBoolean(IS_BOT_KEY, mIsBot);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="155"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result.putBoolean(IS_IMPORTANT_KEY, mIsImportant);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="156"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new android.app.Person.Builder()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="175"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setName(getName())"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="176"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setIcon((getIcon() != null) ? getIcon().toIcon() : null)"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="177"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setUri(getUri())"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="178"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setKey(getKey())"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="179"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBot(isBot())"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="180"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setImportant(isImportant())"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="181"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.Person is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/Person.java"
- line="182"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.PointerIconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new PointerIconCompat(PointerIcon.getSystemIcon(context, style));"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/PointerIconCompat.java"
- line="131"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.PointerIconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new PointerIconCompat(PointerIcon.create(bitmap, hotSpotX, hotSpotY));"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/PointerIconCompat.java"
- line="152"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.view.PointerIconCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new PointerIconCompat(PointerIcon.load(resources, resourceId));"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/core/view/PointerIconCompat.java"
- line="181"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.widget.PopupMenuCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return ((PopupMenu) popupMenu).getDragToOpenListener();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/PopupMenuCompat.java"
- line="56"
- column="44"/>
- </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=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="197"
- column="28"/>
- </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=" .setBreakStrategy(strategy)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="198"
- column="26"/>
- </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=" .setHyphenationFrequency(frequency)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="199"
- column="26"/>
- </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=" .setTextDirection(textDir)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="200"
- column="26"/>
- </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=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="201"
- column="26"/>
- </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=" mPaint = wrapped.getTextPaint();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="213"
- column="30"/>
- </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=" mTextDir = wrapped.getTextDirection();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="214"
- column="32"/>
- </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=" mBreakStrategy = wrapped.getBreakStrategy();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="215"
- column="38"/>
- </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=" mHyphenationFrequency = wrapped.getHyphenationFrequency();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="216"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (mPaint.getLetterSpacing() != other.getTextPaint().getLetterSpacing()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="292"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (mPaint.getLetterSpacing() != other.getTextPaint().getLetterSpacing()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="292"
- column="71"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!TextUtils.equals(mPaint.getFontFeatureSettings(),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="295"
- column="46"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" other.getTextPaint().getFontFeatureSettings())) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="296"
- column="46"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!mPaint.getTextLocales().equals(other.getTextPaint().getTextLocales())) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="304"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!mPaint.getTextLocales().equals(other.getTextPaint().getTextLocales())) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="304"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!mPaint.getTextLocale().equals(other.getTextPaint().getTextLocale())) {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="308"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!mPaint.getTextLocale().equals(other.getTextPaint().getTextLocale())) {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="308"
- column="73"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextSkewX(), mPaint.getLetterSpacing(), mPaint.getFlags(),"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="352"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextLocales(), mPaint.getTypeface(), mPaint.isElegantTextHeight(),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="353"
- column="79"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextLocales(), mPaint.getTypeface(), mPaint.isElegantTextHeight(),"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="353"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextSkewX(), mPaint.getLetterSpacing(), mPaint.getFlags(),"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="357"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextLocale(), mPaint.getTypeface(), mPaint.isElegantTextHeight(),"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="358"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextLocale(), mPaint.getTypeface(), mPaint.isElegantTextHeight(),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="358"
- column="78"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextSkewX(), mPaint.getFlags(), mPaint.getTextLocale(),"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="362"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPaint.getTextSkewX(), mPaint.getFlags(), mPaint.getTextLocale(),"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="366"
- column="74"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sb.append(", letterSpacing=" + mPaint.getLetterSpacing());"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="382"
- column="55"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sb.append(", elegantTextHeight=" + mPaint.isElegantTextHeight());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="383"
- column="59"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sb.append(", textLocale=" + mPaint.getTextLocales());"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="386"
- column="52"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sb.append(", textLocale=" + mPaint.getTextLocale());"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="388"
- column="52"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sb.append(", variationSettings=" + mPaint.getFontVariationSettings());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="392"
- column="59"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" PrecomputedText.create(text, params.mWrapped), params);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="437"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" StaticLayout.Builder.obtain(text, 0, text.length(), params.getTextPaint(),"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="465"
- column="38"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBreakStrategy(params.getBreakStrategy())"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="467"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setHyphenationFrequency(params.getHyphenationFrequency())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="468"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setTextDirection(params.getTextDirection())"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="469"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="470"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mWrapped.getParagraphCount();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="528"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mWrapped.getParagraphStart(paraIndex);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="540"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.text.PrecomputedTextCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mWrapped.getParagraphEnd(paraIndex);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/PrecomputedTextCompat.java"
- line="552"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" IconCompat.createFromIcon(remoteAction.getIcon()), remoteAction.getTitle(),"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="117"
- column="56"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" IconCompat.createFromIcon(remoteAction.getIcon()), remoteAction.getTitle(),"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="117"
- column="81"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" remoteAction.getContentDescription(), remoteAction.getActionIntent());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="118"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" remoteAction.getContentDescription(), remoteAction.getActionIntent());"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="118"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" action.setEnabled(remoteAction.isEnabled());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="119"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" action.setShouldShowIcon(remoteAction.shouldShowIcon());"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="121"
- column="51"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" RemoteAction action = new RemoteAction(mIcon.toIcon(), mTitle, mContentDescription,"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="190"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" action.setEnabled(isEnabled());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="192"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.RemoteActionCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" action.setShouldShowIcon(shouldShowIcon());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteActionCompat.java"
- line="194"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return android.app.RemoteInput.getDataResultsFromIntent(intent, remoteInputResultKey);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="339"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return android.app.RemoteInput.getResultsFromIntent(intent);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="377"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" android.app.RemoteInput.addResultsToIntent(fromCompat(remoteInputs), intent, results);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="403"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" android.app.RemoteInput.addResultsToIntent("
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="426"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" intent.setClipData(ClipData.newIntent(RemoteInput.RESULTS_CLIP_LABEL, clipDataIntent));"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="452"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" android.app.RemoteInput.addDataResultToIntent(fromCompat(remoteInput), intent, results);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="467"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" intent.setClipData(ClipData.newIntent(RemoteInput.RESULTS_CLIP_LABEL, clipDataIntent));"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="487"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" android.app.RemoteInput.setResultsSource(intent, source);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="506"
- column="37"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="513"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return android.app.RemoteInput.getResultsSource(intent);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="531"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" new android.app.RemoteInput.Builder(src.getResultKey())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="562"
- column="17"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setLabel(src.getLabel())"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="563"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setChoices(src.getChoices())"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="564"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setAllowFreeFormInput(src.getAllowFreeFormInput())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="565"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .addExtras(src.getExtras());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="566"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setAllowDataType(allowedDataType, true);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="571"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setEditChoicesBeforeSending(src.getEditChoicesBeforeSending());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="576"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return builder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="578"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" new RemoteInput.Builder(src.getResultKey())"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="584"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setLabel(src.getLabel())"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="585"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setChoices(src.getChoices())"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="586"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setAllowFreeFormInput(src.getAllowFreeFormInput())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="587"
- column="52"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .addExtras(src.getExtras());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="588"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Set<String> allowedDataTypes = src.getAllowedDataTypes();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="590"
- column="48"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setEditChoicesBeforeSending(src.getEditChoicesBeforeSending());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="598"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.RemoteInput is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ClipData clipData = intent.getClipData();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/RemoteInput.java"
- line="605"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.res.ResourcesCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return res.getDrawable(id, theme);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="104"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.res.ResourcesCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return res.getDrawableForDensity(id, density, theme);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="137"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.content.res.ResourcesCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return res.getDrawableForDensity(id, density);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="139"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.res.ResourcesCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return res.getColor(id, theme);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="167"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.res.ResourcesCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return res.getColorStateList(id, theme);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="195"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.database.sqlite.SQLiteCursorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" cursor.setFillWindowForwardOnly(fillWindowForwardOnly);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/database/sqlite/SQLiteCursorCompat.java"
- line="46"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.ScaleGestureDetectorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" scaleGestureDetector.setQuickScaleEnabled(enabled);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java"
- line="54"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.ScaleGestureDetectorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return scaleGestureDetector.isQuickScaleEnabled();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java"
- line="79"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.ServiceCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" service.stopForeground(flags);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ServiceCompat.java"
- line="99"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.ShareCompat.IntentReader is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result = Html.escapeHtml(text);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/ShareCompat.java"
- line="835"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ShortcutInfo.Builder builder = new ShortcutInfo.Builder(mContext, mId)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="108"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setShortLabel(mLabel)"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="109"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setIntents(mIntents);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="110"
- column="18"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setIcon(mIcon.toIcon(mContext));"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="112"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setLongLabel(mLongLabel);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="115"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setDisabledMessage(mDisabledMessage);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="118"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setActivity(mActivity);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="121"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setCategories(mCategories);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="124"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setRank(mRank);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="126"
- column="17"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setExtras(mExtras);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="128"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setPersons(persons);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="136"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setLocusId(mLocusId.toLocusId());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="139"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setLongLived(mIsLongLived);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="141"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setExtras(buildLegacyExtrasBundle());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="146"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return builder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="148"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mExtras = new PersistableBundle();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="158"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mExtras.putInt(EXTRA_PERSON_COUNT, mPersons.length);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="161"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mExtras.putPersistableBundle(EXTRA_PERSON_ + (i + 1),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="163"
- column="25"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mExtras.putString(EXTRA_LOCUS_ID, mLocusId.getId());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="168"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mExtras.putBoolean(EXTRA_LONG_LIVED, mIsLongLived);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="170"
- column="17"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (bundle == null || !bundle.containsKey(EXTRA_PERSON_COUNT)) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="337"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" int personsLength = bundle.getInt(EXTRA_PERSON_COUNT);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="341"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" bundle.getPersistableBundle(EXTRA_PERSON_ + (i + 1)));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="345"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (bundle == null || !bundle.containsKey(EXTRA_LONG_LIVED)) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="357"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 22; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return bundle.getBoolean(EXTRA_LONG_LIVED);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="360"
- column="23"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (shortcutInfo.getLocusId() == null) return null;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="474"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return LocusIdCompat.toLocusIdCompat(shortcutInfo.getLocusId());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="475"
- column="63"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return getLocusIdFromExtra(shortcutInfo.getExtras());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="477"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final String locusId = bundle.getString(EXTRA_LOCUS_ID);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="489"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mId = shortcutInfo.getId();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="558"
- column="38"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mPackageName = shortcutInfo.getPackage();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="559"
- column="47"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Intent[] intents = shortcutInfo.getIntents();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="560"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mActivity = shortcutInfo.getActivity();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="562"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mLabel = shortcutInfo.getShortLabel();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="563"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mLongLabel = shortcutInfo.getLongLabel();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="564"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mDisabledMessage = shortcutInfo.getDisabledMessage();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="565"
- column="51"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mDisabledReason = shortcutInfo.getDisabledReason();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="567"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mDisabledReason = shortcutInfo.isEnabled()"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="569"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mCategories = shortcutInfo.getCategories();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="573"
- column="46"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mPersons = ShortcutInfoCompat.getPersonsFromExtra(shortcutInfo.getExtras());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="574"
- column="82"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mUser = shortcutInfo.getUserHandle();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="575"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mLastChangedTimestamp = shortcutInfo.getLastChangedTimestamp();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="576"
- column="56"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mIsCached = shortcutInfo.isCached();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="578"
- column="48"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mIsDynamic = shortcutInfo.isDynamic();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="580"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mIsPinned = shortcutInfo.isPinned();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="581"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mIsDeclaredInManifest = shortcutInfo.isDeclaredInManifest();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="582"
- column="56"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mIsImmutable = shortcutInfo.isImmutable();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="583"
- column="47"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mIsEnabled = shortcutInfo.isEnabled();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="584"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mHasKeyFieldsOnly = shortcutInfo.hasKeyFieldsOnly();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="585"
- column="52"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mRank = shortcutInfo.getRank();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="587"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mExtras = shortcutInfo.getExtras();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="588"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mExtras = new PersistableBundle();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="907"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mExtras.putStringArray("
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="914"
- column="39"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mExtras.putStringArray(capability + "/" + paramName,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="920"
- column="43"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mExtras = new PersistableBundle();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="927"
- column="41"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.content.pm.ShortcutInfoCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mInfo.mExtras.putString(EXTRA_SLICE_URI, UriCompat.toSafeString(mSliceUri));"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java"
- line="929"
- column="35"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).isRequestPinShortcutSupported();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="154"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).isRequestPinShortcutSupported();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="154"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).requestPinShortcut("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="191"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).requestPinShortcut("
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="191"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" result = context.getSystemService(ShortcutManager.class)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="235"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .createShortcutResultIntent(shortcut.toShortcutInfo());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="236"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).getShortcuts(matchFlags);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="276"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).getShortcuts(matchFlags);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="276"
- column="69"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final ShortcutManager manager = context.getSystemService(ShortcutManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="279"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" shortcuts.addAll(manager.getManifestShortcuts());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="282"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" shortcuts.addAll(manager.getDynamicShortcuts());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="285"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" shortcuts.addAll(manager.getPinnedShortcuts());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="288"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!context.getSystemService(ShortcutManager.class).addDynamicShortcuts(shortcuts)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="324"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!context.getSystemService(ShortcutManager.class).addDynamicShortcuts(shortcuts)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="324"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).getMaxShortcutCountPerActivity();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="343"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).getMaxShortcutCountPerActivity();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="343"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).isRateLimitingActive();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="360"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).isRateLimitingActive();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="360"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).getIconMaxWidth();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="380"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).getIconMaxWidth();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="380"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).getIconMaxHeight();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="391"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(ShortcutManager.class).getIconMaxHeight();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="391"
- column="68"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).reportShortcutUsed(shortcutId);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="418"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).reportShortcutUsed(shortcutId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="418"
- column="61"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!context.getSystemService(ShortcutManager.class).setDynamicShortcuts(shortcuts)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="456"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!context.getSystemService(ShortcutManager.class).setDynamicShortcuts(shortcuts)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="456"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" List<ShortcutInfo> shortcuts = context.getSystemService("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="480"
- column="52"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ShortcutManager.class).getDynamicShortcuts();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="481"
- column="44"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!context.getSystemService(ShortcutManager.class).updateShortcuts(shortcuts)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="519"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (!context.getSystemService(ShortcutManager.class).updateShortcuts(shortcuts)) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="519"
- column="66"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="586"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .disableShortcuts(shortcutIds, disabledMessage);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="587"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).enableShortcuts(shortcutIds);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="617"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).enableShortcuts(shortcutIds);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="617"
- column="61"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).removeDynamicShortcuts(shortcutIds);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="636"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).removeDynamicShortcuts(shortcutIds);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="636"
- column="61"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).removeAllDynamicShortcuts();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="654"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).removeAllDynamicShortcuts();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="654"
- column="61"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).removeLongLivedShortcuts(shortcutIds);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="681"
- column="17"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).removeLongLivedShortcuts(shortcutIds);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="681"
- column="57"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).pushDynamicShortcut("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="734"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" context.getSystemService(ShortcutManager.class).pushDynamicShortcut("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="734"
- column="61"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final ShortcutManager sm = context.getSystemService(ShortcutManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="737"
- column="48"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (sm.isRateLimitingActive()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="738"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final List<ShortcutInfo> shortcuts = sm.getDynamicShortcuts();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="741"
- column="53"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sm.removeDynamicShortcuts(Arrays.asList("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="743"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 25; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" sm.addDynamicShortcuts(Arrays.asList(shortcut.toShortcutInfo()));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="746"
- column="16"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.content.pm.ShortcutManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Build.VERSION.SDK_INT < 19 || am == null || am.isLowRamDevice();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java"
- line="801"
- column="64"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.TaskStackBuilder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return PendingIntent.getActivities(mSourceContext, requestCode, intents, flags,"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/TaskStackBuilder.java"
- line="341"
- column="34"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.text.TextUtilsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return TextUtils.getLayoutDirectionFromLocale(locale);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/text/TextUtilsCompat.java"
- line="91"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setCompoundDrawablesRelative(start, top, end, bottom);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="152"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="154"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="179"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="181"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="211"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="213"
- column="36"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getMaxLines();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="227"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getMinLines();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="253"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setTextAppearance(resId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="284"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getCompoundDrawablesRelative();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="296"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="299"
- column="42"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setAutoSizeTextTypeWithDefaults(autoSizeTextType);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="327"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setAutoSizeTextTypeUniformWithConfiguration("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="362"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="388"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getAutoSizeTextType();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="407"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getAutoSizeStepGranularity();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="423"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getAutoSizeMinTextSize();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="440"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getAutoSizeMaxTextSize();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="457"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getAutoSizeTextAvailableSizes();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="474"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setFirstBaselineToTopHeight(firstBaselineToTopHeight);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="715"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" || textView.getIncludeFontPadding()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="724"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" || textView.getIncludeFontPadding()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="765"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new PrecomputedTextCompat.Params(textView.getTextMetricsParams());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="836"
- column="62"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setBreakStrategy(textView.getBreakStrategy());"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="841"
- column="51"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setHyphenationFrequency(textView.getHyphenationFrequency());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="842"
- column="58"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setTextDirection(getTextDirection(params.getTextDirection()));"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="863"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setBreakStrategy(params.getBreakStrategy());"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="886"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setHyphenationFrequency(params.getHyphenationFrequency());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="887"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" DecimalFormatSymbols.getInstance(textView.getTextLocale());"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="939"
- column="67"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" DecimalFormatSymbols.getInstance(textView.getTextLocale());"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="939"
- column="46"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final String zero = symbols.getDigitStrings()[0];"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="940"
- column="45"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final boolean defaultIsRtl = (textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="955"
- column="48"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 17; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" switch (textView.getTextDirection()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="958"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setCompoundDrawableTintList(tint);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="1015"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getCompoundDrawableTintList();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="1031"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" textView.setCompoundDrawableTintMode(tintMode);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="1049"
- column="22"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.widget.TextViewCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return textView.getCompoundDrawableTintMode();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/widget/TextViewCompat.java"
- line="1066"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.os.TraceCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Trace.isEnabled();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/TraceCompat.java"
- line="79"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.os.TraceCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Trace.beginSection(sectionName);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/TraceCompat.java"
- line="105"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.os.TraceCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Trace.endSection();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/TraceCompat.java"
- line="118"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.os.TraceCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Trace.beginAsyncSection(methodName, cookie);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/TraceCompat.java"
- line="134"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.os.TraceCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Trace.endAsyncSection(methodName, cookie);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/TraceCompat.java"
- line="154"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.os.TraceCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Trace.setCounter(counterName, counterValue);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/TraceCompat.java"
- line="173"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.net.TrafficStatsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" TrafficStats.tagDatagramSocket(socket);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/net/TrafficStatsCompat.java"
- line="138"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.net.TrafficStatsCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" TrafficStats.untagDatagramSocket(socket);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/net/TrafficStatsCompat.java"
- line="155"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.graphics.TypefaceCompatUtil is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r", cancellationSignal)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/TypefaceCompatUtil.java"
- line="110"
- column="50"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.os.UserManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(UserManager.class).isUserUnlocked();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/UserManagerCompat.java"
- line="42"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.os.UserManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return context.getSystemService(UserManager.class).isUserUnlocked();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/UserManagerCompat.java"
- line="42"
- column="64"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.ViewConfigurationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return config.getScaledHorizontalScrollFactor();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewConfigurationCompat.java"
- line="82"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.view.ViewConfigurationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return config.getScaledVerticalScrollFactor();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewConfigurationCompat.java"
- line="99"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.ViewConfigurationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return config.getScaledHoverSlop();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewConfigurationCompat.java"
- line="129"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.ViewConfigurationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return config.shouldShowMenuShortcutsWhenKeyboardPresent();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewConfigurationCompat.java"
- line="142"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.ViewGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return group.getLayoutMode();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewGroupCompat.java"
- line="115"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.ViewGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" group.setLayoutMode(mode);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewGroupCompat.java"
- line="131"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" group.setTransitionGroup(isTransitionGroup);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewGroupCompat.java"
- line="145"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return group.isTransitionGroup();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewGroupCompat.java"
- line="158"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return group.getNestedScrollAxes();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewGroupCompat.java"
- line="182"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return parent.onStartNestedScroll(child, target, nestedScrollAxes);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="215"
- column="35"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" parent.onNestedScrollAccepted(child, target, nestedScrollAxes);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="256"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" parent.onStopNestedScroll(target);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="289"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" parent.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="346"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" parent.onNestedPreScroll(target, dx, dy, consumed);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="391"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return parent.onNestedFling(target, velocityX, velocityY, consumed);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="426"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return parent.onNestedPreFling(target, velocityX, velocityY);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="463"
- column="31"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.ViewParentCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewParentCompat.java"
- line="493"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().withEndAction(runnable);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="218"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 18; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return (Interpolator) view.animate().getInterpolator();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="269"
- column="54"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().translationZBy(value);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="572"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().translationZ(value);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="591"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().z(value);"
- errorLine2=" ~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="610"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().zBy(value);"
- errorLine2=" ~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="629"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().withLayer();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="682"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().withStartAction(runnable);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="710"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 19; however, the containing class androidx.core.view.ViewPropertyAnimatorCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" view.animate().setUpdateListener(wrapped);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java"
- line="787"
- column="32"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.view.WindowCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return window.requireViewById(id);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/WindowCompat.java"
- line="89"
- column="27"/>
- </issue>
-
- <issue
id="PrivateConstructorForUtilityClass"
message="Utility class is missing private constructor"
errorLine1="public class NotificationCompat {"
@@ -13897,7 +3832,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="171"
+ line="173"
column="19"/>
</issue>
@@ -13908,7 +3843,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="209"
+ line="211"
column="49"/>
</issue>
@@ -13919,7 +3854,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="567"
+ line="605"
column="78"/>
</issue>
@@ -13930,7 +3865,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/ActivityCompat.java"
- line="568"
+ line="606"
column="13"/>
</issue>
@@ -14755,7 +4690,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/core/widget/EdgeEffectCompat.java"
- line="47"
+ line="53"
column="29"/>
</issue>
@@ -14766,7 +4701,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/core/widget/EdgeEffectCompat.java"
- line="207"
+ line="294"
column="25"/>
</issue>
@@ -16383,7 +6318,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="97"
+ line="99"
column="29"/>
</issue>
@@ -16394,7 +6329,7 @@
errorLine2=" ~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="247"
+ line="262"
column="31"/>
</issue>
@@ -16405,7 +6340,7 @@
errorLine2=" ~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="253"
+ line="268"
column="60"/>
</issue>
@@ -16416,7 +6351,7 @@
errorLine2=" ~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="253"
+ line="268"
column="76"/>
</issue>
@@ -16427,7 +6362,7 @@
errorLine2=" ~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="287"
+ line="302"
column="31"/>
</issue>
@@ -16438,7 +6373,7 @@
errorLine2=" ~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="293"
+ line="308"
column="60"/>
</issue>
@@ -16449,7 +6384,7 @@
errorLine2=" ~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="293"
+ line="308"
column="76"/>
</issue>
@@ -16460,7 +6395,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="472"
+ line="487"
column="25"/>
</issue>
@@ -16471,7 +6406,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="481"
+ line="496"
column="25"/>
</issue>
@@ -16482,7 +6417,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="490"
+ line="505"
column="25"/>
</issue>
@@ -16493,7 +6428,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="490"
+ line="505"
column="37"/>
</issue>
@@ -16504,7 +6439,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="499"
+ line="514"
column="25"/>
</issue>
@@ -16515,7 +6450,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="499"
+ line="514"
column="48"/>
</issue>
@@ -16526,7 +6461,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="620"
+ line="635"
column="37"/>
</issue>
@@ -16537,7 +6472,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="717"
+ line="732"
column="42"/>
</issue>
@@ -16548,7 +6483,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="828"
+ line="844"
column="33"/>
</issue>
@@ -16559,7 +6494,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1011"
+ line="1067"
column="41"/>
</issue>
@@ -16570,7 +6505,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1574"
+ line="1630"
column="33"/>
</issue>
@@ -16581,7 +6516,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1590"
+ line="1646"
column="44"/>
</issue>
@@ -16592,7 +6527,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1725"
+ line="1814"
column="60"/>
</issue>
@@ -16603,7 +6538,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1791"
+ line="1880"
column="35"/>
</issue>
@@ -16614,7 +6549,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1791"
+ line="1880"
column="47"/>
</issue>
@@ -16625,7 +6560,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1811"
+ line="1900"
column="13"/>
</issue>
@@ -16636,7 +6571,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1838"
+ line="1927"
column="50"/>
</issue>
@@ -16647,7 +6582,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1838"
+ line="1927"
column="62"/>
</issue>
@@ -16658,7 +6593,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="1998"
+ line="2072"
column="22"/>
</issue>
@@ -16669,7 +6604,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="2079"
+ line="2151"
column="43"/>
</issue>
@@ -16680,7 +6615,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/androidx/core/widget/NestedScrollView.java"
- line="2092"
+ line="2164"
column="15"/>
</issue>
@@ -16702,7 +6637,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="832"
+ line="882"
column="16"/>
</issue>
@@ -16713,7 +6648,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="836"
+ line="886"
column="16"/>
</issue>
@@ -16724,7 +6659,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="897"
+ line="948"
column="16"/>
</issue>
@@ -16735,7 +6670,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2361"
+ line="2435"
column="16"/>
</issue>
@@ -16746,7 +6681,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2369"
+ line="2443"
column="16"/>
</issue>
@@ -16757,7 +6692,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2377"
+ line="2451"
column="16"/>
</issue>
@@ -16768,7 +6703,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2435"
+ line="2519"
column="19"/>
</issue>
@@ -16779,7 +6714,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2481"
+ line="2565"
column="27"/>
</issue>
@@ -16790,7 +6725,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2497"
+ line="2581"
column="16"/>
</issue>
@@ -16801,7 +6736,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2497"
+ line="2581"
column="44"/>
</issue>
@@ -16812,7 +6747,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2505"
+ line="2589"
column="16"/>
</issue>
@@ -16823,7 +6758,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2505"
+ line="2589"
column="47"/>
</issue>
@@ -16834,7 +6769,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2513"
+ line="2597"
column="16"/>
</issue>
@@ -16845,7 +6780,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2513"
+ line="2597"
column="51"/>
</issue>
@@ -16856,7 +6791,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2824"
+ line="2908"
column="16"/>
</issue>
@@ -16867,7 +6802,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2874"
+ line="2958"
column="42"/>
</issue>
@@ -16878,7 +6813,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2875"
+ line="2959"
column="17"/>
</issue>
@@ -16889,7 +6824,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="2999"
+ line="3083"
column="27"/>
</issue>
@@ -16900,7 +6835,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="3194"
+ line="3278"
column="27"/>
</issue>
@@ -16911,7 +6846,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="3538"
+ line="3622"
column="27"/>
</issue>
@@ -16922,7 +6857,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4098"
+ line="4182"
column="27"/>
</issue>
@@ -16933,7 +6868,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4199"
+ line="4283"
column="27"/>
</issue>
@@ -16944,7 +6879,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4210"
+ line="4294"
column="16"/>
</issue>
@@ -16955,7 +6890,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4210"
+ line="4294"
column="44"/>
</issue>
@@ -16966,7 +6901,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4227"
+ line="4311"
column="16"/>
</issue>
@@ -16977,7 +6912,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4227"
+ line="4311"
column="47"/>
</issue>
@@ -16988,7 +6923,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4248"
+ line="4332"
column="16"/>
</issue>
@@ -16999,7 +6934,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4248"
+ line="4332"
column="51"/>
</issue>
@@ -17010,7 +6945,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4432"
+ line="4516"
column="16"/>
</issue>
@@ -17021,7 +6956,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"
- line="4437"
+ line="4521"
column="16"/>
</issue>
@@ -17901,7 +7836,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="435"
+ line="433"
column="54"/>
</issue>
@@ -17912,7 +7847,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="504"
+ line="502"
column="19"/>
</issue>
@@ -17923,7 +7858,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/androidx/core/content/res/ResourcesCompat.java"
- line="504"
+ line="502"
column="79"/>
</issue>
@@ -19496,7 +9431,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="542"
+ line="543"
column="49"/>
</issue>
@@ -19507,7 +9442,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="555"
+ line="556"
column="47"/>
</issue>
@@ -19518,7 +9453,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="572"
+ line="573"
column="41"/>
</issue>
@@ -19529,7 +9464,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="592"
+ line="593"
column="42"/>
</issue>
@@ -19540,7 +9475,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="632"
+ line="633"
column="53"/>
</issue>
@@ -19551,7 +9486,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="632"
+ line="633"
column="61"/>
</issue>
@@ -19562,7 +9497,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="664"
+ line="665"
column="55"/>
</issue>
@@ -19573,7 +9508,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="664"
+ line="665"
column="63"/>
</issue>
@@ -19584,7 +9519,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1467"
+ line="1468"
column="34"/>
</issue>
@@ -19595,7 +9530,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1506"
+ line="1507"
column="37"/>
</issue>
@@ -19606,7 +9541,7 @@
errorLine2=" ~~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1506"
+ line="1507"
column="74"/>
</issue>
@@ -19617,7 +9552,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1530"
+ line="1531"
column="36"/>
</issue>
@@ -19628,7 +9563,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1698"
+ line="1699"
column="36"/>
</issue>
@@ -19639,7 +9574,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1735"
+ line="1736"
column="48"/>
</issue>
@@ -19650,7 +9585,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1752"
+ line="1753"
column="49"/>
</issue>
@@ -19661,7 +9596,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1766"
+ line="1767"
column="40"/>
</issue>
@@ -19672,7 +9607,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1958"
+ line="1959"
column="41"/>
</issue>
@@ -19683,7 +9618,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1972"
+ line="1973"
column="41"/>
</issue>
@@ -19694,7 +9629,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="1994"
+ line="1995"
column="36"/>
</issue>
@@ -19705,7 +9640,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2100"
+ line="2101"
column="40"/>
</issue>
@@ -19716,7 +9651,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2117"
+ line="2118"
column="40"/>
</issue>
@@ -19727,7 +9662,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2134"
+ line="2135"
column="33"/>
</issue>
@@ -19738,7 +9673,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2149"
+ line="2150"
column="29"/>
</issue>
@@ -19749,7 +9684,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2164"
+ line="2165"
column="29"/>
</issue>
@@ -19760,7 +9695,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2177"
+ line="2178"
column="36"/>
</issue>
@@ -19771,7 +9706,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2191"
+ line="2192"
column="37"/>
</issue>
@@ -19782,7 +9717,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2205"
+ line="2206"
column="37"/>
</issue>
@@ -19793,7 +9728,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2218"
+ line="2219"
column="34"/>
</issue>
@@ -19804,7 +9739,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2231"
+ line="2232"
column="34"/>
</issue>
@@ -19815,7 +9750,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2242"
+ line="2243"
column="35"/>
</issue>
@@ -19826,7 +9761,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2258"
+ line="2259"
column="34"/>
</issue>
@@ -19837,7 +9772,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2271"
+ line="2272"
column="35"/>
</issue>
@@ -19848,7 +9783,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2287"
+ line="2288"
column="34"/>
</issue>
@@ -19859,7 +9794,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2295"
+ line="2296"
column="37"/>
</issue>
@@ -19870,7 +9805,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2303"
+ line="2304"
column="38"/>
</issue>
@@ -19881,7 +9816,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2311"
+ line="2312"
column="38"/>
</issue>
@@ -19892,7 +9827,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2319"
+ line="2320"
column="35"/>
</issue>
@@ -19903,7 +9838,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2327"
+ line="2328"
column="35"/>
</issue>
@@ -19914,7 +9849,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2335"
+ line="2336"
column="30"/>
</issue>
@@ -19925,7 +9860,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2343"
+ line="2344"
column="30"/>
</issue>
@@ -19936,7 +9871,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2467"
+ line="2468"
column="55"/>
</issue>
@@ -19947,7 +9882,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2508"
+ line="2509"
column="45"/>
</issue>
@@ -19958,7 +9893,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2522"
+ line="2523"
column="52"/>
</issue>
@@ -19969,7 +9904,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2853"
+ line="2929"
column="49"/>
</issue>
@@ -19980,7 +9915,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/core/view/ViewCompat.java"
- line="2869"
+ line="2945"
column="37"/>
</issue>
diff --git a/core/core/proguard-rules.pro b/core/core/proguard-rules.pro
index 47a95b5..bcc9a89 100644
--- a/core/core/proguard-rules.pro
+++ b/core/core/proguard-rules.pro
@@ -11,3 +11,6 @@
-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.os.UserHandleCompat$Api*Impl {
<methods>;
}
+-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.widget.EdgeEffectCompat$Api*Impl {
+ <methods>;
+}
diff --git a/core/core/src/androidTest/AndroidManifest.xml b/core/core/src/androidTest/AndroidManifest.xml
index acea6c4..6981570 100644
--- a/core/core/src/androidTest/AndroidManifest.xml
+++ b/core/core/src/androidTest/AndroidManifest.xml
@@ -15,52 +15,104 @@
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.support.compat.test">
-
- <uses-permission android:name="android.permission.VIBRATE"/>
- <uses-permission android:name="android.permission.WAKE_LOCK"/>
- <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
-
- <uses-permission android:name="android.permission.READ_CONTACTS"/>
- <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
-
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-
- <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ package="android.support.compat.test">
<application
android:name="androidx.multidex.MultiDexApplication"
+ android:exported="true"
android:supportsRtl="true"
android:theme="@style/TestActivityTheme">
- <activity android:name="androidx.core.widget.ListViewTestActivity"/>
+ <activity
+ android:name="androidx.core.widget.ListViewTestActivity"
+ android:exported="true" />
- <activity android:name="androidx.core.widget.TextViewTestActivity"/>
+ <activity
+ android:name="androidx.core.widget.TextViewTestActivity"
+ android:exported="true" />
- <activity android:name="androidx.core.widget.ReceiveContentTestActivity"/>
+ <activity
+ android:name="androidx.core.widget.ReceiveContentTestActivity"
+ android:exported="true" />
- <activity android:name="androidx.core.widget.TestContentViewActivity"/>
+ <activity
+ android:name="androidx.core.widget.TestContentViewActivity"
+ android:exported="true" />
- <activity android:name="androidx.core.view.VpaActivity"/>
+ <activity
+ android:name="androidx.core.view.VpaActivity"
+ android:exported="true" />
<activity
android:name="android.support.v4.ThemedYellowActivity"
- android:theme="@style/YellowTheme"/>
+ android:exported="true"
+ android:theme="@style/YellowTheme" />
- <activity android:name="androidx.core.view.ViewCompatActivity"/>
+ <activity
+ android:name="androidx.core.view.ViewCompatActivity"
+ android:exported="true" />
- <activity android:name="androidx.core.app.NavUtilsParentActivity"/>
+ <activity
+ android:name="androidx.core.app.NavUtilsParentActivity"
+ android:exported="true" />
<activity
android:name="androidx.core.app.NavUtilsActivity"
+ android:exported="true"
android:parentActivityName="androidx.core.app.NavUtilsParentActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="androidx.core.app.NavUtilsParentActivity" />
</activity>
+
+ <activity
+ android:name="androidx.core.app.TestActivity"
+ android:exported="true"
+ android:icon="@drawable/test_drawable_blue">
+ <intent-filter>
+ <action android:name="androidx.core.content.pm.SHORTCUT_LISTENER" />
+ </intent-filter>
+ <meta-data
+ android:name="androidx.core.content.pm.shortcut_listener_impl"
+ android:value="androidx.core.content.pm.TestShortcutInfoChangeListener" />
+ </activity>
+
+ <activity
+ android:name="androidx.core.app.TestComponentActivity"
+ android:exported="true" />
+
+ <activity
+ android:name="androidx.core.app.TestActivityWithLifecycle"
+ android:exported="true" />
+ <activity
+ android:name="androidx.core.app.ActivityCompatRecreateLifecycleTestActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.core.view.DragStartHelperTestActivity"
+ android:exported="true" />
+
+ <activity
+ android:name="androidx.core.widget.ContentLoadingProgressBarActivity"
+ android:exported="true" />
+
+ <activity
+ android:name="androidx.core.app.FrameMetricsActivity"
+ android:exported="true" />
+
+ <activity
+ android:name="androidx.core.app.FrameMetricsSubActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.core.widget.EdgeEffectCompatTest$EdgeEffectCompatTestActivity"
+ android:exported="true" />
+ <activity
+ android:name="androidx.core.view.WindowCompatActivity"
+ android:exported="true"
+ android:theme="@android:style/Theme.Light.NoTitleBar" />
+
+ <activity
+ android:name="androidx.core.view.WindowInsetsCompatActivity"
+ android:exported="true"
+ android:theme="@android:style/Theme.Light.NoTitleBar" />
+
<activity-alias
android:name="androidx.core.app.NavUtilsAliasActivity"
android:targetActivity="androidx.core.app.NavUtilsActivity">
@@ -69,34 +121,6 @@
android:value="androidx.core.app.NavUtilsParentActivity" />
</activity-alias>
- <activity android:name="androidx.core.app.TestActivity"
- android:icon="@drawable/test_drawable_blue">
- <intent-filter>
- <action android:name="androidx.core.content.pm.SHORTCUT_LISTENER"/>
- </intent-filter>
- <meta-data android:name="androidx.core.content.pm.shortcut_listener_impl"
- android:value="androidx.core.content.pm.TestShortcutInfoChangeListener"/>
- </activity>
-
- <activity android:name="androidx.core.app.TestComponentActivity"/>
- <activity android:name="androidx.core.app.TestActivityWithLifecycle"/>
- <activity android:name="androidx.core.app.ActivityCompatRecreateLifecycleTestActivity"/>
-
- <activity android:name="androidx.core.view.DragStartHelperTestActivity"/>
-
- <activity android:name="androidx.core.widget.ContentLoadingProgressBarActivity"/>
-
- <activity android:name="androidx.core.app.FrameMetricsActivity"/>
- <activity android:name="androidx.core.app.FrameMetricsSubActivity"/>
-
- <activity
- android:name="androidx.core.view.WindowCompatActivity"
- android:theme="@android:style/Theme.Light.NoTitleBar" />
-
- <activity
- android:name="androidx.core.view.WindowInsetsCompatActivity"
- android:theme="@android:style/Theme.Light.NoTitleBar" />
-
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="moocow;additional.authority"
@@ -104,17 +128,36 @@
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/paths"/>
+ android:resource="@xml/paths" />
</provider>
- <provider android:name="androidx.core.provider.MockFontProvider"
- android:authorities="androidx.core.provider.fonts.font"
- android:exported="false"
- android:multiprocess="true"/>
+ <provider
+ android:name="androidx.core.provider.MockFontProvider"
+ android:authorities="androidx.core.provider.fonts.font"
+ android:exported="false"
+ android:multiprocess="true" />
- <service android:name="androidx.core.app.JobIntentServiceTest$TargetService"
- android:permission="android.permission.BIND_JOB_SERVICE"/>
+ <service
+ android:name="androidx.core.app.JobIntentServiceTest$TargetService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
+ <uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
</manifest>
diff --git a/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java b/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
index 53eebef..8ce5db7 100644
--- a/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
@@ -559,6 +559,18 @@
@FlakyTest(bugId = 190533219)
@Test
+ public void testNotificationBuilder_foregroundServiceBehavior() {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, "channelId");
+ assertEquals(NotificationCompat.FOREGROUND_SERVICE_DEFAULT,
+ builder.getForegroundServiceBehavior());
+ builder.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE);
+ assertEquals(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE,
+ builder.getForegroundServiceBehavior());
+
+ // TODO: validate the built Notifications once there's testing API there
+ }
+
+ @Test
public void testNotificationBuilder_createContentView() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, "channelId");
assertNull(builder.getContentView());
diff --git a/core/core/src/androidTest/java/androidx/core/content/res/CamTest.java b/core/core/src/androidTest/java/androidx/core/content/res/CamTest.java
new file mode 100644
index 0000000..4d8676d
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/content/res/CamTest.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.content.res;
+
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class CamTest {
+ static final int BLACK = 0xff000000;
+ static final int WHITE = 0xffffffff;
+ static final int MIDGRAY = 0xff777777;
+
+ static final int RED = 0xffff0000;
+ static final int GREEN = 0xff00ff00;
+ static final int BLUE = 0xff0000ff;
+
+ @Test
+ public void xyzFromRgb() {
+ float[] xyz = CamUtils.xyzFromInt(RED);
+ float[] expected = new float[]{41.233f, 21.260f, 1.932f};
+ assertArrayEquals(expected, xyz, 0.001f);
+ }
+
+ @Test
+ public void intFrom50LStar() {
+ int color = CamUtils.intFromLStar(50.0f);
+ assertEquals(MIDGRAY, color);
+ }
+
+ @Test
+ public void intFrom0LStar() {
+ int color = CamUtils.intFromLStar(0.0f);
+ assertEquals(BLACK, color);
+ }
+
+ @Test
+ public void intFrom100LStar() {
+ int color = CamUtils.intFromLStar(100.0f);
+ assertEquals(WHITE, color);
+ }
+
+ @Test
+ public void camFromIntToInt() {
+ CamColor cam = CamColor.fromColor(RED);
+ int color = cam.viewed(ViewingConditions.DEFAULT);
+ assertEquals(color, RED);
+ }
+
+ @Test
+ public void yFromMidgray() {
+ assertEquals(18.418f, CamUtils.yFromLStar(50.0f), 0.001);
+ }
+
+ @Test
+ public void yFromBlack() {
+ assertEquals(0.0f, CamUtils.yFromLStar(0.0f), 0.001);
+ }
+
+ @Test
+ public void yFromWhite() {
+ assertEquals(100.0f, CamUtils.yFromLStar(100.0f), 0.001);
+ }
+
+ @Test
+ public void camFromRed() {
+ CamColor cam = CamColor.fromColor(RED);
+ assertEquals(46.445f, cam.getJ(), 0.001f);
+ assertEquals(113.357f, cam.getChroma(), 0.001f);
+ assertEquals(27.408f, cam.getHue(), 0.001f);
+ assertEquals(89.494f, cam.getM(), 0.001f);
+ assertEquals(91.889f, cam.getS(), 0.001f);
+ assertEquals(105.988f, cam.getQ(), 0.001f);
+ }
+
+ @Test
+ public void camFromGreen() {
+ CamColor cam = CamColor.fromColor(GREEN);
+ assertEquals(79.331f, cam.getJ(), 0.001f);
+ assertEquals(108.409f, cam.getChroma(), 0.001f);
+ assertEquals(142.139f, cam.getHue(), 0.001f);
+ assertEquals(85.587f, cam.getM(), 0.001f);
+ assertEquals(78.604f, cam.getS(), 0.001f);
+ assertEquals(138.520, cam.getQ(), 0.001f);
+ }
+
+ @Test
+ public void camFromBlue() {
+ CamColor cam = CamColor.fromColor(BLUE);
+ assertEquals(25.465f, cam.getJ(), 0.001f);
+ assertEquals(87.230f, cam.getChroma(), 0.001f);
+ assertEquals(282.788f, cam.getHue(), 0.001f);
+ assertEquals(68.867f, cam.getM(), 0.001f);
+ assertEquals(93.674f, cam.getS(), 0.001f);
+ assertEquals(78.481f, cam.getQ(), 0.001f);
+ }
+
+ @Test
+ public void camFromBlack() {
+ CamColor cam = CamColor.fromColor(BLACK);
+ assertEquals(0.0f, cam.getJ(), 0.001f);
+ assertEquals(0.0f, cam.getChroma(), 0.001f);
+ assertEquals(0.0f, cam.getHue(), 0.001f);
+ assertEquals(0.0f, cam.getM(), 0.001f);
+ assertEquals(0.0f, cam.getS(), 0.001f);
+ assertEquals(0.0f, cam.getQ(), 0.001f);
+ }
+
+ @Test
+ public void camFromWhite() {
+ CamColor cam = CamColor.fromColor(WHITE);
+ assertEquals(100.0f, cam.getJ(), 0.001f);
+ assertEquals(2.869f, cam.getChroma(), 0.001f);
+ assertEquals(209.492f, cam.getHue(), 0.001f);
+ assertEquals(2.265f, cam.getM(), 0.001f);
+ assertEquals(12.068f, cam.getS(), 0.001f);
+ assertEquals(155.521, cam.getQ(), 0.001f);
+ }
+
+ @Test
+ public void getRedFromGamutMap() {
+ int colorToTest = RED;
+ CamColor cam = CamColor.fromColor(colorToTest);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(),
+ CamUtils.lStarFromInt(colorToTest));
+ assertEquals(colorToTest, color);
+ }
+
+ @Test
+ public void getGreenFromGamutMap() {
+ int colorToTest = GREEN;
+ CamColor cam = CamColor.fromColor(colorToTest);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(),
+ CamUtils.lStarFromInt(colorToTest));
+ assertEquals(colorToTest, color);
+ }
+
+ @Test
+ public void getBlueFromGamutMap() {
+ int colorToTest = BLUE;
+ CamColor cam = CamColor.fromColor(colorToTest);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(),
+ CamUtils.lStarFromInt(colorToTest));
+ assertEquals(colorToTest, color);
+ }
+
+ @Test
+ public void getWhiteFromGamutMap() {
+ int colorToTest = WHITE;
+ CamColor cam = CamColor.fromColor(colorToTest);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(),
+ CamUtils.lStarFromInt(colorToTest));
+ assertEquals(colorToTest, color);
+ }
+
+ @Test
+ public void getBlackFromGamutMap() {
+ int colorToTest = BLACK;
+ CamColor cam = CamColor.fromColor(colorToTest);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(),
+ CamUtils.lStarFromInt(colorToTest));
+ assertEquals(colorToTest, color);
+ }
+
+ @Test
+ public void getMidgrayFromGamutMap() {
+ int colorToTest = MIDGRAY;
+ CamColor cam = CamColor.fromColor(colorToTest);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(),
+ CamUtils.lStarFromInt(colorToTest));
+ assertEquals(colorToTest, color);
+ }
+
+ @Test
+ public void getMidredFromRedAndGamutMap() {
+ CamColor cam = CamColor.fromColor(RED);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(), 50.0f);
+ assertEquals(0xfff00000, color);
+ }
+
+ @Test
+ public void getRandomGreenFromGamutMap() {
+ int colorToTest = 0xff009200;
+ CamColor cam = CamColor.fromColor(colorToTest);
+ int color = CamColor.toColor(cam.getHue(), cam.getChroma(),
+ CamUtils.lStarFromInt(colorToTest));
+ assertEquals(colorToTest, color);
+ }
+
+ @Test
+ public void gamutMapArbitraryHCL() {
+ int color = CamColor.toColor(309.0f, 40.0f, 70.0f);
+ CamColor cam = CamColor.fromColor(color);
+
+ assertEquals(308.759f, cam.getHue(), 0.001);
+ assertEquals(40.148f, cam.getChroma(), 0.001);
+ assertEquals(70.029f, CamUtils.lStarFromInt(color), 0.001f);
+ }
+
+ @Test
+ public void ucsCoordinates() {
+ CamColor cam = CamColor.fromColor(RED);
+
+ assertEquals(59.584f, cam.getJStar(), 0.001f);
+ assertEquals(43.297f, cam.getAStar(), 0.001f);
+ assertEquals(22.451f, cam.getBStar(), 0.001f);
+ }
+
+ @Test
+ public void deltaEWhiteToBlack() {
+ assertEquals(25.661f, CamColor.fromColor(WHITE).distance(CamColor.fromColor(BLACK)),
+ 0.001f);
+ }
+
+ @Test
+ public void deltaERedToBlue() {
+ assertEquals(21.415f, CamColor.fromColor(RED).distance(CamColor.fromColor(BLUE)), 0.001f);
+ }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/content/res/ColorStateListInflaterCompatTest.java b/core/core/src/androidTest/java/androidx/core/content/res/ColorStateListInflaterCompatTest.java
index 72572a4..0a74104 100644
--- a/core/core/src/androidTest/java/androidx/core/content/res/ColorStateListInflaterCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/content/res/ColorStateListInflaterCompatTest.java
@@ -29,9 +29,11 @@
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
+import androidx.core.graphics.ColorUtils;
import androidx.core.test.R;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -93,6 +95,46 @@
assertEquals(expectedTextColorSecondary, result.getDefaultColor());
}
+ @Test
+ public void testCreateFromXmlWithAppLStar() {
+ final double lStarInXml = 50.0;
+ final int alphaInXml = 128;
+
+ final Resources res = mContext.getResources();
+ final ColorStateList c = ColorStateListInflaterCompat.inflate(
+ res, R.color.color_state_list_lstar, mContext.getTheme());
+ final int defaultColor = c.getDefaultColor();
+
+ final double[] labColor = new double[3];
+ ColorUtils.colorToLAB(defaultColor, labColor);
+
+ // There's precision loss when converting to @ColorInt. We need a small delta.
+ assertEquals(lStarInXml, labColor[0], 1.0 /* delta */);
+ assertEquals(alphaInXml, Color.alpha(defaultColor));
+ }
+
+ /**
+ * Tests using android:lStar which is added in Android S
+ */
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testCreateFromXmlWithAndroidLStar() {
+ final double lStarInXml = 50.0;
+ final int alphaInXml = 128;
+
+ final Resources res = mContext.getResources();
+ final ColorStateList c = ColorStateListInflaterCompat.inflate(
+ res, R.color.color_state_list_android_lstar, mContext.getTheme());
+ final int defaultColor = c.getDefaultColor();
+
+ final double[] labColor = new double[3];
+ ColorUtils.colorToLAB(defaultColor, labColor);
+
+ // There's precision loss when converting to @ColorInt. We need a small delta.
+ assertEquals(lStarInXml, labColor[0], 1.0 /* delta */);
+ assertEquals(alphaInXml, Color.alpha(defaultColor));
+ }
+
@ColorInt
private int getColorFromTheme(@AttrRes int attrResId) {
TypedArray a = TypedArrayUtils.obtainAttributes(mResources, mContext.getTheme(), null,
diff --git a/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java b/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java
index a8a5399..c59abd0 100644
--- a/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java
@@ -19,11 +19,12 @@
import static android.provider.Settings.Secure.LOCATION_MODE;
import static android.provider.Settings.Secure.LOCATION_MODE_OFF;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Handler;
@@ -33,7 +34,6 @@
import androidx.core.os.CancellationSignal;
import androidx.core.os.ExecutorCompat;
-import androidx.core.util.Consumer;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -76,20 +76,68 @@
}
@Test
+ public void testHasProvider() {
+ for (String provider : mLocationManager.getAllProviders()) {
+ boolean hasProvider;
+ if (Build.VERSION.SDK_INT >= 31) {
+ hasProvider = mLocationManager.hasProvider(provider);
+ } else {
+ hasProvider = mLocationManager.getProvider(provider) != null;
+ }
+
+ assertEquals(hasProvider, LocationManagerCompat.hasProvider(mLocationManager,
+ provider));
+ }
+ }
+
+ @Test
public void testGetCurrentLocation() {
// can't do much to test this except check it doesn't crash
CancellationSignal cs = new CancellationSignal();
LocationManagerCompat.getCurrentLocation(mLocationManager,
LocationManager.PASSIVE_PROVIDER, cs,
ExecutorCompat.create(new Handler(Looper.getMainLooper())),
- new Consumer<Location>() {
- @Override
- public void accept(Location location) {}
- });
+ location -> {});
cs.cancel();
}
@Test
+ public void testRequestLocationUpdates_Executor() {
+ // can't do much to test this except check it doesn't crash
+ LocationRequestCompat request = new LocationRequestCompat.Builder(0).build();
+ LocationListenerCompat listener1 = location -> {};
+ LocationListenerCompat listener2 = location -> {};
+ for (String provider : mLocationManager.getAllProviders()) {
+ LocationManagerCompat.requestLocationUpdates(mLocationManager, provider, request,
+ directExecutor(), listener1);
+ LocationManagerCompat.requestLocationUpdates(mLocationManager, provider, request,
+ directExecutor(), listener2);
+ LocationManagerCompat.requestLocationUpdates(mLocationManager, provider, request,
+ directExecutor(), listener1);
+ }
+ LocationManagerCompat.removeUpdates(mLocationManager, listener1);
+ LocationManagerCompat.removeUpdates(mLocationManager, listener2);
+ }
+
+ @Test
+ public void testRequestLocationUpdates_Looper() {
+ // can't do much to test this except check it doesn't crash
+ LocationRequestCompat request = new LocationRequestCompat.Builder(0).build();
+ LocationListenerCompat listener1 = location -> {};
+ LocationListenerCompat listener2 = location -> {};
+ for (String provider : mLocationManager.getAllProviders()) {
+ LocationManagerCompat.requestLocationUpdates(mLocationManager, provider, request,
+ listener1, Looper.getMainLooper());
+ LocationManagerCompat.requestLocationUpdates(mLocationManager, provider, request,
+ listener2, Looper.getMainLooper());
+ LocationManagerCompat.requestLocationUpdates(mLocationManager, provider, request,
+ listener1, Looper.getMainLooper());
+ }
+ LocationManagerCompat.removeUpdates(mLocationManager, listener1);
+ LocationManagerCompat.removeUpdates(mLocationManager, listener2);
+ }
+
+ @Test
public void testGetGnssHardwareModelName() {
// can't do much to test this except check it doesn't crash
LocationManagerCompat.getGnssHardwareModelName(mLocationManager);
diff --git a/core/core/src/androidTest/java/androidx/core/location/LocationRequestCompatTest.java b/core/core/src/androidTest/java/androidx/core/location/LocationRequestCompatTest.java
new file mode 100644
index 0000000..4500b2c
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/location/LocationRequestCompatTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.location;
+
+import static androidx.core.location.LocationRequestCompat.PASSIVE_INTERVAL;
+import static androidx.core.location.LocationRequestCompat.QUALITY_BALANCED_POWER_ACCURACY;
+import static androidx.core.location.LocationRequestCompat.QUALITY_HIGH_ACCURACY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+
+import android.location.LocationRequest;
+import android.os.SystemClock;
+
+import androidx.core.util.Preconditions;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.collect.Range;
+
+import org.junit.Test;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+@SmallTest
+public class LocationRequestCompatTest {
+
+ private static Method sGetProviderMethod;
+ private static Method sGetIntervalMethod;
+ private static Method sGetFastestIntervalMethod;
+ private static Method sGetExpireAtMethod;
+ private static Method sGetNumUpdatesMethod;
+ private static Method sGetSmallestDisplacementMethod;
+
+ @Test
+ public void testBuilder() {
+ LocationRequestCompat.Builder builder = new LocationRequestCompat.Builder(0);
+
+ assertEquals(QUALITY_BALANCED_POWER_ACCURACY, builder.build().getQuality());
+ assertEquals(0, builder.build().getIntervalMillis());
+ assertEquals(0, builder.build().getMinUpdateIntervalMillis());
+ assertEquals(Long.MAX_VALUE, builder.build().getDurationMillis());
+ assertEquals(Integer.MAX_VALUE, builder.build().getMaxUpdates());
+ assertEquals(0, builder.build().getMinUpdateDistanceMeters(), 0);
+ assertEquals(0, builder.build().getMaxUpdateDelayMillis());
+
+ builder.setQuality(QUALITY_HIGH_ACCURACY);
+ assertEquals(QUALITY_HIGH_ACCURACY, builder.build().getQuality());
+
+ builder.setIntervalMillis(1000);
+ assertEquals(1000, builder.build().getIntervalMillis());
+
+ builder.setMinUpdateIntervalMillis(1500);
+ assertEquals(1000, builder.build().getMinUpdateIntervalMillis());
+
+ builder.setMinUpdateIntervalMillis(500);
+ assertEquals(500, builder.build().getMinUpdateIntervalMillis());
+
+ builder.clearMinUpdateIntervalMillis();
+ assertEquals(1000, builder.build().getMinUpdateIntervalMillis());
+
+ builder.setDurationMillis(1);
+ assertEquals(1, builder.build().getDurationMillis());
+
+ builder.setMaxUpdates(1);
+ assertEquals(1, builder.build().getMaxUpdates());
+
+ builder.setMinUpdateDistanceMeters(10);
+ assertEquals(10, builder.build().getMinUpdateDistanceMeters(), 0);
+
+ builder.setMaxUpdateDelayMillis(10000);
+ assertEquals(10000, builder.build().getMaxUpdateDelayMillis());
+
+ builder.setIntervalMillis(PASSIVE_INTERVAL);
+ builder.setMinUpdateIntervalMillis(0);
+ assertEquals(PASSIVE_INTERVAL, builder.build().getIntervalMillis());
+ }
+
+ @SdkSuppress(minSdkVersion = 19, maxSdkVersion = 30)
+ @Test
+ public void testConversion_19Plus() throws Exception {
+ LocationRequestCompat.Builder builder = new LocationRequestCompat.Builder(0);
+
+ assertEquals("test", getProvider(builder.build().toLocationRequest("test")));
+ assertEquals(QUALITY_BALANCED_POWER_ACCURACY,
+ builder.build().toLocationRequest("test").getQuality());
+ assertEquals(0, getInterval(builder.build().toLocationRequest("test")));
+ assertEquals(0, getFastestInterval(builder.build().toLocationRequest("test")));
+ assertEquals(Long.MAX_VALUE, getExpireAt(builder.build().toLocationRequest()));
+ assertEquals(Integer.MAX_VALUE, getNumUpdates(builder.build().toLocationRequest("test")));
+ assertEquals(0, getSmallestDisplacement(builder.build().toLocationRequest("test")), 0);
+
+ builder.setQuality(QUALITY_HIGH_ACCURACY);
+ assertEquals(QUALITY_HIGH_ACCURACY, builder.build().toLocationRequest("test").getQuality());
+
+ builder.setIntervalMillis(1000);
+ assertEquals(1000, getInterval(builder.build().toLocationRequest("test")));
+
+ builder.setMinUpdateIntervalMillis(1500);
+ assertEquals(1000, getFastestInterval(builder.build().toLocationRequest("test")));
+
+ builder.setMinUpdateIntervalMillis(500);
+ assertEquals(500, getFastestInterval(builder.build().toLocationRequest("test")));
+
+ builder.clearMinUpdateIntervalMillis();
+ assertEquals(1000, getFastestInterval(builder.build().toLocationRequest("test")));
+
+ builder.setDurationMillis(1);
+ long time = SystemClock.elapsedRealtime();
+ assertThat(getExpireAt(builder.build().toLocationRequest())).isIn(
+ Range.closed(time - 1000, time));
+
+ builder.setMaxUpdates(1);
+ assertEquals(1, getNumUpdates(builder.build().toLocationRequest("test")));
+
+ builder.setMinUpdateDistanceMeters(10);
+ assertEquals(10, getSmallestDisplacement(builder.build().toLocationRequest("test")), 0);
+ }
+
+ @SdkSuppress(minSdkVersion = 31)
+ @Test
+ public void testConversion_31Plus() {
+ LocationRequestCompat.Builder builder = new LocationRequestCompat.Builder(0);
+
+ assertEquals(QUALITY_BALANCED_POWER_ACCURACY,
+ builder.build().toLocationRequest().getQuality());
+ assertEquals(0, builder.build().toLocationRequest().getIntervalMillis());
+ assertEquals(0, builder.build().toLocationRequest().getMinUpdateIntervalMillis());
+ assertEquals(Long.MAX_VALUE, builder.build().toLocationRequest().getDurationMillis());
+ assertEquals(Integer.MAX_VALUE, builder.build().toLocationRequest().getMaxUpdates());
+ assertEquals(0, builder.build().toLocationRequest().getMinUpdateDistanceMeters(), 0);
+ assertEquals(0, builder.build().toLocationRequest().getMaxUpdateDelayMillis());
+
+ builder.setQuality(QUALITY_HIGH_ACCURACY);
+ assertEquals(QUALITY_HIGH_ACCURACY, builder.build().toLocationRequest().getQuality());
+
+ builder.setIntervalMillis(1000);
+ assertEquals(1000, builder.build().toLocationRequest().getIntervalMillis());
+
+ builder.setMinUpdateIntervalMillis(1500);
+ assertEquals(1000, builder.build().toLocationRequest().getMinUpdateIntervalMillis());
+
+ builder.setMinUpdateIntervalMillis(500);
+ assertEquals(500, builder.build().toLocationRequest().getMinUpdateIntervalMillis());
+
+ builder.clearMinUpdateIntervalMillis();
+ assertEquals(1000, builder.build().toLocationRequest().getMinUpdateIntervalMillis());
+
+ builder.setDurationMillis(1);
+ assertEquals(1, builder.build().toLocationRequest().getDurationMillis());
+
+ builder.setMaxUpdates(1);
+ assertEquals(1, builder.build().toLocationRequest().getMaxUpdates());
+
+ builder.setMinUpdateDistanceMeters(10);
+ assertEquals(10, builder.build().toLocationRequest().getMinUpdateDistanceMeters(), 0);
+
+ builder.setMaxUpdateDelayMillis(10000);
+ assertEquals(10000, builder.build().toLocationRequest().getMaxUpdateDelayMillis());
+
+ builder.setMinUpdateIntervalMillis(1000);
+ builder.setIntervalMillis(PASSIVE_INTERVAL);
+ assertEquals(PASSIVE_INTERVAL,
+ builder.build().toLocationRequest().getIntervalMillis());
+ }
+
+ private static String getProvider(LocationRequest request)
+ throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ if (sGetProviderMethod == null) {
+ sGetProviderMethod = LocationRequest.class.getDeclaredMethod("getProvider");
+ sGetProviderMethod.setAccessible(true);
+ }
+
+ return (String) sGetProviderMethod.invoke(request);
+ }
+
+ private static long getInterval(LocationRequest request)
+ throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ if (sGetIntervalMethod == null) {
+ sGetIntervalMethod = LocationRequest.class.getDeclaredMethod("getInterval");
+ sGetIntervalMethod.setAccessible(true);
+ }
+
+ return (Long) Preconditions.checkNotNull(sGetIntervalMethod.invoke(request));
+ }
+
+ private static long getFastestInterval(LocationRequest request)
+ throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ if (sGetFastestIntervalMethod == null) {
+ sGetFastestIntervalMethod = LocationRequest.class.getDeclaredMethod(
+ "getFastestInterval");
+ sGetFastestIntervalMethod.setAccessible(true);
+ }
+
+ return (Long) Preconditions.checkNotNull(sGetFastestIntervalMethod.invoke(request));
+ }
+
+ private static long getExpireAt(LocationRequest request)
+ throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ if (sGetExpireAtMethod == null) {
+ sGetExpireAtMethod = LocationRequest.class.getDeclaredMethod("getExpireAt");
+ sGetExpireAtMethod.setAccessible(true);
+ }
+
+ return (Long) Preconditions.checkNotNull(sGetExpireAtMethod.invoke(request));
+ }
+
+ private static int getNumUpdates(LocationRequest request)
+ throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ if (sGetNumUpdatesMethod == null) {
+ sGetNumUpdatesMethod = LocationRequest.class.getDeclaredMethod("getNumUpdates");
+ sGetNumUpdatesMethod.setAccessible(true);
+ }
+
+ return (Integer) Preconditions.checkNotNull(sGetNumUpdatesMethod.invoke(request));
+ }
+
+ private static float getSmallestDisplacement(LocationRequest request)
+ throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ if (sGetSmallestDisplacementMethod == null) {
+ sGetSmallestDisplacementMethod = LocationRequest.class.getDeclaredMethod(
+ "getSmallestDisplacement");
+ sGetSmallestDisplacementMethod.setAccessible(true);
+ }
+
+ return (Float) Preconditions.checkNotNull(sGetSmallestDisplacementMethod.invoke(request));
+ }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/view/AccessibilityDelegateCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/AccessibilityDelegateCompatTest.java
index 6257ad1..b27dd32 100644
--- a/core/core/src/androidTest/java/androidx/core/view/AccessibilityDelegateCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/AccessibilityDelegateCompatTest.java
@@ -16,14 +16,10 @@
package androidx.core.view;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -57,11 +53,11 @@
import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
import androidx.core.view.accessibility.AccessibilityViewCommand;
import androidx.core.view.accessibility.AccessibilityViewCommand.MoveAtGranularityArguments;
-import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SdkSuppress;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -78,7 +74,6 @@
BaseInstrumentationTestCase<ViewCompatActivity> {
private static final int TIMEOUT_ASYNC_PROCESSING = 5000;
- private static Instrumentation sInstrumentation;
private static UiAutomation sUiAutomation;
private ViewGroup mView;
@@ -88,21 +83,24 @@
}
@Before
- public void setUp() {
- sInstrumentation = InstrumentationRegistry.getInstrumentation();
- sUiAutomation = sInstrumentation.getUiAutomation();
+ public void setUp() throws Throwable {
+ Instrumentation instr = InstrumentationRegistry.getInstrumentation();
+ sUiAutomation = instr.getUiAutomation();
+
final Activity activity = mActivityTestRule.getActivity();
- // Use a group, so it has a child
- mView = (ViewGroup) activity.findViewById(androidx.core.test.R.id.view).getParent();
- // On KitKat, some delegate methods aren't called for non-important views
- ViewCompat.setImportantForAccessibility(mView, View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ mActivityTestRule.runOnUiThread(() -> {
+ // Use a group, so it has a child
+ mView = (ViewGroup) activity.findViewById(androidx.core.test.R.id.view).getParent();
+ // On KitKat, some delegate methods aren't called for non-important views
+ ViewCompat.setImportantForAccessibility(mView, View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ });
}
@Test
- public void testViewWithDelegate_reportsHasDelegate() {
- assertThat(ViewCompat.hasAccessibilityDelegate(mView), equalTo(false));
+ public void testViewWithDelegate_reportsHasDelegate() throws Throwable {
+ assertFalse(ViewCompat.hasAccessibilityDelegate(mView));
ViewCompat.setAccessibilityDelegate(mView, new AccessibilityDelegateCompat());
- assertThat(ViewCompat.hasAccessibilityDelegate(mView), equalTo(true));
+ assertTrue(ViewCompat.hasAccessibilityDelegate(mView));
}
@Test
@@ -115,37 +113,37 @@
@Test
@SdkSuppress(minSdkVersion = 19)
public void testScreenReaderFocusable_propagatesToAccessibilityNodeInfo() {
- assertThat(ViewCompat.isScreenReaderFocusable(mView), is(false));
- assertThat(getNodeCompatForView(mView).isScreenReaderFocusable(), is(false));
+ assertFalse(ViewCompat.isScreenReaderFocusable(mView));
+ assertFalse(getNodeCompatForView(mView).isScreenReaderFocusable());
ViewCompat.setScreenReaderFocusable(mView, true);
- assertThat(ViewCompat.isScreenReaderFocusable(mView), is(true));
- assertThat(getNodeCompatForView(mView).isScreenReaderFocusable(), is(true));
+ assertTrue(ViewCompat.isScreenReaderFocusable(mView));
+ assertTrue(getNodeCompatForView(mView).isScreenReaderFocusable());
// The value should still propagate even if we attach and detach another delegate compat
ViewCompat.setAccessibilityDelegate(mView, new AccessibilityDelegateCompat());
- assertThat(getNodeCompatForView(mView).isScreenReaderFocusable(), is(true));
+ assertTrue(getNodeCompatForView(mView).isScreenReaderFocusable());
ViewCompat.setAccessibilityDelegate(mView, null);
- assertThat(getNodeCompatForView(mView).isScreenReaderFocusable(), is(true));
+ assertTrue(getNodeCompatForView(mView).isScreenReaderFocusable());
}
@Test
@SdkSuppress(minSdkVersion = 19)
public void testAccessibilityHeading_propagatesToAccessibilityNodeInfo() {
- assertThat(ViewCompat.isAccessibilityHeading(mView), is(false));
- assertThat(getNodeCompatForView(mView).isHeading(), is(false));
+ assertFalse(ViewCompat.isAccessibilityHeading(mView));
+ assertFalse(getNodeCompatForView(mView).isHeading());
ViewCompat.setAccessibilityHeading(mView, true);
- assertThat(ViewCompat.isAccessibilityHeading(mView), is(true));
- assertThat(getNodeCompatForView(mView).isHeading(), is(true));
+ assertTrue(ViewCompat.isAccessibilityHeading(mView));
+ assertTrue(getNodeCompatForView(mView).isHeading());
// The value should still propagate even if we attach and detach another delegate compat
ViewCompat.setAccessibilityDelegate(mView, new AccessibilityDelegateCompat());
- assertThat(getNodeCompatForView(mView).isHeading(), is(true));
+ assertTrue(getNodeCompatForView(mView).isHeading());
ViewCompat.setAccessibilityDelegate(mView, null);
- assertThat(getNodeCompatForView(mView).isHeading(), is(true));
+ assertTrue(getNodeCompatForView(mView).isHeading());
}
@Test
@@ -197,14 +195,11 @@
public void testAccessibilityPaneTitle_isSentOnAppearance() throws Throwable {
final CharSequence title = "Sample title";
ViewCompat.setAccessibilityPaneTitle(mView, title);
- mActivityTestRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- // Update the AccessibilityPaneVisibilityManager
- mView.setVisibility(View.INVISIBLE);
- mView.getViewTreeObserver().dispatchOnGlobalLayout();
- mView.setVisibility(View.VISIBLE);
- }
+ mActivityTestRule.runOnUiThread(() -> {
+ // Update the AccessibilityPaneVisibilityManager
+ mView.setVisibility(View.INVISIBLE);
+ mView.getViewTreeObserver().dispatchOnGlobalLayout();
+ mView.setVisibility(View.VISIBLE);
});
final AccessibilityDelegateCompat mockDelegate = mock(
@@ -217,15 +212,15 @@
ArgumentCaptor.forClass(AccessibilityEvent.class);
if (Build.VERSION.SDK_INT < 28) {
// Validity check
- assertThat(ViewCompat.getImportantForAccessibility(mView),
- equalTo(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES));
+ assertEquals(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
+ ViewCompat.getImportantForAccessibility(mView));
verify(mockDelegate).sendAccessibilityEventUnchecked(
eq(mView), argumentCaptor.capture());
AccessibilityEvent event = argumentCaptor.getValue();
- assertThat(event.getText().get(0), equalTo(title));
- assertThat((event.getContentChangeTypes()
- & AccessibilityEventCompat.CONTENT_CHANGE_TYPE_PANE_APPEARED), not(0));
+ assertEquals(title, event.getText().get(0));
+ assertNotEquals(0, event.getContentChangeTypes()
+ & AccessibilityEventCompat.CONTENT_CHANGE_TYPE_PANE_APPEARED);
} else {
verify(mockDelegate, never()).sendAccessibilityEventUnchecked(
eq(mView), argumentCaptor.capture());
@@ -239,46 +234,40 @@
ViewCompat.setAccessibilityPaneTitle(mView, title);
// Validity check
- assertThat(ViewCompat.getImportantForAccessibility(mView),
- equalTo(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES));
+ assertEquals(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
+ ViewCompat.getImportantForAccessibility(mView));
final Activity activity = mActivityTestRule.getActivity();
- sUiAutomation.executeAndWaitForEvent(new Runnable() {
- @Override
- public void run() {
- try {
- mActivityTestRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
+ sUiAutomation.executeAndWaitForEvent(
+ () -> {
+ try {
+ mActivityTestRule.runOnUiThread(() -> {
// Update the AccessibilityPaneVisibilityManager
mView.setVisibility(View.INVISIBLE);
mView.getViewTreeObserver().dispatchOnGlobalLayout();
- }
- });
- } catch (Throwable throwable) {
- throwable.printStackTrace();
- }
- }
- }, new UiAutomation.AccessibilityEventFilter() {
- @Override
- public boolean accept(AccessibilityEvent event) {
- boolean isWindowStateChanged = event.getEventType()
- == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
- int isPaneTitle = (event.getContentChangeTypes()
- & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED);
- // onInitializeA11yEvent was not called in 28, so package name was not set
- boolean isFromThisPackage = Build.VERSION.SDK_INT == 28
- || TextUtils.equals(event.getPackageName(), activity.getPackageName());
- boolean hasTitleText = false;
- if (event.getText().size() > 0) {
- hasTitleText = event.getText().get(0).equals(title);
- }
- return isWindowStateChanged
- && (isPaneTitle != 0)
- && isFromThisPackage
- && hasTitleText;
- }
- }, TIMEOUT_ASYNC_PROCESSING);
+ });
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ },
+ event -> {
+ boolean isWindowStateChanged = event.getEventType()
+ == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+ int isPaneTitle = (event.getContentChangeTypes()
+ & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED);
+ // onInitializeA11yEvent was not called in 28, so package name was not set
+ boolean isFromThisPackage = Build.VERSION.SDK_INT == 28
+ || TextUtils.equals(event.getPackageName(), activity.getPackageName());
+ boolean hasTitleText = false;
+ if (event.getText().size() > 0) {
+ hasTitleText = event.getText().get(0).equals(title);
+ }
+ return isWindowStateChanged
+ && (isPaneTitle != 0)
+ && isFromThisPackage
+ && hasTitleText;
+ },
+ TIMEOUT_ASYNC_PROCESSING);
}
@Test
@@ -315,8 +304,8 @@
ArgumentCaptor.forClass(Bundle.class);
verify(nodeInfo).performAction(
integerArgumentCaptor.capture(), bundleArgumentCaptor.capture());
- Bundle args = bundleArgumentCaptor.<Bundle>getValue();
- int actionId = integerArgumentCaptor.<Integer>getValue();
+ Bundle args = bundleArgumentCaptor.getValue();
+ int actionId = integerArgumentCaptor.getValue();
//The service would end up calling the same thing ViewCompat calls
ViewCompat.performAccessibilityAction(mView, actionId, args);
@@ -340,10 +329,10 @@
final AccessibilityViewCommand action = mock(AccessibilityViewCommand.class);
final CharSequence label = "Asad's action";
final int id = ViewCompat.addAccessibilityAction(mView, label, action);
- assertThat(nodeActionCountsWithId(id, label), equalTo(1));
+ assertEquals(1, nodeActionCountsWithId(id, label));
final int newId = ViewCompat.addAccessibilityAction(mView, label, action);
- assertThat(nodeActionCountsWithId(id, label), equalTo(1));
+ assertEquals(1, nodeActionCountsWithId(id, label));
assertEquals(id, newId);
}
@@ -441,15 +430,12 @@
@Test
@SdkSuppress(minSdkVersion = 21)
public void testReplaceActionPerformIsCalledWithArguments() {
- final AccessibilityViewCommand action =
- (AccessibilityViewCommand) mock(
- AccessibilityViewCommand.class);
+ final AccessibilityViewCommand action = mock(AccessibilityViewCommand.class);
ViewCompat.replaceAccessibilityAction(mView,
AccessibilityActionCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, "Move title",
action);
-
final Bundle bundle = new Bundle();
final int granularity = AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER;
bundle.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
@@ -466,8 +452,8 @@
final ArgumentCaptor<MoveAtGranularityArguments> argCaptor = ArgumentCaptor.forClass(
MoveAtGranularityArguments.class);
verify(action).perform(eq(mView), argCaptor.capture());
- assertTrue(argCaptor.getValue().getGranularity() == granularity);
- assertTrue(argCaptor.getValue().getExtendSelection() == extendSelection);
+ assertEquals(granularity, argCaptor.getValue().getGranularity());
+ assertEquals(extendSelection, argCaptor.getValue().getExtendSelection());
}
@Test
@@ -484,29 +470,24 @@
public void testSetAccessibilityPaneTitle_sendsOutCorrectEvent() throws TimeoutException {
final Activity activity = mActivityTestRule.getActivity();
- sUiAutomation.executeAndWaitForEvent(new Runnable() {
- @Override
- public void run() {
- ViewCompat.setAccessibilityPaneTitle(mView, "test");
- }
- }, new UiAutomation.AccessibilityEventFilter() {
- @Override
- public boolean accept(AccessibilityEvent event) {
- boolean isWindowStateChanged = event.getEventType()
- == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
- int isPaneTitle = (event.getContentChangeTypes()
- & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE);
- // onInitializeA11yEvent is not called in 28 for panes, so the package name
- // isn't set
- boolean isFromThisPackage = Build.VERSION.SDK_INT == 28
- || TextUtils.equals(event.getPackageName(),
- activity.getPackageName());
- boolean isFromThisSource =
- event.getSource().equals(mView.createAccessibilityNodeInfo());
- return isWindowStateChanged && (isPaneTitle != 0) && isFromThisPackage
- && isFromThisSource;
- }
- }, TIMEOUT_ASYNC_PROCESSING);
+ sUiAutomation.executeAndWaitForEvent(
+ () -> ViewCompat.setAccessibilityPaneTitle(mView, "test"),
+ event -> {
+ boolean isWindowStateChanged = event.getEventType()
+ == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+ int isPaneTitle = (event.getContentChangeTypes()
+ & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE);
+ // onInitializeA11yEvent is not called in 28 for panes, so the package name
+ // isn't set
+ boolean isFromThisPackage = Build.VERSION.SDK_INT == 28
+ || TextUtils.equals(event.getPackageName(),
+ activity.getPackageName());
+ boolean isFromThisSource =
+ event.getSource().equals(mView.createAccessibilityNodeInfo());
+ return isWindowStateChanged && (isPaneTitle != 0) && isFromThisPackage
+ && isFromThisSource;
+ },
+ TIMEOUT_ASYNC_PROCESSING);
}
@Test
@@ -516,35 +497,29 @@
final Activity activity = mActivityTestRule.getActivity();
final CharSequence state = "test";
- assertThat(ViewCompat.getStateDescription(mView), is(nullValue()));
- assertThat(getNodeCompatForView(mView).getStateDescription(), is(nullValue()));
+ assertNull(ViewCompat.getStateDescription(mView));
+ assertNull(getNodeCompatForView(mView).getStateDescription());
- sUiAutomation.executeAndWaitForEvent(new Runnable() {
- @Override
- public void run() {
- ViewCompat.setStateDescription(mView, state);
- }
- }, new UiAutomation.AccessibilityEventFilter() {
- @Override
- public boolean accept(AccessibilityEvent event) {
- boolean isContentChanged = event.getEventType()
- == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
- int isStateDescription = (event.getContentChangeTypes()
- & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION);
- boolean isFromThisPackage = TextUtils.equals(event.getPackageName(),
- activity.getPackageName());
- return isContentChanged && (isStateDescription != 0) && isFromThisPackage;
- }
- }, TIMEOUT_ASYNC_PROCESSING);
+ sUiAutomation.executeAndWaitForEvent(
+ () -> ViewCompat.setStateDescription(mView, state), event -> {
+ boolean isContentChanged = event.getEventType()
+ == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
+ int isStateDescription = (event.getContentChangeTypes()
+ & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION);
+ boolean isFromThisPackage = TextUtils.equals(event.getPackageName(),
+ activity.getPackageName());
+ return isContentChanged && (isStateDescription != 0) && isFromThisPackage;
+ },
+ TIMEOUT_ASYNC_PROCESSING);
- assertThat(ViewCompat.getStateDescription(mView), is(state));
- assertThat(getNodeCompatForView(mView).getStateDescription(), is(state));
+ assertEquals(state, ViewCompat.getStateDescription(mView));
+ assertEquals(state, getNodeCompatForView(mView).getStateDescription());
// The value should still propagate even if we attach and detach another delegate compat
ViewCompat.setAccessibilityDelegate(mView, new AccessibilityDelegateCompat());
- assertThat(getNodeCompatForView(mView).getStateDescription(), is(state));
+ assertEquals(state, getNodeCompatForView(mView).getStateDescription());
ViewCompat.setAccessibilityDelegate(mView, null);
- assertThat(getNodeCompatForView(mView).getStateDescription(), is(state));
+ assertEquals(state, getNodeCompatForView(mView).getStateDescription());
}
private void assertMockAccessibilityDelegateWorkingOnView(
@@ -625,7 +600,7 @@
};
when(bridgedCompat.getAccessibilityNodeProvider(mView)).thenReturn(providerCompat);
AccessibilityNodeProvider provider = mView.getAccessibilityNodeProvider();
- assertThat(provider.createAccessibilityNodeInfo(0), equalTo(info));
+ assertEquals(info, provider.createAccessibilityNodeInfo(0));
final Bundle bundle = new Bundle();
mView.performAccessibilityAction(
diff --git a/core/core/src/androidTest/java/androidx/core/view/ContentInfoCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/ContentInfoCompatTest.java
index 74dd573..9c5f09a 100644
--- a/core/core/src/androidTest/java/androidx/core/view/ContentInfoCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/ContentInfoCompatTest.java
@@ -16,6 +16,8 @@
package androidx.core.view;
+import static androidx.core.view.ContentInfoCompat.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static androidx.core.view.ContentInfoCompat.SOURCE_APP;
import static androidx.core.view.ContentInfoCompat.SOURCE_CLIPBOARD;
import static com.google.common.truth.Truth.assertThat;
@@ -24,11 +26,14 @@
import android.net.Uri;
import android.os.Bundle;
import android.util.Pair;
+import android.view.ContentInfo;
import androidx.core.util.Predicate;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,7 +48,7 @@
clip.addItem(new ClipData.Item("Hi"));
clip.addItem(new ClipData.Item(sampleUri));
ContentInfoCompat payload = new ContentInfoCompat.Builder(clip, SOURCE_CLIPBOARD)
- .setFlags(ContentInfoCompat.FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setFlags(FLAG_CONVERT_TO_PLAIN_TEXT)
.setLinkUri(Uri.parse("http://example.com"))
.setExtras(new Bundle())
.build();
@@ -95,7 +100,7 @@
public void testPartition_singleItem() throws Exception {
ClipData clip = ClipData.newPlainText("", "Hello");
ContentInfoCompat payload = new ContentInfoCompat.Builder(clip, SOURCE_CLIPBOARD)
- .setFlags(ContentInfoCompat.FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setFlags(FLAG_CONVERT_TO_PLAIN_TEXT)
.setLinkUri(Uri.parse("http://example.com"))
.setExtras(new Bundle())
.build();
@@ -119,4 +124,247 @@
assertThat(split.first).isSameInstanceAs(payload);
assertThat(split.second).isNull();
}
+
+ @Test
+ public void testBuilder_validation() throws Exception {
+ ClipData clip = ClipData.newPlainText("", "Hello");
+
+ // Test validation of source.
+ ContentInfoCompat.Builder builder = new ContentInfoCompat.Builder(clip, 6);
+ try {
+ ContentInfoCompat payload = builder.build();
+ Assert.fail("Expected exception but got: " + payload);
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Test validation of flags.
+ builder = new ContentInfoCompat.Builder(clip, SOURCE_CLIPBOARD).setFlags(1 << 1);
+ try {
+ ContentInfoCompat payload = builder.build();
+ Assert.fail("Expected exception but got: " + payload);
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testBuilder_copy() throws Exception {
+ ClipData clip = ClipData.newPlainText("", "Hello");
+ ContentInfoCompat original = new ContentInfoCompat.Builder(clip, SOURCE_CLIPBOARD)
+ .setFlags(FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setLinkUri(Uri.parse("http://example.com"))
+ .setExtras(new Bundle())
+ .build();
+
+ // Verify that that calling the builder with a ContentInfoCompat instance creates a
+ // shallow copy.
+ ContentInfoCompat copy = new ContentInfoCompat.Builder(original).build();
+ assertThat(copy).isNotSameInstanceAs(original);
+ assertThat(copy.getClip()).isSameInstanceAs(original.getClip());
+ assertThat(copy.getSource()).isEqualTo(original.getSource());
+ assertThat(copy.getFlags()).isEqualTo(original.getFlags());
+ assertThat(copy.getLinkUri()).isSameInstanceAs(original.getLinkUri());
+ assertThat(copy.getExtras()).isSameInstanceAs(original.getExtras());
+ }
+
+ @Test
+ public void testBuilder_copyAndUpdate() throws Exception {
+ ClipData clip1 = ClipData.newPlainText("", "Hello");
+ ContentInfoCompat original = new ContentInfoCompat.Builder(clip1, SOURCE_CLIPBOARD)
+ .setFlags(FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setLinkUri(Uri.parse("http://example.com"))
+ .setExtras(new Bundle())
+ .build();
+
+ // Verify that calling setters after initializing the builder with a ContentInfoCompat
+ // instance updates the fields.
+ ClipData clip2 = ClipData.newPlainText("", "Bye");
+ ContentInfoCompat copy = new ContentInfoCompat.Builder(original)
+ .setClip(clip2)
+ .setSource(SOURCE_APP)
+ .setFlags(0)
+ .setLinkUri(null)
+ .setExtras(null)
+ .build();
+ assertThat(copy.getClip().getItemAt(0).getText()).isEqualTo("Bye");
+ assertThat(copy.getSource()).isEqualTo(SOURCE_APP);
+ assertThat(copy.getFlags()).isEqualTo(0);
+ assertThat(copy.getLinkUri()).isEqualTo(null);
+ assertThat(copy.getExtras()).isEqualTo(null);
+ }
+
+ @SdkSuppress(minSdkVersion = 31)
+ @Test
+ public void testBuilder_copyAndUpdate_platformContentInfo() throws Exception {
+ ClipData clip1 = ClipData.newPlainText("", "Hello");
+ ContentInfoCompat original = new ContentInfoCompat.Builder(clip1, SOURCE_CLIPBOARD)
+ .setFlags(FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setLinkUri(Uri.parse("http://example.com"))
+ .setExtras(new Bundle())
+ .build();
+
+ // Verify that calling setters after initializing the builder with a ContentInfoCompat
+ // instance updates the wrapped platform object also.
+ ClipData clip2 = ClipData.newPlainText("", "Bye");
+ ContentInfoCompat copy = new ContentInfoCompat.Builder(original)
+ .setClip(clip2)
+ .setSource(SOURCE_APP)
+ .setFlags(0)
+ .setLinkUri(null)
+ .setExtras(null)
+ .build();
+ ContentInfo platContentInfo = copy.toContentInfo();
+ assertThat(platContentInfo).isNotSameInstanceAs(original.toContentInfo());
+ assertThat(platContentInfo.getClip().getItemAt(0).getText()).isEqualTo("Bye");
+ assertThat(platContentInfo.getSource()).isEqualTo(SOURCE_APP);
+ assertThat(platContentInfo.getFlags()).isEqualTo(0);
+ assertThat(platContentInfo.getLinkUri()).isEqualTo(null);
+ assertThat(platContentInfo.getExtras()).isEqualTo(null);
+ }
+
+ @SdkSuppress(minSdkVersion = 31)
+ @Test
+ public void testCompatToPlatform() throws Exception {
+ ClipData clip = ClipData.newPlainText("", "Hello");
+ Bundle extras = new Bundle();
+ extras.putString("sampleExtrasKey", "sampleExtrasValue");
+ ContentInfoCompat contentInfo = new ContentInfoCompat.Builder(clip, SOURCE_CLIPBOARD)
+ .setFlags(FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setLinkUri(Uri.parse("http://example.com"))
+ .setExtras(extras)
+ .build();
+
+ // Verify that retrieving the platform object returns a shallow copy.
+ ContentInfo platContentInfo = contentInfo.toContentInfo();
+ assertThat(platContentInfo.getClip()).isSameInstanceAs(contentInfo.getClip());
+ assertThat(platContentInfo.getSource()).isEqualTo(contentInfo.getSource());
+ assertThat(platContentInfo.getFlags()).isEqualTo(contentInfo.getFlags());
+ assertThat(platContentInfo.getLinkUri()).isSameInstanceAs(contentInfo.getLinkUri());
+ assertThat(platContentInfo.getExtras()).isSameInstanceAs(contentInfo.getExtras());
+
+ // Verify that retrieving the platform object multiple times returns the same instance.
+ ContentInfo platContentInfo2 = contentInfo.toContentInfo();
+ assertThat(platContentInfo2).isSameInstanceAs(platContentInfo);
+ }
+
+ @SdkSuppress(minSdkVersion = 31)
+ @Test
+ public void testPlatformToCompat() throws Exception {
+ ClipData clip = ClipData.newPlainText("", "Hello");
+ Bundle extras = new Bundle();
+ extras.putString("sampleExtrasKey", "sampleExtrasValue");
+ ContentInfo platContentInfo = new ContentInfo.Builder(clip, ContentInfo.SOURCE_CLIPBOARD)
+ .setFlags(ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setLinkUri(Uri.parse("http://example.com"))
+ .setExtras(extras)
+ .build();
+
+ // Verify that converting to the compat object returns a shallow copy.
+ ContentInfoCompat contentInfo = ContentInfoCompat.toContentInfoCompat(platContentInfo);
+ assertThat(contentInfo.getClip()).isSameInstanceAs(platContentInfo.getClip());
+ assertThat(contentInfo.getSource()).isEqualTo(platContentInfo.getSource());
+ assertThat(contentInfo.getFlags()).isEqualTo(platContentInfo.getFlags());
+ assertThat(contentInfo.getLinkUri()).isSameInstanceAs(platContentInfo.getLinkUri());
+ assertThat(contentInfo.getExtras()).isSameInstanceAs(platContentInfo.getExtras());
+
+ // Verify that converting to the compat object multiple times returns a new instance each
+ // time.
+ ContentInfoCompat contentInfo2 = ContentInfoCompat.toContentInfoCompat(platContentInfo);
+ assertThat(contentInfo2).isNotSameInstanceAs(contentInfo);
+
+ // Verify that converting back from the compat object returns the original platform
+ // instance.
+ assertThat(contentInfo.toContentInfo()).isSameInstanceAs(platContentInfo);
+ assertThat(contentInfo2.toContentInfo()).isSameInstanceAs(platContentInfo);
+ }
+
+ @SdkSuppress(minSdkVersion = 31)
+ @Test
+ public void testPartitionPlatformContentInfo_multipleItems() throws Exception {
+ Uri sampleUri = Uri.parse("content://com.example/path");
+ ClipData clip = ClipData.newPlainText("", "Hello");
+ clip.addItem(new ClipData.Item("Hi", "<b>Salut</b>"));
+ clip.addItem(new ClipData.Item(sampleUri));
+ ContentInfo payload = new ContentInfo.Builder(clip, ContentInfo.SOURCE_CLIPBOARD)
+ .setFlags(ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setLinkUri(Uri.parse("http://example.com"))
+ .setExtras(new Bundle())
+ .build();
+
+ // Test splitting when some items match and some don't.
+ Pair<ContentInfo, ContentInfo> split;
+ split = ContentInfoCompat.partition(payload,
+ new java.util.function.Predicate<ClipData.Item>() {
+ @Override
+ public boolean test(ClipData.Item item) {
+ return item.getUri() != null;
+ }
+ });
+ assertThat(split.first.getClip().getItemCount()).isEqualTo(1);
+ assertThat(split.second.getClip().getItemCount()).isEqualTo(2);
+ assertThat(split.first.getClip().getItemAt(0).getUri()).isEqualTo(sampleUri);
+ assertThat(split.first.getClip().getDescription()).isNotSameInstanceAs(
+ payload.getClip().getDescription());
+ assertThat(split.second.getClip().getDescription()).isNotSameInstanceAs(
+ payload.getClip().getDescription());
+ assertThat(split.first.getSource()).isEqualTo(ContentInfo.SOURCE_CLIPBOARD);
+ assertThat(split.first.getLinkUri()).isNotNull();
+ assertThat(split.first.getExtras()).isNotNull();
+ assertThat(split.second.getSource()).isEqualTo(ContentInfo.SOURCE_CLIPBOARD);
+ assertThat(split.second.getLinkUri()).isNotNull();
+ assertThat(split.second.getExtras()).isNotNull();
+
+ // Test splitting when none of the items match.
+ split = ContentInfoCompat.partition(payload,
+ new java.util.function.Predicate<ClipData.Item>() {
+ @Override
+ public boolean test(ClipData.Item item) {
+ return false;
+ }
+ });
+ assertThat(split.first).isNull();
+ assertThat(split.second).isSameInstanceAs(payload);
+
+ // Test splitting when all of the items match.
+ split = ContentInfoCompat.partition(payload,
+ new java.util.function.Predicate<ClipData.Item>() {
+ @Override
+ public boolean test(ClipData.Item item) {
+ return true;
+ }
+ });
+ assertThat(split.first).isSameInstanceAs(payload);
+ assertThat(split.second).isNull();
+ }
+
+ @SdkSuppress(minSdkVersion = 31)
+ @Test
+ public void testPartitionPlatformContentInfo_singleItem() throws Exception {
+ ClipData clip = ClipData.newPlainText("", "Hello");
+ ContentInfo payload = new ContentInfo.Builder(clip, ContentInfo.SOURCE_CLIPBOARD)
+ .setFlags(ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT)
+ .setLinkUri(Uri.parse("http://example.com"))
+ .setExtras(new Bundle())
+ .build();
+
+ Pair<ContentInfo, ContentInfo> split;
+ split = ContentInfoCompat.partition(payload,
+ new java.util.function.Predicate<ClipData.Item>() {
+ @Override
+ public boolean test(ClipData.Item item) {
+ return false;
+ }
+ });
+ assertThat(split.first).isNull();
+ assertThat(split.second).isSameInstanceAs(payload);
+
+ split = ContentInfoCompat.partition(payload,
+ new java.util.function.Predicate<ClipData.Item>() {
+ @Override
+ public boolean test(ClipData.Item item) {
+ return true;
+ }
+ });
+ assertThat(split.first).isSameInstanceAs(payload);
+ assertThat(split.second).isNull();
+ }
}
diff --git a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt
index 8ce528b..58611ce 100644
--- a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt
+++ b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt
@@ -198,6 +198,35 @@
assertThat(windowInsetsController.isAppearanceLightStatusBars(), `is`(true))
}
+ /**
+ * Tests that after calling setAppearanceLightStatusBars in API 30
+ * isAppearanceLightStatusBars is true and SYSTEM_UI_FLAG_LIGHT_STATUS_BAR flag is unset.
+ *
+ * Currently this works only with Impl30(Window window, WindowInsetsControllerCompat
+ * compatController) constructor (b/180881870).
+ */
+ @SdkSuppress(minSdkVersion = 30, maxSdkVersion = 30)
+ @Test
+ public fun systemBar_light_theme() {
+ val decorView = scenario.withActivity { window.decorView }
+
+ scenario.onActivity { activity ->
+ windowInsetsController = WindowInsetsControllerCompat(
+ activity.window, activity.findViewById(R.id.container)
+ )
+
+ decorView.systemUiVisibility = decorView.systemUiVisibility or
+ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ windowInsetsController.setAppearanceLightStatusBars(true)
+ }
+
+ assertThat(
+ decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+ equalTo(0)
+ )
+ assertThat(windowInsetsController.isAppearanceLightStatusBars(), `is`(true))
+ }
+
@SdkSuppress(minSdkVersion = 26)
@Test
public fun navigationBar_light() {
diff --git a/core/core/src/androidTest/java/androidx/core/widget/EdgeEffectCompatTest.java b/core/core/src/androidTest/java/androidx/core/widget/EdgeEffectCompatTest.java
new file mode 100644
index 0000000..c4a7136
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/widget/EdgeEffectCompatTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.v4.BaseTestActivity;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.EdgeEffect;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.test.R;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EdgeEffectCompatTest extends
+ BaseInstrumentationTestCase<EdgeEffectCompatTest.EdgeEffectCompatTestActivity> {
+ private ViewWithEdgeEffect mView;
+ private EdgeEffect mEdgeEffect;
+
+ public EdgeEffectCompatTest() {
+ super(EdgeEffectCompatTestActivity.class);
+ }
+
+ @Before
+ public void setUp() {
+ Activity activity = mActivityTestRule.getActivity();
+ mView = activity.findViewById(R.id.edgeEffectView);
+ mEdgeEffect = mView.mEdgeEffect;
+ }
+
+ // TODO(b/181171227): Change to R
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ public void distanceApi30() {
+ assertEquals(0, EdgeEffectCompat.getDistance(mEdgeEffect), 0f);
+ assertEquals(1f, EdgeEffectCompat.onPullDistance(mEdgeEffect, 1, 0.5f), 0f);
+ assertEquals(0, EdgeEffectCompat.getDistance(mEdgeEffect), 0f);
+ }
+
+ // TODO(b/181171227): Change to S
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
+ @Test
+ public void distanceApi31() {
+ // TODO(b/181171227): Remove this condition
+ if (isSOrHigher()) {
+ assertEquals(0, EdgeEffectCompat.getDistance(mEdgeEffect), 0f);
+ assertEquals(1f, EdgeEffectCompat.onPullDistance(mEdgeEffect, 1, 0.5f), 0f);
+ assertEquals(1, EdgeEffectCompat.getDistance(mEdgeEffect), 0f);
+ assertEquals(-1f, EdgeEffectCompat.onPullDistance(mEdgeEffect, -1.5f, 0.5f), 0f);
+ assertEquals(0, EdgeEffectCompat.getDistance(mEdgeEffect), 0f);
+ } else {
+ distanceApi30();
+ }
+ }
+
+ // TODO(b/181171227): Remove this.
+ private static boolean isSOrHigher() {
+ int sdk = Build.VERSION.SDK_INT;
+ return sdk > Build.VERSION_CODES.R
+ || (sdk == Build.VERSION_CODES.R && Build.VERSION.PREVIEW_SDK_INT != 0);
+ }
+
+ public static class EdgeEffectCompatTestActivity extends BaseTestActivity {
+ @Override
+ protected int getContentViewLayoutResId() {
+ return R.layout.edge_effect_compat;
+ }
+ }
+
+ public static class ViewWithEdgeEffect extends View {
+ public EdgeEffect mEdgeEffect;
+
+ public ViewWithEdgeEffect(Context context) {
+ super(context);
+ initEdgeEffect(context, null);
+ }
+
+ public ViewWithEdgeEffect(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initEdgeEffect(context, attrs);
+ }
+
+ public ViewWithEdgeEffect(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initEdgeEffect(context, attrs);
+ }
+
+ @RequiresApi(21)
+ @SuppressWarnings("unused")
+ public ViewWithEdgeEffect(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ initEdgeEffect(context, attrs);
+ }
+
+ private void initEdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs) {
+ mEdgeEffect = EdgeEffectCompat.create(context, attrs);
+ }
+ }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewNestedScrollingChildTest.java b/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewNestedScrollingChildTest.java
index 1391695..d01a587 100644
--- a/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewNestedScrollingChildTest.java
+++ b/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewNestedScrollingChildTest.java
@@ -83,6 +83,7 @@
mNestedScrollView = new NestedScrollView(ApplicationProvider.getApplicationContext());
mNestedScrollView.setMinimumWidth(1000);
mNestedScrollView.setMinimumHeight(1000);
+ mNestedScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
mParentSpy = Mockito.spy(
new NestedScrollingSpyView(ApplicationProvider.getApplicationContext()));
diff --git a/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewTest.java b/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewTest.java
index a6b9e414..90d984a 100644
--- a/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewTest.java
+++ b/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewTest.java
@@ -18,14 +18,20 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.os.Parcelable;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
+import android.widget.EdgeEffect;
+import androidx.core.os.BuildCompat;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -303,6 +309,127 @@
assertThat(mNestedScrollView.getScrollY(), is(100));
}
+ @Test
+ public void testTopEdgeEffectReversal() {
+ setup(200);
+ setChildMargins(0, 0);
+ measureAndLayout(100);
+ swipeDown(false);
+ assertEquals(0, mNestedScrollView.getScrollY());
+ swipeUp(true);
+ if (BuildCompat.isAtLeastS()) {
+ // This should just reverse the overscroll effect
+ assertEquals(0, mNestedScrollView.getScrollY());
+ } else {
+ // Can't catch the overscroll effect for R and earlier
+ assertNotEquals(0, mNestedScrollView.getScrollY());
+ }
+ }
+
+ @Test
+ public void testBottomEdgeEffectReversal() {
+ setup(200);
+ setChildMargins(0, 0);
+ measureAndLayout(100);
+ int scrollRange = mNestedScrollView.getScrollRange();
+ mNestedScrollView.scrollTo(0, scrollRange);
+ assertEquals(scrollRange, mNestedScrollView.getScrollY());
+ swipeUp(false);
+ assertEquals(scrollRange, mNestedScrollView.getScrollY());
+ swipeDown(true);
+ if (BuildCompat.isAtLeastS()) {
+ // This should just reverse the overscroll effect
+ assertEquals(scrollRange, mNestedScrollView.getScrollY());
+ } else {
+ // Can't catch the overscroll effect for R and earlier
+ assertNotEquals(scrollRange, mNestedScrollView.getScrollY());
+ }
+ }
+
+ @Test
+ public void testFlingWhileStretchedAtTop() {
+ setup(200);
+ setChildMargins(0, 0);
+ measureAndLayout(100);
+ CaptureOnAbsorbEdgeEffect edgeEffect =
+ new CaptureOnAbsorbEdgeEffect(mNestedScrollView.getContext());
+ mNestedScrollView.mEdgeGlowTop = edgeEffect;
+ flingDown();
+ assertTrue(edgeEffect.pullDistance > 0);
+
+ if (BuildCompat.isAtLeastS()) {
+ assertTrue(edgeEffect.absorbVelocity > 0);
+ } else {
+ assertEquals(0, edgeEffect.absorbVelocity);
+ flingUp();
+ assertNotEquals(0, mNestedScrollView.getScrollY());
+ }
+ }
+
+ @Test
+ public void testFlingWhileStretchedAtBottom() {
+ setup(200);
+ setChildMargins(0, 0);
+ measureAndLayout(100);
+ CaptureOnAbsorbEdgeEffect edgeEffect =
+ new CaptureOnAbsorbEdgeEffect(mNestedScrollView.getContext());
+ mNestedScrollView.mEdgeGlowBottom = edgeEffect;
+
+ int scrollRange = mNestedScrollView.getScrollRange();
+ mNestedScrollView.scrollTo(0, scrollRange);
+ assertEquals(scrollRange, mNestedScrollView.getScrollY());
+ flingUp();
+ assertTrue(edgeEffect.pullDistance > 0);
+ assertEquals(scrollRange, mNestedScrollView.getScrollY());
+
+ if (BuildCompat.isAtLeastS()) {
+ assertTrue(edgeEffect.absorbVelocity > 0);
+ } else {
+ assertEquals(0, edgeEffect.absorbVelocity);
+ flingDown();
+ assertNotEquals(scrollRange, mNestedScrollView.getScrollY());
+ }
+ }
+
+ private void swipeDown(boolean shortSwipe) {
+ float endY = shortSwipe ? mNestedScrollView.getHeight() / 2f :
+ mNestedScrollView.getHeight() - 1;
+ swipe(0, endY);
+ }
+
+ private void swipeUp(boolean shortSwipe) {
+ float endY = shortSwipe ? mNestedScrollView.getHeight() / 2f : 0;
+ swipe(mNestedScrollView.getHeight() - 1, endY);
+ }
+
+ private void swipe(float startY, float endY) {
+ float x = mNestedScrollView.getWidth() / 2f;
+ MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, x, startY, 0);
+ mNestedScrollView.dispatchTouchEvent(down);
+ MotionEvent move = MotionEvent.obtain(0, 10, MotionEvent.ACTION_MOVE, x, endY, 0);
+ mNestedScrollView.dispatchTouchEvent(move);
+ MotionEvent up = MotionEvent.obtain(0, 1000, MotionEvent.ACTION_UP, x, endY, 0);
+ mNestedScrollView.dispatchTouchEvent(up);
+ }
+
+ private void flingDown() {
+ fling(0, mNestedScrollView.getHeight() - 1);
+ }
+
+ private void flingUp() {
+ fling(mNestedScrollView.getHeight() - 1, 0);
+ }
+
+ private void fling(float startY, float endY) {
+ float x = mNestedScrollView.getWidth() / 2f;
+ MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, x, startY, 0);
+ mNestedScrollView.dispatchTouchEvent(down);
+ MotionEvent move = MotionEvent.obtain(0, 10, MotionEvent.ACTION_MOVE, x, endY, 0);
+ mNestedScrollView.dispatchTouchEvent(move);
+ MotionEvent up = MotionEvent.obtain(0, 11, MotionEvent.ACTION_UP, x, endY, 0);
+ mNestedScrollView.dispatchTouchEvent(up);
+ }
+
private void setup(int childHeight) {
Context context = ApplicationProvider.getApplicationContext();
@@ -339,4 +466,36 @@
measure(height);
mNestedScrollView.layout(0, 0, 100, height);
}
+
+ private static class CaptureOnAbsorbEdgeEffect extends EdgeEffect {
+ public int absorbVelocity;
+ public float pullDistance;
+
+ CaptureOnAbsorbEdgeEffect(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onPull(float deltaDistance) {
+ pullDistance += deltaDistance;
+ super.onPull(deltaDistance);
+ }
+
+ @Override
+ public void onPull(float deltaDistance, float displacement) {
+ pullDistance += deltaDistance;
+ super.onPull(deltaDistance, displacement);
+ }
+
+ @Override
+ public void onAbsorb(int velocity) {
+ absorbVelocity = velocity;
+ super.onAbsorb(velocity);
+ }
+
+ @Override
+ public void onRelease() {
+ super.onRelease();
+ }
+ }
}
diff --git a/core/core/src/androidTest/res/color/color_state_list_android_lstar.xml b/core/core/src/androidTest/res/color/color_state_list_android_lstar.xml
new file mode 100644
index 0000000..541d0de
--- /dev/null
+++ b/core/core/src/androidTest/res/color/color_state_list_android_lstar.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.5" android:color="#FFA6C839" android:lStar="50" />
+</selector>
\ No newline at end of file
diff --git a/core/core/src/androidTest/res/color/color_state_list_lstar.xml b/core/core/src/androidTest/res/color/color_state_list_lstar.xml
new file mode 100644
index 0000000..f9de313
--- /dev/null
+++ b/core/core/src/androidTest/res/color/color_state_list_lstar.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item android:alpha="0.5" android:color="#FFA6C839" app:lStar="50" />
+</selector>
\ No newline at end of file
diff --git a/core/core/src/androidTest/res/layout/edge_effect_compat.xml b/core/core/src/androidTest/res/layout/edge_effect_compat.xml
new file mode 100644
index 0000000..fda0658
--- /dev/null
+++ b/core/core/src/androidTest/res/layout/edge_effect_compat.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<view
+ class="androidx.core.widget.EdgeEffectCompatTest$ViewWithEdgeEffect"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/edgeEffectView"
+ android:layout_width="100px"
+ android:layout_height="100px" />
\ No newline at end of file
diff --git a/core/core/src/androidTest/res/layout/nested_scroll_view_stretch.xml b/core/core/src/androidTest/res/layout/nested_scroll_view_stretch.xml
new file mode 100644
index 0000000..c18e4ad
--- /dev/null
+++ b/core/core/src/androidTest/res/layout/nested_scroll_view_stretch.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<androidx.core.widget.NestedScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/nestedScrollView"
+ android:layout_width="100px"
+ android:layout_height="100px" />
\ No newline at end of file
diff --git a/core/core/src/main/java/androidx/core/app/ActivityCompat.java b/core/core/src/main/java/androidx/core/app/ActivityCompat.java
index 5a05109..945b9d2 100644
--- a/core/core/src/main/java/androidx/core/app/ActivityCompat.java
+++ b/core/core/src/main/java/androidx/core/app/ActivityCompat.java
@@ -30,6 +30,7 @@
import android.os.Looper;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.view.Display;
import android.view.DragEvent;
import android.view.View;
@@ -41,6 +42,7 @@
import androidx.annotation.RestrictTo;
import androidx.core.content.ContextCompat;
import androidx.core.content.LocusIdCompat;
+import androidx.core.os.BuildCompat;
import androidx.core.view.DragAndDropPermissionsCompat;
import java.util.Arrays;
@@ -556,6 +558,42 @@
}
/**
+ * Indicates whether this activity is launched from a bubble. A bubble is a floating shortcut
+ * on the screen that expands to show an activity.
+ *
+ * If your activity can be used normally or as a bubble, you might use this method to check
+ * if the activity is bubbled to modify any behaviour that might be different between the
+ * normal activity and the bubbled activity. For example, if you normally cancel the
+ * notification associated with the activity when you open the activity, you might not want to
+ * do that when you're bubbled as that would remove the bubble.
+ *
+ * @return {@code true} if the activity is launched from a bubble.
+ *
+ * @see NotificationCompat.Builder#setBubbleMetadata(NotificationCompat.BubbleMetadata)
+ * @see NotificationCompat.BubbleMetadata.Builder#Builder(String)
+ *
+ * Compatibility behavior:
+ * <ul>
+ * <li>API 31 and above, this method matches platform behavior</li>
+ * <li>API 29, 30, this method checks the window display ID</li>
+ * <li>API 28 and earlier, this method is a no-op</li>
+ * </ul>
+ */
+ public static boolean isLaunchedFromBubble(@NonNull Activity activity) {
+ if (BuildCompat.isAtLeastS()) {
+ return Api31Impl.isLaunchedFromBubble(activity);
+ } else if (Build.VERSION.SDK_INT == 30) {
+ return activity.getDisplay() != null
+ && activity.getDisplay().getDisplayId() != Display.DEFAULT_DISPLAY;
+ } else if (Build.VERSION.SDK_INT == 29) {
+ return activity.getWindowManager().getDefaultDisplay() != null
+ && activity.getWindowManager().getDefaultDisplay().getDisplayId()
+ != Display.DEFAULT_DISPLAY;
+ }
+ return false;
+ }
+
+ /**
* Create {@link DragAndDropPermissionsCompat} object bound to this activity and controlling
* the access permissions for content URIs associated with the {@link android.view.DragEvent}.
* @param dragEvent Drag event to request permission for
@@ -715,4 +753,19 @@
activity.setLocusContext(locusId == null ? null : locusId.toLocusId(), bundle);
}
}
+
+ @RequiresApi(31)
+ static class Api31Impl {
+
+ /**
+ * This class should not be instantiated.
+ */
+ private Api31Impl() {
+ // Not intended for instantiation.
+ }
+
+ static boolean isLaunchedFromBubble(@NonNull final Activity activity) {
+ return activity.isLaunchedFromBubble();
+ }
+ }
}
diff --git a/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java b/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
index 9ca7d09..c8b4123 100644
--- a/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
@@ -16,6 +16,7 @@
package androidx.core.app;
+import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.os.Build;
@@ -54,6 +55,7 @@
* @see android.content.Context#registerReceiver
* @see android.content.Intent#filterEquals
*/
+ @SuppressLint("MissingPermission")
public static void setAlarmClock(@NonNull AlarmManager alarmManager, long triggerTime,
@NonNull PendingIntent showIntent, @NonNull PendingIntent operation) {
if (Build.VERSION.SDK_INT >= 21) {
diff --git a/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java b/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java
index 689d943..41e5fc8 100644
--- a/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java
@@ -20,9 +20,12 @@
import android.app.AppOpsManager;
import android.content.Context;
+import android.os.Binder;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
/**
* Helper for accessing features in {@link android.app.AppOpsManager}.
@@ -179,4 +182,76 @@
return MODE_IGNORED;
}
}
+
+ /**
+ * Check op for both proxy and proxied packages. Do a quick check for whether an application
+ * might be able to perform an operation. This is not a security check.
+ * On API 23-28, fallback to {@link #noteProxyOpNoThrow(Context, String, String)}
+ * On API 22 and lower, this method always returns {@link #MODE_IGNORED}
+ * @param context Your context.
+ * @param proxyUid The uid of the proxy application.
+ * @param op The operation to note. One of the OPSTR_* constants.
+ * @param proxiedPackageName The name of the application calling into the proxy application.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * @link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ */
+ public static int checkOrNoteProxyOp(@NonNull Context context, int proxyUid,
+ @NonNull String op, @NonNull String proxiedPackageName) {
+ if (SDK_INT >= 29) {
+ AppOpsManager appOpsManager = Api29Impl.getSystemService(context);
+ // Check proxied op
+ int proxiedUid = Binder.getCallingUid();
+ int checkProxiedOpResult = Api29Impl.checkOpNoThrow(appOpsManager, op, proxiedUid,
+ proxiedPackageName);
+ if (checkProxiedOpResult != MODE_ALLOWED) {
+ return checkProxiedOpResult;
+ }
+
+ // Check proxy op
+ String proxyPackageName = Api29Impl.getOpPackageName(context);
+ return Api29Impl.checkOpNoThrow(appOpsManager, op, proxyUid, proxyPackageName);
+ } else {
+ // For API level 23-28 we want to fallback to noteProxyOpNoThrow()
+ return noteProxyOpNoThrow(context, op, proxiedPackageName);
+ }
+ }
+
+ /**
+ * Nested class to avoid verification errors for methods introduced in Android 10 (API 29).
+ */
+ @RequiresApi(29)
+ static class Api29Impl {
+ private Api29Impl() {
+ }
+
+ /**
+ * Return the AppOpsManager system service.
+ */
+ @DoNotInline
+ static @Nullable AppOpsManager getSystemService(@NonNull Context context) {
+ return context.getSystemService(AppOpsManager.class);
+ }
+
+ /**
+ * Use the AppOpsManager to perform checkOp().
+ */
+ @DoNotInline
+ static int checkOpNoThrow(@Nullable AppOpsManager appOpsManager,
+ @NonNull String op, int uid, @NonNull String packageName) {
+ if (appOpsManager == null) {
+ return MODE_IGNORED;
+ }
+
+ return appOpsManager.checkOpNoThrow(op, uid, packageName);
+ }
+
+ /**
+ * Return the packageName from the context.
+ */
+ @DoNotInline
+ static @NonNull String getOpPackageName(@NonNull Context context) {
+ return context.getOpPackageName();
+ }
+ }
}
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index 5873f9b..584f2a2 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -795,6 +795,56 @@
*/
public static final String GROUP_KEY_SILENT = "silent";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @RestrictTo(LIBRARY_GROUP_PREFIX)
+ @IntDef({FOREGROUND_SERVICE_DEFAULT,
+ FOREGROUND_SERVICE_IMMEDIATE,
+ FOREGROUND_SERVICE_DEFERRED})
+ public @interface ServiceNotificationBehavior {}
+
+ /**
+ * Constant for {@link Builder#setForegroundServiceBehavior(int)}. In Android 12 or later,
+ * if the Notification associated with starting a foreground service has been
+ * built using setForegroundServiceBehavior() with this behavior, display of
+ * the notification will often be suppressed for a short time to avoid visual
+ * disturbances to the user.
+ *
+ * @see NotificationCompat.Builder#setForegroundServiceBehavior(int)
+ * @see #FOREGROUND_SERVICE_IMMEDIATE
+ * @see #FOREGROUND_SERVICE_DEFERRED
+ */
+ public static final int FOREGROUND_SERVICE_DEFAULT =
+ Notification.FOREGROUND_SERVICE_DEFAULT;
+
+ /**
+ * Constant for {@link Builder#setForegroundServiceBehavior(int)}. In Android 12 or later,
+ * if the Notification associated with starting a foreground service has been
+ * built using setForegroundServiceBehavior() with this behavior, display of
+ * the notification will be immediate even if the default behavior would be
+ * to defer visibility for a short time.
+ *
+ * @see NotificationCompat.Builder#setForegroundServiceBehavior(int)
+ * @see #FOREGROUND_SERVICE_DEFAULT
+ * @see #FOREGROUND_SERVICE_DEFERRED
+ */
+ public static final int FOREGROUND_SERVICE_IMMEDIATE =
+ Notification.FOREGROUND_SERVICE_IMMEDIATE;
+
+ /**
+ * Constant for {@link Builder#setForegroundServiceBehavior(int)}. In Android 12 or later,
+ * if the Notification associated with starting a foreground service has been
+ * built using setForegroundServiceBehavior() with this behavior, display of
+ * the notification will usually be suppressed for a short time to avoid visual
+ * disturbances to the user.
+ *
+ * @see NotificationCompat.Builder#setForegroundServiceBehavior(int)
+ * @see #FOREGROUND_SERVICE_DEFAULT
+ * @see #FOREGROUND_SERVICE_IMMEDIATE
+ */
+ public static final int FOREGROUND_SERVICE_DEFERRED =
+ Notification.FOREGROUND_SERVICE_DEFERRED;
+
/**
* Builder class for {@link NotificationCompat} objects. Allows easier control over
* all the flags, as well as help constructing the typical notification layouts.
@@ -884,6 +934,7 @@
LocusIdCompat mLocusId;
long mTimeout;
@GroupAlertBehavior int mGroupAlertBehavior = GROUP_ALERT_ALL;
+ @ServiceNotificationBehavior int mFgsDeferBehavior = FOREGROUND_SERVICE_DEFAULT;
boolean mAllowSystemGeneratedContextualActions;
BubbleMetadata mBubbleMetadata;
Notification mNotification = new Notification();
@@ -2295,6 +2346,31 @@
}
/**
+ * Specify a desired visibility policy for a Notification associated with a
+ * foreground service. The default value is {@link #FOREGROUND_SERVICE_DEFAULT},
+ * meaning the system can choose to defer visibility of the notification for
+ * a short time after the service is started. Pass
+ * {@link NotificationCompat#FOREGROUND_SERVICE_IMMEDIATE FOREGROUND_SERVICE_IMMEDIATE}
+ * to this method in order to guarantee that visibility is never deferred. Pass
+ * {@link NotificationCompat#FOREGROUND_SERVICE_DEFERRED FOREGROUND_SERVICE_DEFERRED}
+ * to request that visibility is deferred whenever possible.
+ *
+ * <p class="note">Note that deferred visibility is not guaranteed. There
+ * may be some circumstances under which the system will show the foreground
+ * service's associated Notification immediately even when the app has used
+ * this method to explicitly request deferred display.</p>
+ *
+ * This method has no effect when running on versions prior to
+ * {@link android.os.Build.VERSION_CODES#S}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // no underlying getter in platform API
+ @NonNull
+ public Builder setForegroundServiceBehavior(@ServiceNotificationBehavior int behavior) {
+ mFgsDeferBehavior = behavior;
+ return this;
+ }
+
+ /**
* Sets the {@link BubbleMetadata} that will be used to display app content in a floating
* window over the existing foreground activity.
*
@@ -2397,6 +2473,16 @@
}
/**
+ * @return the foreground service behavior defined for the notification
+ *
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP_PREFIX)
+ public int getForegroundServiceBehavior() {
+ return mFgsDeferBehavior;
+ }
+
+ /**
* @return the color of the notification
*
* @hide
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java b/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
index 00b1660..827b9bf 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
@@ -36,6 +36,7 @@
import androidx.annotation.RestrictTo;
import androidx.collection.ArraySet;
import androidx.core.graphics.drawable.IconCompat;
+import androidx.core.os.BuildCompat;
import java.util.ArrayList;
import java.util.List;
@@ -247,6 +248,11 @@
mBuilder.setLocusId(b.mLocusId.toLocusId());
}
}
+ if (BuildCompat.isAtLeastS()) {
+ if (b.mFgsDeferBehavior != NotificationCompat.FOREGROUND_SERVICE_DEFAULT) {
+ mBuilder.setForegroundServiceBehavior(b.mFgsDeferBehavior);
+ }
+ }
if (b.mSilent) {
if (mBuilderCompat.mGroupSummary) {
diff --git a/core/core/src/main/java/androidx/core/content/PackageManagerCompat.java b/core/core/src/main/java/androidx/core/content/PackageManagerCompat.java
index e0ffa4b..71f119c 100644
--- a/core/core/src/main/java/androidx/core/content/PackageManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/content/PackageManagerCompat.java
@@ -170,11 +170,11 @@
UnusedAppRestrictionsBackportServiceConnection backportServiceConnection =
new UnusedAppRestrictionsBackportServiceConnection(context);
- resultFuture.addListener(() -> {
- // Keep the connection object alive until the async operation completes, and then
- // disconnect it.
- backportServiceConnection.disconnectFromService();
- }, Executors.newSingleThreadExecutor());
+ // Keep the connection object alive until the async operation completes, and then
+ // disconnect it.
+ resultFuture.addListener(
+ backportServiceConnection::disconnectFromService,
+ Executors.newSingleThreadExecutor());
// Start binding the service and fetch the result
backportServiceConnection.connectAndFetchResult(resultFuture);
diff --git a/core/core/src/main/java/androidx/core/content/PermissionChecker.java b/core/core/src/main/java/androidx/core/content/PermissionChecker.java
index 20697c7..fad8c62 100644
--- a/core/core/src/main/java/androidx/core/content/PermissionChecker.java
+++ b/core/core/src/main/java/androidx/core/content/PermissionChecker.java
@@ -28,6 +28,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.core.app.AppOpsManagerCompat;
+import androidx.core.util.ObjectsCompat;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -111,12 +112,20 @@
packageName = packageNames[0];
}
- if (AppOpsManagerCompat.noteProxyOpNoThrow(context, op, packageName)
- != AppOpsManagerCompat.MODE_ALLOWED) {
- return PERMISSION_DENIED_APP_OP;
+ int proxyUid = android.os.Process.myUid();
+ String proxyPackageName = context.getPackageName();
+ boolean isCheckSelfPermission =
+ proxyUid == uid && ObjectsCompat.equals(proxyPackageName, packageName);
+
+ int checkOpResult;
+ if (isCheckSelfPermission) {
+ checkOpResult = AppOpsManagerCompat.checkOrNoteProxyOp(context, uid, op, packageName);
+ } else {
+ checkOpResult = AppOpsManagerCompat.noteProxyOpNoThrow(context, op, packageName);
}
- return PERMISSION_GRANTED;
+ return checkOpResult == AppOpsManagerCompat.MODE_ALLOWED ? PERMISSION_GRANTED :
+ PERMISSION_DENIED_APP_OP;
}
/**
diff --git a/core/core/src/main/java/androidx/core/content/res/CamColor.java b/core/core/src/main/java/androidx/core/content/res/CamColor.java
new file mode 100644
index 0000000..ed7758f
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/content/res/CamColor.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.content.res;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.FloatRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.ColorUtils;
+
+/**
+ * A color appearance model, based on CAM16, extended to use L* as the lightness dimension, and
+ * coupled to a gamut mapping algorithm. Creates a color system, enables a digital design system.
+ */
+class CamColor {
+ // The maximum difference between the requested L* and the L* returned.
+ private static final float DL_MAX = 0.2f;
+ // The maximum color distance, in CAM16-UCS, between a requested color and the color returned.
+ private static final float DE_MAX = 1.0f;
+ // When the delta between the floor & ceiling of a binary search for chroma is less than this,
+ // the binary search terminates.
+ private static final float CHROMA_SEARCH_ENDPOINT = 0.4f;
+ // When the delta between the floor & ceiling of a binary search for J, lightness in CAM16,
+ // is less than this, the binary search terminates.
+ private static final float LIGHTNESS_SEARCH_ENDPOINT = 0.01f;
+
+ // CAM16 color dimensions, see getters for documentation.
+ private final float mHue;
+ private final float mChroma;
+ private final float mJ;
+ private final float mQ;
+ private final float mM;
+ private final float mS;
+
+ // Coordinates in UCS space. Used to determine color distance, like delta E equations in L*a*b*.
+ private final float mJstar;
+ private final float mAstar;
+ private final float mBstar;
+
+ /** Hue in CAM16 */
+ @FloatRange(from = 0.0, to = 360.0, toInclusive = false)
+ float getHue() {
+ return mHue;
+ }
+
+ /** Chroma in CAM16 */
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float getChroma() {
+ return mChroma;
+ }
+
+ /** Lightness in CAM16 */
+ @FloatRange(from = 0.0, to = 100.0)
+ float getJ() {
+ return mJ;
+ }
+
+ /**
+ * Brightness in CAM16.
+ *
+ * <p>Prefer lightness, brightness is an absolute quantity. For example, a sheet of white paper
+ * is much brighter viewed in sunlight than in indoor light, but it is the lightest object under
+ * any lighting.
+ */
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float getQ() {
+ return mQ;
+ }
+
+ /**
+ * Colorfulness in CAM16.
+ *
+ * <p>Prefer chroma, colorfulness is an absolute quantity. For example, a yellow toy car is much
+ * more colorful outside than inside, but it has the same chroma in both environments.
+ */
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float getM() {
+ return mM;
+ }
+
+ /**
+ * Saturation in CAM16.
+ *
+ * <p>Colorfulness in proportion to brightness. Prefer chroma, saturation measures colorfulness
+ * relative to the color's own brightness, where chroma is colorfulness relative to white.
+ */
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float getS() {
+ return mS;
+ }
+
+ /** Lightness coordinate in CAM16-UCS */
+ @FloatRange(from = 0.0, to = 100.0)
+ float getJStar() {
+ return mJstar;
+ }
+
+ /** a* coordinate in CAM16-UCS */
+ @FloatRange(from = Double.NEGATIVE_INFINITY, to = Double.POSITIVE_INFINITY, fromInclusive =
+ false, toInclusive = false)
+ float getAStar() {
+ return mAstar;
+ }
+
+ /** b* coordinate in CAM16-UCS */
+ @FloatRange(from = Double.NEGATIVE_INFINITY, to = Double.POSITIVE_INFINITY, fromInclusive =
+ false, toInclusive = false)
+ float getBStar() {
+ return mBstar;
+ }
+
+ /** Construct a CAM16 color */
+ CamColor(float hue, float chroma, float j, float q, float m, float s, float jStar, float aStar,
+ float bStar) {
+ mHue = hue;
+ mChroma = chroma;
+ mJ = j;
+ mQ = q;
+ mM = m;
+ mS = s;
+ mJstar = jStar;
+ mAstar = aStar;
+ mBstar = bStar;
+ }
+
+ /**
+ * Given a hue & chroma in CAM16, L* in L*a*b*, return an ARGB integer. The chroma of the color
+ * returned may, and frequently will, be lower than requested. Assumes the color is viewed in
+ * the default ViewingConditions.
+ */
+ static int toColor(@FloatRange(from = 0.0, to = 360.0) float hue,
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float chroma,
+ @FloatRange(from = 0.0, to = 100.0) float lStar) {
+ return toColor(hue, chroma, lStar, ViewingConditions.DEFAULT);
+ }
+
+ /**
+ * Create a color appearance model from a ARGB integer representing a color. It is assumed the
+ * color was viewed in the default ViewingConditions.
+ *
+ * The alpha component is ignored, CamColor only represents opaque colors.
+ */
+ @NonNull
+ static CamColor fromColor(@ColorInt int color) {
+ return fromColorInViewingConditions(color, ViewingConditions.DEFAULT);
+ }
+
+ /**
+ * Create a color appearance model from a ARGB integer representing a color, specifying the
+ * ViewingConditions in which the color was viewed. Prefer Cam.fromColor.
+ */
+ @NonNull
+ static CamColor fromColorInViewingConditions(@ColorInt int color,
+ @NonNull ViewingConditions viewingConditions) {
+ // Transform ARGB int to XYZ
+ float[] xyz = CamUtils.xyzFromInt(color);
+
+ // Transform XYZ to 'cone'/'rgb' responses
+ float[][] matrix = CamUtils.XYZ_TO_CAM16RGB;
+ float rT = (xyz[0] * matrix[0][0]) + (xyz[1] * matrix[0][1]) + (xyz[2] * matrix[0][2]);
+ float gT = (xyz[0] * matrix[1][0]) + (xyz[1] * matrix[1][1]) + (xyz[2] * matrix[1][2]);
+ float bT = (xyz[0] * matrix[2][0]) + (xyz[1] * matrix[2][1]) + (xyz[2] * matrix[2][2]);
+
+ // Discount illuminant
+ float rD = viewingConditions.getRgbD()[0] * rT;
+ float gD = viewingConditions.getRgbD()[1] * gT;
+ float bD = viewingConditions.getRgbD()[2] * bT;
+
+ // Chromatic adaptation
+ float rAF = (float) Math.pow(viewingConditions.getFl() * Math.abs(rD) / 100.0, 0.42);
+ float gAF = (float) Math.pow(viewingConditions.getFl() * Math.abs(gD) / 100.0, 0.42);
+ float bAF = (float) Math.pow(viewingConditions.getFl() * Math.abs(bD) / 100.0, 0.42);
+ float rA = Math.signum(rD) * 400.0f * rAF / (rAF + 27.13f);
+ float gA = Math.signum(gD) * 400.0f * gAF / (gAF + 27.13f);
+ float bA = Math.signum(bD) * 400.0f * bAF / (bAF + 27.13f);
+
+ // redness-greenness
+ float a = (float) (11.0 * rA + -12.0 * gA + bA) / 11.0f;
+ // yellowness-blueness
+ float b = (float) (rA + gA - 2.0 * bA) / 9.0f;
+
+ // auxiliary components
+ float u = (20.0f * rA + 20.0f * gA + 21.0f * bA) / 20.0f;
+ float p2 = (40.0f * rA + 20.0f * gA + bA) / 20.0f;
+
+ // hue
+ float atan2 = (float) Math.atan2(b, a);
+ float atanDegrees = atan2 * 180.0f / (float) Math.PI;
+ float hue =
+ atanDegrees < 0
+ ? atanDegrees + 360.0f
+ : atanDegrees >= 360 ? atanDegrees - 360.0f : atanDegrees;
+ float hueRadians = hue * (float) Math.PI / 180.0f;
+
+ // achromatic response to color
+ float ac = p2 * viewingConditions.getNbb();
+
+ // CAM16 lightness and brightness
+ float j = 100.0f * (float) Math.pow(ac / viewingConditions.getAw(),
+ viewingConditions.getC() * viewingConditions.getZ());
+ float q =
+ 4.0f
+ / viewingConditions.getC()
+ * (float) Math.sqrt(j / 100.0f)
+ * (viewingConditions.getAw() + 4.0f)
+ * viewingConditions.getFlRoot();
+
+ // CAM16 chroma, colorfulness, and saturation.
+ float huePrime = (hue < 20.14) ? hue + 360 : hue;
+ float eHue = 0.25f * (float) (Math.cos(huePrime * Math.PI / 180.0 + 2.0) + 3.8);
+ float p1 = 50000.0f / 13.0f * eHue * viewingConditions.getNc() * viewingConditions.getNcb();
+ float t = p1 * (float) Math.sqrt(a * a + b * b) / (u + 0.305f);
+ float alpha = (float) Math.pow(1.64 - Math.pow(0.29, viewingConditions.getN()), 0.73)
+ * (float) Math.pow(t, 0.9);
+ // CAM16 chroma, colorfulness, saturation
+ float c = alpha * (float) Math.sqrt(j / 100.0);
+ float m = c * viewingConditions.getFlRoot();
+ float s = 50.0f * (float) Math.sqrt((alpha * viewingConditions.getC()) / (
+ viewingConditions.getAw() + 4.0f));
+
+ // CAM16-UCS components
+ float jstar = (1.0f + 100.0f * 0.007f) * j / (1.0f + 0.007f * j);
+ float mstar = 1.0f / 0.0228f * (float) Math.log(1.0f + 0.0228f * m);
+ float astar = mstar * (float) Math.cos(hueRadians);
+ float bstar = mstar * (float) Math.sin(hueRadians);
+
+ return new CamColor(hue, c, j, q, m, s, jstar, astar, bstar);
+ }
+
+ /**
+ * Create a CAM from lightness, chroma, and hue coordinates. It is assumed those coordinates
+ * were measured in the default ViewingConditions.
+ */
+ @NonNull
+ private static CamColor fromJch(@FloatRange(from = 0.0, to = 100.0) float j,
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false) float c,
+ @FloatRange(from = 0.0, to = 360.0) float h) {
+ return fromJchInFrame(j, c, h, ViewingConditions.DEFAULT);
+ }
+
+ /**
+ * Create a CAM from lightness, chroma, and hue coordinates, and also specify the
+ * ViewingConditions where the color was seen.
+ */
+ @NonNull
+ private static CamColor fromJchInFrame(@FloatRange(from = 0.0, to = 100.0) float j,
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false) float c,
+ @FloatRange(from = 0.0, to = 360.0) float h, ViewingConditions viewingConditions) {
+ float q =
+ 4.0f
+ / viewingConditions.getC()
+ * (float) Math.sqrt(j / 100.0)
+ * (viewingConditions.getAw() + 4.0f)
+ * viewingConditions.getFlRoot();
+ float m = c * viewingConditions.getFlRoot();
+ float alpha = c / (float) Math.sqrt(j / 100.0);
+ float s = 50.0f * (float) Math.sqrt((alpha * viewingConditions.getC()) / (
+ viewingConditions.getAw() + 4.0f));
+
+ float hueRadians = h * (float) Math.PI / 180.0f;
+ float jstar = (1.0f + 100.0f * 0.007f) * j / (1.0f + 0.007f * j);
+ float mstar = 1.0f / 0.0228f * (float) Math.log(1.0 + 0.0228 * m);
+ float astar = mstar * (float) Math.cos(hueRadians);
+ float bstar = mstar * (float) Math.sin(hueRadians);
+ return new CamColor(h, c, j, q, m, s, jstar, astar, bstar);
+ }
+
+ /**
+ * Distance in CAM16-UCS space between two colors.
+ *
+ * <p>Much like L*a*b* was designed to measure distance between colors, the CAM16 standard
+ * defined a color space called CAM16-UCS to measure distance between CAM16 colors.
+ */
+ float distance(@NonNull CamColor other) {
+ float dJ = getJStar() - other.getJStar();
+ float dA = getAStar() - other.getAStar();
+ float dB = getBStar() - other.getBStar();
+ double dEPrime = Math.sqrt(dJ * dJ + dA * dA + dB * dB);
+ double dE = 1.41 * Math.pow(dEPrime, 0.63);
+ return (float) dE;
+ }
+
+ /** Returns perceived color as an ARGB integer, as viewed in default ViewingConditions. */
+ @ColorInt
+ int viewedInSrgb() {
+ return viewed(ViewingConditions.DEFAULT);
+ }
+
+ /** Returns color perceived in a ViewingConditions as an ARGB integer. */
+ @ColorInt
+ int viewed(@NonNull ViewingConditions viewingConditions) {
+ float alpha =
+ (getChroma() == 0.0 || getJ() == 0.0)
+ ? 0.0f
+ : getChroma() / (float) Math.sqrt(getJ() / 100.0);
+
+ float t = (float) Math.pow(alpha / Math.pow(1.64
+ - Math.pow(0.29, viewingConditions.getN()), 0.73), 1.0 / 0.9);
+ float hRad = getHue() * (float) Math.PI / 180.0f;
+
+ float eHue = 0.25f * (float) (Math.cos(hRad + 2.0) + 3.8);
+ float ac = viewingConditions.getAw() * (float) Math.pow(getJ() / 100.0,
+ 1.0 / viewingConditions.getC() / viewingConditions.getZ());
+ float p1 =
+ eHue * (50000.0f / 13.0f) * viewingConditions.getNc() * viewingConditions.getNcb();
+ float p2 = (ac / viewingConditions.getNbb());
+
+ float hSin = (float) Math.sin(hRad);
+ float hCos = (float) Math.cos(hRad);
+
+ float gamma =
+ 23.0f * (p2 + 0.305f) * t / (23.0f * p1 + 11.0f * t * hCos + 108.0f * t * hSin);
+ float a = gamma * hCos;
+ float b = gamma * hSin;
+ float rA = (460.0f * p2 + 451.0f * a + 288.0f * b) / 1403.0f;
+ float gA = (460.0f * p2 - 891.0f * a - 261.0f * b) / 1403.0f;
+ float bA = (460.0f * p2 - 220.0f * a - 6300.0f * b) / 1403.0f;
+
+ float rCBase = (float) Math.max(0, (27.13 * Math.abs(rA)) / (400.0 - Math.abs(rA)));
+ float rC = Math.signum(rA) * (100.0f / viewingConditions.getFl()) * (float) Math.pow(rCBase,
+ 1.0 / 0.42);
+ float gCBase = (float) Math.max(0, (27.13 * Math.abs(gA)) / (400.0 - Math.abs(gA)));
+ float gC = Math.signum(gA) * (100.0f / viewingConditions.getFl()) * (float) Math.pow(gCBase,
+ 1.0 / 0.42);
+ float bCBase = (float) Math.max(0, (27.13 * Math.abs(bA)) / (400.0 - Math.abs(bA)));
+ float bC = Math.signum(bA) * (100.0f / viewingConditions.getFl()) * (float) Math.pow(bCBase,
+ 1.0 / 0.42);
+ float rF = rC / viewingConditions.getRgbD()[0];
+ float gF = gC / viewingConditions.getRgbD()[1];
+ float bF = bC / viewingConditions.getRgbD()[2];
+
+
+ float[][] matrix = CamUtils.CAM16RGB_TO_XYZ;
+ float x = (rF * matrix[0][0]) + (gF * matrix[0][1]) + (bF * matrix[0][2]);
+ float y = (rF * matrix[1][0]) + (gF * matrix[1][1]) + (bF * matrix[1][2]);
+ float z = (rF * matrix[2][0]) + (gF * matrix[2][1]) + (bF * matrix[2][2]);
+
+ int argb = ColorUtils.XYZToColor(x, y, z);
+ return argb;
+ }
+
+ /**
+ * Given a hue & chroma in CAM16, L* in L*a*b*, and the ViewingConditions in which the
+ * color will be viewed, return an ARGB integer.
+ *
+ * <p>The chroma of the color returned may, and frequently will, be lower than requested. This
+ * is a fundamental property of color that cannot be worked around by engineering. For example,
+ * a red hue, with high chroma, and high L* does not exist: red hues have a maximum chroma
+ * below 10 in light shades, creating pink.
+ */
+ static @ColorInt int toColor(@FloatRange(from = 0.0, to = 360.0) float hue,
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float chroma,
+ @FloatRange(from = 0.0, to = 100.0) float lstar,
+ @NonNull ViewingConditions viewingConditions) {
+ // This is a crucial routine for building a color system, CAM16 itself is not sufficient.
+ //
+ // * Why these dimensions?
+ // Hue and chroma from CAM16 are used because they're the most accurate measures of those
+ // quantities. L* from L*a*b* is used because it correlates with luminance, luminance is
+ // used to measure contrast for a11y purposes, thus providing a key constraint on what
+ // colors
+ // can be used.
+ //
+ // * Why is this routine required to build a color system?
+ // In all perceptually accurate color spaces (i.e. L*a*b* and later), `chroma` may be
+ // impossible for a given `hue` and `lstar`.
+ // For example, a high chroma light red does not exist - chroma is limited to below 10 at
+ // light red shades, we call that pink. High chroma light green does exist, but not dark
+ // Also, when converting from another color space to RGB, the color may not be able to be
+ // represented in RGB. In those cases, the conversion process ends with RGB values
+ // outside 0-255
+ // The vast majority of color libraries surveyed simply round to 0 to 255. That is not an
+ // option for this library, as it distorts the expected luminance, and thus the expected
+ // contrast needed for a11y
+ //
+ // * What does this routine do?
+ // Dealing with colors in one color space not fitting inside RGB is, loosely referred to as
+ // gamut mapping or tone mapping. These algorithms are traditionally idiosyncratic, there is
+ // no universal answer. However, because the intent of this library is to build a system for
+ // digital design, and digital design uses luminance to measure contrast/a11y, we have one
+ // very important constraint that leads to an objective algorithm: the L* of the returned
+ // color _must_ match the requested L*.
+ //
+ // Intuitively, if the color must be distorted to fit into the RGB gamut, and the L*
+ // requested *must* be fulfilled, than the hue or chroma of the returned color will need
+ // to be different from the requested hue/chroma.
+ //
+ // After exploring both options, it was more intuitive that if the requested chroma could
+ // not be reached, it used the highest possible chroma. The alternative was finding the
+ // closest hue where the requested chroma could be reached, but that is not nearly as
+ // intuitive, as the requested hue is so fundamental to the color description.
+
+ // If the color doesn't have meaningful chroma, return a gray with the requested Lstar.
+ //
+ // Yellows are very chromatic at L = 100, and blues are very chromatic at L = 0. All the
+ // other hues are white at L = 100, and black at L = 0. To preserve consistency for users of
+ // this system, it is better to simply return white at L* > 99, and black and L* < 0.
+ if (chroma < 1.0 || Math.round(lstar) <= 0.0 || Math.round(lstar) >= 100.0) {
+ return CamUtils.intFromLStar(lstar);
+ }
+
+ hue = hue < 0 ? 0 : Math.min(360, hue);
+
+ // The highest chroma possible. Updated as binary search proceeds.
+ float high = chroma;
+
+ // The guess for the current binary search iteration. Starts off at the highest chroma,
+ // thus, if a color is possible at the requested chroma, the search can stop after one try.
+ float mid = chroma;
+ float low = 0.0f;
+ boolean isFirstLoop = true;
+
+ CamColor answer = null;
+
+ while (Math.abs(low - high) >= CHROMA_SEARCH_ENDPOINT) {
+ // Given the current chroma guess, mid, and the desired hue, find J, lightness in
+ // CAM16 color space, that creates a color with L* = `lstar` in the L*a*b* color space.
+ CamColor possibleAnswer = findCamByJ(hue, mid, lstar);
+
+ if (isFirstLoop) {
+ if (possibleAnswer != null) {
+ return possibleAnswer.viewed(viewingConditions);
+ } else {
+ // If this binary search iteration was the first iteration, and this point
+ // has been reached, it means the requested chroma was not available at the
+ // requested hue and L*.
+ // Proceed to a traditional binary search that starts at the midpoint between
+ // the requested chroma and 0.
+ isFirstLoop = false;
+ mid = low + (high - low) / 2.0f;
+ continue;
+ }
+ }
+
+ if (possibleAnswer == null) {
+ // There isn't a CAM16 J that creates a color with L* `lstar`. Try a lower chroma.
+ high = mid;
+ } else {
+ answer = possibleAnswer;
+ // It is possible to create a color. Try higher chroma.
+ low = mid;
+ }
+
+ mid = low + (high - low) / 2.0f;
+ }
+
+ // There was no answer: meaning, for the desired hue, there was no chroma low enough to
+ // generate a color with the desired L*.
+ // All values of L* are possible when there is 0 chroma. Return a color with 0 chroma, i.e.
+ // a shade of gray, with the desired L*.
+ if (answer == null) {
+ return CamUtils.intFromLStar(lstar);
+ }
+
+ return answer.viewed(viewingConditions);
+ }
+
+ // Find J, lightness in CAM16 color space, that creates a color with L* = `lstar` in the L*a*b*
+ // color space.
+ //
+ // Returns null if no J could be found that generated a color with L* `lstar`.
+ @Nullable
+ private static CamColor findCamByJ(@FloatRange(from = 0.0, to = 360.0) float hue,
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float chroma,
+ @FloatRange(from = 0.0, to = 100.0) float lstar) {
+ float low = 0.0f;
+ float high = 100.0f;
+ float mid = 0.0f;
+ float bestdL = 1000.0f;
+ float bestdE = 1000.0f;
+
+ CamColor bestCam = null;
+ while (Math.abs(low - high) > LIGHTNESS_SEARCH_ENDPOINT) {
+ mid = low + (high - low) / 2;
+ // Create the intended CAM color
+ CamColor camBeforeClip = CamColor.fromJch(mid, chroma, hue);
+ // Convert the CAM color to RGB. If the color didn't fit in RGB, during the conversion,
+ // the initial RGB values will be outside 0 to 255. The final RGB values are clipped to
+ // 0 to 255, distorting the intended color.
+ int clipped = camBeforeClip.viewedInSrgb();
+ float clippedLstar = CamUtils.lStarFromInt(clipped);
+ float dL = Math.abs(lstar - clippedLstar);
+
+ // If the clipped color's L* is within error margin...
+ if (dL < DL_MAX) {
+ // ...check if the CAM equivalent of the clipped color is far away from intended CAM
+ // color. For the intended color, use lightness and chroma from the clipped color,
+ // and the intended hue. Callers are wondering what the lightness is, they know
+ // chroma may be distorted, so the only concern here is if the hue slipped too far.
+ CamColor camClipped = CamColor.fromColor(clipped);
+ float dE = camClipped.distance(
+ CamColor.fromJch(camClipped.getJ(), camClipped.getChroma(), hue));
+ if (dE <= DE_MAX) {
+ bestdL = dL;
+ bestdE = dE;
+ bestCam = camClipped;
+ }
+ }
+
+ // If there's no error at all, there's no need to search more.
+ //
+ // Note: this happens much more frequently than expected, but this is a very delicate
+ // property which relies on extremely precise sRGB <=> XYZ calculations, as well as fine
+ // tuning of the constants that determine error margins and when the binary search can
+ // terminate.
+ if (bestdL == 0 && bestdE == 0) {
+ break;
+ }
+
+ if (clippedLstar < lstar) {
+ low = mid;
+ } else {
+ high = mid;
+ }
+ }
+
+ return bestCam;
+ }
+
+}
diff --git a/core/core/src/main/java/androidx/core/content/res/CamUtils.java b/core/core/src/main/java/androidx/core/content/res/CamUtils.java
new file mode 100644
index 0000000..2d1ab7c
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/content/res/CamUtils.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.content.res;
+
+import android.graphics.Color;
+
+import androidx.annotation.NonNull;
+import androidx.core.graphics.ColorUtils;
+
+/**
+ * Collection of methods for transforming between color spaces.
+ *
+ * <p>Methods are named $xFrom$Y. For example, lstarFromInt() returns L* from an ARGB integer.
+ *
+ * <p>These methods, generally, convert colors between the L*a*b*, XYZ, and sRGB spaces.
+ *
+ * <p>L*a*b* is a perceptually accurate color space. This is particularly important in the L*
+ * dimension: it measures luminance and unlike lightness measures traditionally used in UI work via
+ * RGB or HSL, this luminance transitions smoothly, permitting creation of pleasing shades of a
+ * color, and more pleasing transitions between colors.
+ *
+ * <p>XYZ is commonly used as an intermediate color space for converting between one color space to
+ * another. For example, to convert RGB to L*a*b*, first RGB is converted to XYZ, then XYZ is
+ * convered to L*a*b*.
+ *
+ * <p>sRGB is a "specification originated from work in 1990s through cooperation by Hewlett-Packard
+ * and Microsoft, and it was designed to be a standard definition of RGB for the internet, which it
+ * indeed became...The standard is based on a sampling of computer monitors at the time...The whole
+ * idea of sRGB is that if everyone assumed that RGB meant the same thing, then the results would be
+ * consistent, and reasonably good. It worked." - Fairchild, Color Models and Systems: Handbook of
+ * Color Psychology, 2015
+ */
+final class CamUtils {
+ private CamUtils() {
+ }
+
+ // Transforms XYZ color space coordinates to 'cone'/'RGB' responses in CAM16.
+ static final float[][] XYZ_TO_CAM16RGB = {
+ {0.401288f, 0.650173f, -0.051461f},
+ {-0.250268f, 1.204414f, 0.045854f},
+ {-0.002079f, 0.048952f, 0.953127f}
+ };
+
+ // Transforms 'cone'/'RGB' responses in CAM16 to XYZ color space coordinates.
+ static final float[][] CAM16RGB_TO_XYZ = {
+ {1.8620678f, -1.0112547f, 0.14918678f},
+ {0.38752654f, 0.62144744f, -0.00897398f},
+ {-0.01584150f, -0.03412294f, 1.0499644f}
+ };
+
+ // sRGB specification has D65 whitepoint - Stokes, Anderson, Chandrasekar, Motta - A Standard
+ // Default Color Space for the Internet: sRGB, 1996
+ static final float[] WHITE_POINT_D65 = {95.047f, 100.0f, 108.883f};
+
+ // This is a more precise sRGB to XYZ transformation matrix than traditionally
+ // used. It was derived using Schlomer's technique of transforming the xyY
+ // primaries to XYZ, then applying a correction to ensure mapping from sRGB
+ // 1, 1, 1 to the reference white point, D65.
+ static final float[][] SRGB_TO_XYZ = {
+ {0.41233894f, 0.35762063f, 0.18051042f},
+ {0.2126f, 0.7152f, 0.0722f},
+ {0.01932141f, 0.11916382f, 0.9503448f}
+ };
+
+ static int intFromLStar(float lStar) {
+ if (lStar < 1) {
+ return 0xff000000;
+ } else if (lStar > 99) {
+ return 0xffffffff;
+ }
+
+ // XYZ to LAB conversion routine, assume a and b are 0.
+ float fy = (lStar + 16.0f) / 116.0f;
+
+ // fz = fx = fy because a and b are 0
+ float fz = fy;
+ float fx = fy;
+
+ float kappa = 24389f / 27f;
+ float epsilon = 216f / 24389f;
+ boolean lExceedsEpsilonKappa = (lStar > 8.0f);
+ float yT = lExceedsEpsilonKappa ? fy * fy * fy : lStar / kappa;
+ boolean cubeExceedEpsilon = (fy * fy * fy) > epsilon;
+ float xT = cubeExceedEpsilon ? fx * fx * fx : (116f * fx - 16f) / kappa;
+ float zT = cubeExceedEpsilon ? fz * fz * fz : (116f * fx - 16f) / kappa;
+
+ return ColorUtils.XYZToColor(xT * CamUtils.WHITE_POINT_D65[0],
+ yT * CamUtils.WHITE_POINT_D65[1], zT * CamUtils.WHITE_POINT_D65[2]);
+ }
+
+ static float lerp(float start, float stop, float amount) {
+ return start + (stop - start) * amount;
+ }
+
+ /** Returns L* from L*a*b*, perceptual luminance, from an ARGB integer (ColorInt). */
+ static float lStarFromInt(int argb) {
+ return lStarFromY(yFromInt(argb));
+ }
+
+ static float lStarFromY(float y) {
+ y = y / 100.0f;
+ final float e = 216.f / 24389.f;
+ float yIntermediate;
+ if (y <= e) {
+ return ((24389.f / 27.f) * y);
+ } else {
+ yIntermediate = (float) Math.cbrt(y);
+ }
+ return 116.f * yIntermediate - 16.f;
+ }
+
+ static float yFromInt(int argb) {
+ final float r = linearized(Color.red(argb));
+ final float g = linearized(Color.green(argb));
+ final float b = linearized(Color.blue(argb));
+ float[][] matrix = SRGB_TO_XYZ;
+ float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
+ return y;
+ }
+
+ @NonNull
+ static float[] xyzFromInt(int argb) {
+ final float r = linearized(Color.red(argb));
+ final float g = linearized(Color.green(argb));
+ final float b = linearized(Color.blue(argb));
+
+ float[][] matrix = SRGB_TO_XYZ;
+ float x = (r * matrix[0][0]) + (g * matrix[0][1]) + (b * matrix[0][2]);
+ float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
+ float z = (r * matrix[2][0]) + (g * matrix[2][1]) + (b * matrix[2][2]);
+ return new float[]{x, y, z};
+ }
+
+ static float yFromLStar(float lstar) {
+ float ke = 8.0f;
+ if (lstar > ke) {
+ return (float) Math.pow(((lstar + 16.0) / 116.0), 3) * 100f;
+ } else {
+ return lstar / (24389f / 27f) * 100f;
+ }
+ }
+
+ static float linearized(int rgbComponent) {
+ float normalized = (float) rgbComponent / 255.0f;
+
+ if (normalized <= 0.04045f) {
+ return (normalized / 12.92f) * 100.0f;
+ } else {
+ return (float) Math.pow(((normalized + 0.055f) / 1.055f), 2.4f) * 100.0f;
+ }
+ }
+}
diff --git a/core/core/src/main/java/androidx/core/content/res/ColorStateListInflaterCompat.java b/core/core/src/main/java/androidx/core/content/res/ColorStateListInflaterCompat.java
index 2015927..9ea4288 100644
--- a/core/core/src/main/java/androidx/core/content/res/ColorStateListInflaterCompat.java
+++ b/core/core/src/main/java/androidx/core/content/res/ColorStateListInflaterCompat.java
@@ -36,6 +36,8 @@
import androidx.annotation.RestrictTo;
import androidx.annotation.XmlRes;
import androidx.core.R;
+import androidx.core.math.MathUtils;
+import androidx.core.os.BuildCompat;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -165,6 +167,14 @@
alphaMod = a.getFloat(R.styleable.ColorStateListItem_alpha, alphaMod);
}
+ final float lStar;
+ if (BuildCompat.isAtLeastS()
+ && a.hasValue(R.styleable.ColorStateListItem_android_lStar)) {
+ lStar = a.getFloat(R.styleable.ColorStateListItem_android_lStar, -1.0f);
+ } else {
+ lStar = a.getFloat(R.styleable.ColorStateListItem_lStar, -1.0f);
+ }
+
a.recycle();
// Parse all unrecognized attributes as state specifiers.
@@ -173,8 +183,10 @@
int[] stateSpec = new int[numAttrs];
for (int i = 0; i < numAttrs; i++) {
final int stateResId = attrs.getAttributeNameResource(i);
- if (stateResId != android.R.attr.color && stateResId != android.R.attr.alpha
- && stateResId != R.attr.alpha) {
+ if (stateResId != android.R.attr.color
+ && stateResId != android.R.attr.alpha
+ && stateResId != R.attr.alpha
+ && stateResId != R.attr.lStar) {
// Unrecognized attribute, add to state set
stateSpec[j++] = attrs.getAttributeBooleanValue(i, false)
? stateResId : -stateResId;
@@ -182,10 +194,10 @@
}
stateSpec = StateSet.trimStateSet(stateSpec, j);
- // Apply alpha modulation. If we couldn't resolve the color or
+ // Apply alpha and luminance modulation. If we couldn't resolve the color or
// alpha yet, the default values leave us enough information to
// modulate again during applyTheme().
- final int color = modulateColorAlpha(baseColor, alphaMod);
+ final int color = modulateColorAlpha(baseColor, alphaMod, lStar);
colorList = GrowingArrayUtils.append(colorList, listSize, color);
stateSpecList = GrowingArrayUtils.append(stateSpecList, listSize, stateSpec);
@@ -225,8 +237,21 @@
@ColorInt
private static int modulateColorAlpha(@ColorInt int color,
- @FloatRange(from = 0f, to = 1f) float alphaMod) {
- int alpha = Math.round(Color.alpha(color) * alphaMod);
- return (color & 0x00ffffff) | (alpha << 24);
+ @FloatRange(from = 0f, to = 1f) float alphaMod,
+ @FloatRange(from = 0f, to = 100f) float lStar) {
+ final boolean validLStar = lStar >= 0.0f && lStar <= 100.0f;
+ if (alphaMod == 1.0f && !validLStar) {
+ return color;
+ }
+
+ final int baseAlpha = Color.alpha(color);
+ final int alpha = MathUtils.clamp((int) (baseAlpha * alphaMod + 0.5f), 0, 255);
+
+ if (validLStar) {
+ final CamColor baseCam = CamColor.fromColor(color);
+ color = CamColor.toColor(baseCam.getHue(), baseCam.getChroma(), lStar);
+ }
+
+ return (color & 0xFFFFFF) | (alpha << 24);
}
}
diff --git a/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java b/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
index ff21626c..f27583d 100644
--- a/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
+++ b/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
@@ -190,12 +190,10 @@
@SuppressWarnings("deprecation")
public static ColorStateList getColorStateList(@NonNull Resources res, @ColorRes int id,
@Nullable Theme theme) throws NotFoundException {
- if (SDK_INT >= 23) {
- // On M+ we can use the framework
- return res.getColorStateList(id, theme);
- }
+ // We explicitly do not attempt to use the platform Resources impl on S+
+ // in case the CSL is using only app:lStar
- // Before that, we'll try handle it ourselves
+ // First, try and handle the inflation ourselves
ColorStateListCacheKey key = new ColorStateListCacheKey(res, theme);
ColorStateList csl = getCachedColorStateList(key, id);
if (csl != null) {
diff --git a/core/core/src/main/java/androidx/core/content/res/ViewingConditions.java b/core/core/src/main/java/androidx/core/content/res/ViewingConditions.java
new file mode 100644
index 0000000..1768c07
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/content/res/ViewingConditions.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.content.res;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Viewing conditions define parameters of where a color was seen. Used, along with a color, to
+ * create a color appearance model representing the color.
+ *
+ * <p>To convert a traditional color to a color appearance model, it requires knowing what
+ * conditions the color was observed in. Our perception of color depends on, for example, the tone
+ * of the light illuminating the color, how bright that light was, etc.
+ *
+ * <p>This class is modelled separately from the color appearance model itself because there are a
+ * number of calculations during the color => CAM conversion process that depend only on the viewing
+ * conditions. Caching those calculations saves a significant amount of time.
+ */
+final class ViewingConditions {
+ // Standard viewing conditions assumed in RGB specification - Stokes, Anderson, Chandrasekar,
+ // Motta - A Standard Default Color Space for the Internet: sRGB, 1996.
+ //
+ // White point = D65
+ // Luminance of adapting field: 200 / Pi / 5, units are cd/m^2.
+ // sRGB ambient illuminance = 64 lux (per sRGB spec). However, the spec notes this is
+ // artificially low and based on monitors in 1990s. Use 200, the sRGB spec says this is the
+ // real average, and a survey of lux values on Wikipedia confirms this is a comfortable
+ // default: somewhere between a very dark overcast day and office lighting.
+ // Per CAM16 introduction paper (Li et al, 2017) Ew = pi * lw, and La = lw * Yb/Yw
+ // Ew = ambient environment luminance, in lux.
+ // Yb/Yw is taken to be midgray, ~20% relative luminance (XYZ Y 18.4, CIELAB L* 50).
+ // Therefore La = (Ew / pi) * .184
+ // La = 200 / pi * .184
+ // Image surround to 10 degrees = ~20% relative luminance = CIELAB L* 50
+ //
+ // Not from sRGB standard:
+ // Surround = average, 2.0.
+ // Discounting illuminant = false, doesn't occur for self-luminous displays
+ static final ViewingConditions DEFAULT =
+ ViewingConditions.make(
+ CamUtils.WHITE_POINT_D65,
+ (float) (200.0f / Math.PI * CamUtils.yFromLStar(50.0f) / 100.f), 50.0f, 2.0f,
+ false);
+
+ private final float mAw;
+ private final float mNbb;
+ private final float mNcb;
+ private final float mC;
+ private final float mNc;
+ private final float mN;
+ private final float[] mRgbD;
+ private final float mFl;
+ private final float mFlRoot;
+ private final float mZ;
+
+ float getAw() {
+ return mAw;
+ }
+
+ float getN() {
+ return mN;
+ }
+
+ float getNbb() {
+ return mNbb;
+ }
+
+ float getNcb() {
+ return mNcb;
+ }
+
+ float getC() {
+ return mC;
+ }
+
+ float getNc() {
+ return mNc;
+ }
+
+ @NonNull
+ float[] getRgbD() {
+ return mRgbD;
+ }
+
+ float getFl() {
+ return mFl;
+ }
+
+ float getFlRoot() {
+ return mFlRoot;
+ }
+
+ float getZ() {
+ return mZ;
+ }
+
+ private ViewingConditions(float n, float aw, float nbb, float ncb, float c, float nc,
+ float[] rgbD, float fl, float fLRoot, float z) {
+ mN = n;
+ mAw = aw;
+ mNbb = nbb;
+ mNcb = ncb;
+ mC = c;
+ mNc = nc;
+ mRgbD = rgbD;
+ mFl = fl;
+ mFlRoot = fLRoot;
+ mZ = z;
+ }
+
+ /** Create a custom camFrame. */
+ @NonNull
+ static ViewingConditions make(@NonNull float[] whitepoint, float adaptingLuminance,
+ float backgroundLstar, float surround, boolean discountingIlluminant) {
+ // Transform white point XYZ to 'cone'/'rgb' responses
+ float[][] matrix = CamUtils.XYZ_TO_CAM16RGB;
+ float[] xyz = whitepoint;
+ float rW = (xyz[0] * matrix[0][0]) + (xyz[1] * matrix[0][1]) + (xyz[2] * matrix[0][2]);
+ float gW = (xyz[0] * matrix[1][0]) + (xyz[1] * matrix[1][1]) + (xyz[2] * matrix[1][2]);
+ float bW = (xyz[0] * matrix[2][0]) + (xyz[1] * matrix[2][1]) + (xyz[2] * matrix[2][2]);
+
+ // Scale input surround, domain (0, 2), to CAM16 surround, domain (0.8, 1.0)
+ float f = 0.8f + (surround / 10.0f);
+ // "Exponential non-linearity"
+ float c = (f >= 0.9) ? CamUtils.lerp(0.59f, 0.69f, ((f - 0.9f) * 10.0f)) : CamUtils.lerp(
+ 0.525f, 0.59f, ((f - 0.8f) * 10.0f));
+ // Calculate degree of adaptation to illuminant
+ float d = discountingIlluminant ? 1.0f : f * (1.0f - ((1.0f / 3.6f) * (float) Math.exp(
+ (-adaptingLuminance - 42.0f) / 92.0f)));
+ // Per Li et al, if D is greater than 1 or less than 0, set it to 1 or 0.
+ d = (d > 1.0) ? 1.0f : (d < 0.0) ? 0.0f : d;
+ // Chromatic induction factor
+ float nc = f;
+
+ // Cone responses to the whitepoint, adjusted for illuminant discounting.
+ //
+ // Why use 100.0 instead of the white point's relative luminance?
+ //
+ // Some papers and implementations, for both CAM02 and CAM16, use the Y
+ // value of the reference white instead of 100. Fairchild's Color Appearance
+ // Models (3rd edition) notes that this is in error: it was included in the
+ // CIE 2004a report on CIECAM02, but, later parts of the conversion process
+ // account for scaling of appearance relative to the white point relative
+ // luminance. This part should simply use 100 as luminance.
+ float[] rgbD = new float[]{d * (100.0f / rW) + 1.0f - d, d * (100.0f / gW) + 1.0f - d,
+ d * (100.0f / bW) + 1.0f - d};
+ // Luminance-level adaptation factor
+ float k = 1.0f / (5.0f * adaptingLuminance + 1.0f);
+ float k4 = k * k * k * k;
+ float k4F = 1.0f - k4;
+ float fl = (k4 * adaptingLuminance) + (0.1f * k4F * k4F * (float) Math.cbrt(
+ 5.0 * adaptingLuminance));
+
+ // Intermediate factor, ratio of background relative luminance to white relative luminance
+ float n = CamUtils.yFromLStar(backgroundLstar) / whitepoint[1];
+
+ // Base exponential nonlinearity
+ // note Schlomer 2018 has a typo and uses 1.58, the correct factor is 1.48
+ float z = 1.48f + (float) Math.sqrt(n);
+
+ // Luminance-level induction factors
+ float nbb = 0.725f / (float) Math.pow(n, 0.2);
+ float ncb = nbb;
+
+ // Discounted cone responses to the white point, adjusted for post-chromatic
+ // adaptation perceptual nonlinearities.
+ float[] rgbAFactors = new float[]{(float) Math.pow(fl * rgbD[0] * rW / 100.0, 0.42),
+ (float) Math.pow(fl * rgbD[1] * gW / 100.0, 0.42), (float) Math.pow(
+ fl * rgbD[2] * bW / 100.0, 0.42)};
+
+ float[] rgbA = new float[]{(400.0f * rgbAFactors[0]) / (rgbAFactors[0] + 27.13f),
+ (400.0f * rgbAFactors[1]) / (rgbAFactors[1] + 27.13f),
+ (400.0f * rgbAFactors[2]) / (rgbAFactors[2] + 27.13f)};
+
+ float aw = ((2.0f * rgbA[0]) + rgbA[1] + (0.05f * rgbA[2])) * nbb;
+
+ return new ViewingConditions(n, aw, nbb, ncb, c, nc, rgbD, fl, (float) Math.pow(fl, 0.25),
+ z);
+ }
+}
diff --git a/core/core/src/main/java/androidx/core/location/LocationListenerCompat.java b/core/core/src/main/java/androidx/core/location/LocationListenerCompat.java
new file mode 100644
index 0000000..d626af1
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/location/LocationListenerCompat.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.location;
+
+import android.location.LocationListener;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * A version of {@link LocationListener} suitable for use on all API levels.
+ */
+public interface LocationListenerCompat extends LocationListener {
+
+ @Override
+ default void onStatusChanged(@NonNull String provider, int status, @Nullable Bundle extras) {}
+
+ @Override
+ default void onProviderEnabled(@NonNull String provider) {}
+
+ @Override
+ default void onProviderDisabled(@NonNull String provider) {}
+}
diff --git a/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java b/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
index 61a7836..c450492 100644
--- a/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
@@ -32,6 +32,7 @@
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
+import android.location.LocationRequest;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -52,10 +53,17 @@
import androidx.core.os.CancellationSignal;
import androidx.core.os.ExecutorCompat;
import androidx.core.util.Consumer;
+import androidx.core.util.ObjectsCompat;
import androidx.core.util.Preconditions;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
-import java.util.concurrent.Callable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
@@ -65,6 +73,7 @@
/**
* Helper for accessing features in {@link LocationManager}.
*/
+@SuppressWarnings("deprecation")
public final class LocationManagerCompat {
private static final long GET_CURRENT_LOCATION_TIMEOUT_MS = 30 * 1000;
@@ -72,6 +81,8 @@
private static final long PRE_N_LOOPER_TIMEOUT_S = 5;
private static Field sContextField;
+ private static Method sRequestLocationUpdatesExecutorMethod;
+ private static Method sRequestLocationUpdatesLooperMethod;
/**
* Returns the current enabled/disabled state of location.
@@ -84,6 +95,7 @@
*
* @return {@code true} if location is enabled or {@code false} if location is disabled
*/
+ @SuppressWarnings("JavaReflectionMemberAccess")
public static boolean isLocationEnabled(@NonNull LocationManager locationManager) {
if (VERSION.SDK_INT >= 28) {
return Api28Impl.isLocationEnabled(locationManager);
@@ -122,6 +134,33 @@
}
/**
+ * Returns true if the given location provider exists on this device, irrespective of whether
+ * it is currently enabled or not. If called on Android Q and below for the
+ * {@link LocationManager#FUSED_PROVIDER}, this method may return incorrect results if the
+ * client does not hold at least the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+ * permission.
+ */
+ public static boolean hasProvider(@NonNull LocationManager locationManager,
+ @NonNull String provider) {
+ if (VERSION.SDK_INT >= 31) {
+ return Api31Impl.hasProvider(locationManager, provider);
+ }
+
+ // will not work for the FUSED provider by default
+ if (locationManager.getAllProviders().contains(provider)) {
+ return true;
+ }
+
+ try {
+ // Q and below have pointless location permission requirements when using getProvider()
+ return locationManager.getProvider(provider) != null;
+ } catch (SecurityException ignored) {
+ }
+
+ return false;
+ }
+
+ /**
* Asynchronously returns a single current location fix from the given provider. This may
* activate sensors in order to compute a new location. The given callback will be invoked once
* and only once, either with a valid location or with a null location if the provider was
@@ -146,43 +185,182 @@
if (VERSION.SDK_INT >= 30) {
Api30Impl.getCurrentLocation(locationManager, provider, cancellationSignal, executor,
consumer);
- } else {
- if (cancellationSignal != null) {
- cancellationSignal.throwIfCanceled();
- }
+ return;
+ }
- final Location location = locationManager.getLastKnownLocation(provider);
- if (location != null) {
- long locationAgeMs =
- SystemClock.elapsedRealtime() - getElapsedRealtimeMillis(location);
- if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- consumer.accept(location);
- }
- });
- return;
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
+ final Location location = locationManager.getLastKnownLocation(provider);
+ if (location != null) {
+ long locationAgeMs =
+ SystemClock.elapsedRealtime() - getElapsedRealtimeMillis(location);
+ if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
+ executor.execute(() -> consumer.accept(location));
+ return;
+ }
+ }
+
+ final CancellableLocationListener listener =
+ new CancellableLocationListener(locationManager, executor, consumer);
+ locationManager.requestLocationUpdates(provider, 0, 0, listener,
+ Looper.getMainLooper());
+
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ @Override
+ public void onCancel() {
+ listener.cancel();
+ }
+ });
+ }
+
+ listener.startTimeout(GET_CURRENT_LOCATION_TIMEOUT_MS);
+ }
+
+ @GuardedBy("sLocationListeners")
+ static final WeakHashMap<LocationListener,
+ List<WeakReference<LocationListenerTransport>>> sLocationListeners =
+ new WeakHashMap<>();
+
+ /**
+ * Register for location updates from the specified provider, using a
+ * {@link LocationRequestCompat}, and a callback on the specified {@link Executor}.
+ *
+ * <p>See
+ * {@link LocationManager#requestLocationUpdates(String, LocationRequest, Executor,
+ * LocationListener)} for more information.
+ */
+ @SuppressWarnings("JavaReflectionMemberAccess")
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public static void requestLocationUpdates(@NonNull LocationManager locationManager,
+ @NonNull String provider,
+ @NonNull LocationRequestCompat locationRequest,
+ @NonNull Executor executor,
+ @NonNull LocationListenerCompat listener) {
+ if (VERSION.SDK_INT >= 31) {
+ Api31Impl.requestLocationUpdates(locationManager, provider,
+ locationRequest.toLocationRequest(), executor, listener);
+ return;
+ }
+
+ if (VERSION.SDK_INT >= 30) {
+ try {
+ if (sRequestLocationUpdatesExecutorMethod == null) {
+ sRequestLocationUpdatesExecutorMethod = LocationManager.class.getDeclaredMethod(
+ "requestLocationUpdates",
+ LocationRequest.class, Executor.class, LocationListener.class);
+ sRequestLocationUpdatesExecutorMethod.setAccessible(true);
+ }
+
+ sRequestLocationUpdatesExecutorMethod.invoke(locationManager,
+ locationRequest.toLocationRequest(provider), executor, listener);
+ return;
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+ // ignored
+ }
+ }
+
+ LocationListenerTransport transport = new LocationListenerTransport(listener, executor);
+
+ if (VERSION.SDK_INT >= 19) {
+ try {
+ if (sRequestLocationUpdatesLooperMethod == null) {
+ sRequestLocationUpdatesLooperMethod = LocationManager.class.getDeclaredMethod(
+ "requestLocationUpdates",
+ LocationRequest.class, LocationListener.class, Looper.class);
+ sRequestLocationUpdatesLooperMethod.setAccessible(true);
+ }
+
+ synchronized (sLocationListeners) {
+ sRequestLocationUpdatesLooperMethod.invoke(locationManager,
+ locationRequest.toLocationRequest(provider), transport,
+ Looper.getMainLooper());
+ transport.register();
+ }
+ return;
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+ // ignored
+ }
+ }
+
+ synchronized (sLocationListeners) {
+ locationManager.requestLocationUpdates(provider, locationRequest.getIntervalMillis(),
+ locationRequest.getMinUpdateDistanceMeters(), transport,
+ Looper.getMainLooper());
+ transport.register();
+ }
+ }
+
+ /**
+ * Register for location updates from the specified provider, using a
+ * {@link LocationRequestCompat}, and a callback on the specified {@link Looper}.
+ *
+ * <p>See
+ * {@link LocationManager#requestLocationUpdates(String, LocationRequest, Executor,
+ * LocationListener)} for more information.
+ */
+ @SuppressWarnings("JavaReflectionMemberAccess")
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public static void requestLocationUpdates(@NonNull LocationManager locationManager,
+ @NonNull String provider,
+ @NonNull LocationRequestCompat locationRequest,
+ @NonNull LocationListenerCompat listener,
+ @NonNull Looper looper) {
+ if (VERSION.SDK_INT >= 31) {
+ Api31Impl.requestLocationUpdates(locationManager, provider,
+ locationRequest.toLocationRequest(),
+ ExecutorCompat.create(new Handler(looper)), listener);
+ return;
+ }
+
+ if (VERSION.SDK_INT >= 19) {
+ try {
+ if (sRequestLocationUpdatesLooperMethod == null) {
+ sRequestLocationUpdatesLooperMethod = LocationManager.class.getDeclaredMethod(
+ "requestLocationUpdates",
+ LocationRequest.class, LocationListener.class, Looper.class);
+ sRequestLocationUpdatesLooperMethod.setAccessible(true);
+ }
+
+ sRequestLocationUpdatesLooperMethod.invoke(locationManager,
+ locationRequest.toLocationRequest(provider), listener, looper);
+ return;
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+ // ignored
+ }
+ }
+
+ locationManager.requestLocationUpdates(provider, locationRequest.getIntervalMillis(),
+ locationRequest.getMinUpdateDistanceMeters(), listener, looper);
+ }
+
+ /**
+ * Removes all location updates for the specified {@link LocationListener}.
+ *
+ * <p>See {@link LocationManager#removeUpdates(LocationListener)} for more information.
+ */
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public static void removeUpdates(@NonNull LocationManager locationManager,
+ @NonNull LocationListenerCompat listener) {
+ synchronized (sLocationListeners) {
+ List<WeakReference<LocationListenerTransport>> transports =
+ sLocationListeners.remove(listener);
+ if (transports != null) {
+ for (WeakReference<LocationListenerTransport> reference : transports) {
+ LocationListenerTransport transport = reference.get();
+ if (transport != null && transport.unregister()) {
+ locationManager.removeUpdates(transport);
+ }
}
}
-
- final CancellableLocationListener listener =
- new CancellableLocationListener(locationManager, executor, consumer);
- locationManager.requestLocationUpdates(provider, 0, 0, listener,
- Looper.getMainLooper());
-
- if (cancellationSignal != null) {
- cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
- @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
- @Override
- public void onCancel() {
- listener.cancel();
- }
- });
- }
-
- listener.startTimeout(GET_CURRENT_LOCATION_TIMEOUT_MS);
}
+
+ // a given listener could have been registered both with an executor and a looper, so we
+ // need to remove all possible cases
+ locationManager.removeUpdates(listener);
}
/**
@@ -212,9 +390,12 @@
}
}
- @GuardedBy("sGnssStatusListeners")
- private static final SimpleArrayMap<Object, Object> sGnssStatusListeners =
- new SimpleArrayMap<>();
+ // allows lazy instantiation since most processes do not use GNSS APIs
+ private static class GnssLazyLoader {
+ @GuardedBy("sGnssStatusListeners")
+ static final SimpleArrayMap<Object, Object> sGnssStatusListeners =
+ new SimpleArrayMap<>();
+ }
/**
* Registers a platform agnostic {@link GnssStatusCompat.Callback}. See
@@ -272,14 +453,14 @@
private static boolean registerGnssStatusCallback(final LocationManager locationManager,
Handler baseHandler, Executor executor, GnssStatusCompat.Callback callback) {
if (VERSION.SDK_INT >= VERSION_CODES.R) {
- synchronized (sGnssStatusListeners) {
+ synchronized (GnssLazyLoader.sGnssStatusListeners) {
GnssStatusTransport transport =
- (GnssStatusTransport) sGnssStatusListeners.get(callback);
+ (GnssStatusTransport) GnssLazyLoader.sGnssStatusListeners.get(callback);
if (transport == null) {
transport = new GnssStatusTransport(callback);
}
if (locationManager.registerGnssStatusCallback(executor, transport)) {
- sGnssStatusListeners.put(callback, transport);
+ GnssLazyLoader.sGnssStatusListeners.put(callback, transport);
return true;
} else {
return false;
@@ -287,9 +468,9 @@
}
} else if (VERSION.SDK_INT >= VERSION_CODES.N) {
Preconditions.checkArgument(baseHandler != null);
- synchronized (sGnssStatusListeners) {
+ synchronized (GnssLazyLoader.sGnssStatusListeners) {
PreRGnssStatusTransport transport =
- (PreRGnssStatusTransport) sGnssStatusListeners.get(callback);
+ (PreRGnssStatusTransport) GnssLazyLoader.sGnssStatusListeners.get(callback);
if (transport == null) {
transport = new PreRGnssStatusTransport(callback);
} else {
@@ -298,7 +479,7 @@
transport.register(executor);
if (locationManager.registerGnssStatusCallback(transport, baseHandler)) {
- sGnssStatusListeners.put(callback, transport);
+ GnssLazyLoader.sGnssStatusListeners.put(callback, transport);
return true;
} else {
return false;
@@ -306,9 +487,9 @@
}
} else {
Preconditions.checkArgument(baseHandler != null);
- synchronized (sGnssStatusListeners) {
+ synchronized (GnssLazyLoader.sGnssStatusListeners) {
GpsStatusTransport transport =
- (GpsStatusTransport) sGnssStatusListeners.get(callback);
+ (GpsStatusTransport) GnssLazyLoader.sGnssStatusListeners.get(callback);
if (transport == null) {
transport = new GpsStatusTransport(locationManager, callback);
} else {
@@ -317,13 +498,8 @@
transport.register(executor);
final GpsStatusTransport myTransport = transport;
- FutureTask<Boolean> task = new FutureTask<>(new Callable<Boolean>() {
- @RequiresPermission(ACCESS_FINE_LOCATION)
- @Override
- public Boolean call() {
- return locationManager.addGpsStatusListener(myTransport);
- }
- });
+ FutureTask<Boolean> task = new FutureTask<>(
+ () -> locationManager.addGpsStatusListener(myTransport));
if (Looper.myLooper() == baseHandler.getLooper()) {
task.run();
@@ -338,7 +514,7 @@
while (true) {
try {
if (task.get(remainingNanos, NANOSECONDS)) {
- sGnssStatusListeners.put(callback, myTransport);
+ GnssLazyLoader.sGnssStatusListeners.put(callback, myTransport);
return true;
} else {
return false;
@@ -378,26 +554,27 @@
public static void unregisterGnssStatusCallback(@NonNull LocationManager locationManager,
@NonNull GnssStatusCompat.Callback callback) {
if (VERSION.SDK_INT >= VERSION_CODES.R) {
- synchronized (sGnssStatusListeners) {
+ synchronized (GnssLazyLoader.sGnssStatusListeners) {
GnssStatusTransport transport =
- (GnssStatusTransport) sGnssStatusListeners.remove(callback);
+ (GnssStatusTransport) GnssLazyLoader.sGnssStatusListeners.remove(callback);
if (transport != null) {
locationManager.unregisterGnssStatusCallback(transport);
}
}
} else if (VERSION.SDK_INT >= VERSION_CODES.N) {
- synchronized (sGnssStatusListeners) {
+ synchronized (GnssLazyLoader.sGnssStatusListeners) {
PreRGnssStatusTransport transport =
- (PreRGnssStatusTransport) sGnssStatusListeners.remove(callback);
+ (PreRGnssStatusTransport) GnssLazyLoader.sGnssStatusListeners.remove(
+ callback);
if (transport != null) {
transport.unregister();
locationManager.unregisterGnssStatusCallback(transport);
}
}
} else {
- synchronized (sGnssStatusListeners) {
+ synchronized (GnssLazyLoader.sGnssStatusListeners) {
GpsStatusTransport transport =
- (GpsStatusTransport) sGnssStatusListeners.remove(callback);
+ (GpsStatusTransport) GnssLazyLoader.sGnssStatusListeners.remove(callback);
if (transport != null) {
transport.unregister();
locationManager.removeGpsStatusListener(transport);
@@ -408,6 +585,151 @@
private LocationManagerCompat() {}
+ private static class LocationListenerTransport implements LocationListener {
+
+ @Nullable volatile LocationListenerCompat mListener;
+ final Executor mExecutor;
+
+ LocationListenerTransport(@Nullable LocationListenerCompat listener, Executor executor) {
+ mListener = ObjectsCompat.requireNonNull(listener, "invalid null listener");
+ mExecutor = executor;
+ }
+
+ @GuardedBy("sLocationListeners")
+ public void register() {
+ List<WeakReference<LocationListenerTransport>> transports =
+ sLocationListeners.get(mListener);
+ if (transports == null) {
+ transports = new ArrayList<>(1);
+ sLocationListeners.put(mListener, transports);
+ } else {
+ // clean unreferenced transports
+ if (VERSION.SDK_INT >= VERSION_CODES.N) {
+ transports.removeIf(reference -> reference.get() == null);
+ } else {
+ Iterator<WeakReference<LocationListenerTransport>> it = transports.iterator();
+ while (it.hasNext()) {
+ if (it.next().get() == null) {
+ it.remove();
+ }
+ }
+ }
+ }
+
+ transports.add(new WeakReference<>(this));
+ }
+
+ @GuardedBy("sLocationListeners")
+ public boolean unregister() {
+ LocationListenerCompat listener = mListener;
+ if (listener == null) {
+ return false;
+ }
+ mListener = null;
+
+ List<WeakReference<LocationListenerTransport>> transports =
+ sLocationListeners.get(listener);
+ if (transports != null) {
+ transports.removeIf(reference -> reference.get() == null);
+ if (transports.isEmpty()) {
+ sLocationListeners.remove(listener);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onLocationChanged(@NonNull Location location) {
+ final LocationListenerCompat listener = mListener;
+ if (listener == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> {
+ if (mListener != listener) {
+ return;
+ }
+ listener.onLocationChanged(location);
+ });
+ }
+
+ @Override
+ public void onLocationChanged(@NonNull List<Location> locations) {
+ final LocationListenerCompat listener = mListener;
+ if (listener == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> {
+ if (mListener != listener) {
+ return;
+ }
+ listener.onLocationChanged(locations);
+ });
+ }
+
+ @Override
+ public void onFlushComplete(int requestCode) {
+ final LocationListenerCompat listener = mListener;
+ if (listener == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> {
+ if (mListener != listener) {
+ return;
+ }
+ listener.onFlushComplete(requestCode);
+ });
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ final LocationListenerCompat listener = mListener;
+ if (listener == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> {
+ if (mListener != listener) {
+ return;
+ }
+ listener.onStatusChanged(provider, status, extras);
+ });
+ }
+
+ @Override
+ public void onProviderEnabled(@NonNull String provider) {
+ final LocationListenerCompat listener = mListener;
+ if (listener == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> {
+ if (mListener != listener) {
+ return;
+ }
+ listener.onProviderEnabled(provider);
+ });
+ }
+
+ @Override
+ public void onProviderDisabled(@NonNull String provider) {
+ final LocationListenerCompat listener = mListener;
+ if (listener == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> {
+ if (mListener != listener) {
+ return;
+ }
+ listener.onProviderDisabled(provider);
+ });
+ }
+ }
+
@RequiresApi(VERSION_CODES.R)
private static class GnssStatusTransport extends GnssStatus.Callback {
@@ -468,14 +790,11 @@
return;
}
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onStarted();
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onStarted();
});
}
@@ -486,14 +805,11 @@
return;
}
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onStopped();
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onStopped();
});
}
@@ -504,14 +820,11 @@
return;
}
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onFirstFix(ttffMillis);
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onFirstFix(ttffMillis);
});
}
@@ -522,14 +835,11 @@
return;
}
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onSatelliteStatusChanged(GnssStatusCompat.wrap(status));
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onSatelliteStatusChanged(GnssStatusCompat.wrap(status));
});
}
}
@@ -569,39 +879,30 @@
switch (event) {
case GpsStatus.GPS_EVENT_STARTED:
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onStarted();
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onStarted();
});
break;
case GpsStatus.GPS_EVENT_STOPPED:
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onStopped();
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onStopped();
});
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
gpsStatus = mLocationManager.getGpsStatus(null);
if (gpsStatus != null) {
final int ttff = gpsStatus.getTimeToFirstFix();
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onFirstFix(ttff);
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onFirstFix(ttff);
});
}
break;
@@ -609,14 +910,11 @@
gpsStatus = mLocationManager.getGpsStatus(null);
if (gpsStatus != null) {
final GnssStatusCompat gnssStatus = GnssStatusCompat.wrap(gpsStatus);
- executor.execute(new Runnable() {
- @Override
- public void run() {
- if (mExecutor != executor) {
- return;
- }
- mCallback.onSatelliteStatusChanged(gnssStatus);
+ executor.execute(() -> {
+ if (mExecutor != executor) {
+ return;
}
+ mCallback.onSatelliteStatusChanged(gnssStatus);
});
}
break;
@@ -624,6 +922,24 @@
}
}
+ @RequiresApi(31)
+ private static class Api31Impl {
+ private Api31Impl() {}
+
+ @DoNotInline
+ static boolean hasProvider(LocationManager locationManager, @NonNull String provider) {
+ return locationManager.hasProvider(provider);
+ }
+
+ @DoNotInline
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ static void requestLocationUpdates(LocationManager locationManager,
+ @NonNull String provider, @NonNull LocationRequest locationRequest,
+ @NonNull Executor executor, @NonNull LocationListener listener) {
+ locationManager.requestLocationUpdates(provider, locationRequest, executor, listener);
+ }
+ }
+
@RequiresApi(30)
private static class Api30Impl {
private Api30Impl() {}
@@ -639,12 +955,7 @@
cancellationSignal.getCancellationSignalObject()
: null,
executor,
- new java.util.function.Consumer<Location>() {
- @Override
- public void accept(Location location) {
- consumer.accept(location);
- }
- });
+ consumer::accept);
}
}
@@ -747,12 +1058,7 @@
}
final Consumer<Location> consumer = mConsumer;
- mExecutor.execute(new Runnable() {
- @Override
- public void run() {
- consumer.accept(location);
- }
- });
+ mExecutor.execute(() -> consumer.accept(location));
cleanup();
}
diff --git a/core/core/src/main/java/androidx/core/location/LocationRequestCompat.java b/core/core/src/main/java/androidx/core/location/LocationRequestCompat.java
new file mode 100644
index 0000000..d84ae0d
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/location/LocationRequestCompat.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.location;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+
+import static java.lang.Math.min;
+
+import android.location.LocationRequest;
+import android.os.Build.VERSION;
+
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.core.util.Preconditions;
+import androidx.core.util.TimeUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Compatibility version of {@link LocationRequest}.
+ */
+public final class LocationRequestCompat {
+
+ /**
+ * Represents a passive only request. Such a request will not trigger any active locations or
+ * power usage itself, but may receive locations generated in response to other requests.
+ *
+ * @see LocationRequestCompat#getIntervalMillis()
+ */
+ public static final long PASSIVE_INTERVAL = LocationRequest.PASSIVE_INTERVAL;
+
+ /** @hide */
+ @RestrictTo(LIBRARY)
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({QUALITY_LOW_POWER, QUALITY_BALANCED_POWER_ACCURACY, QUALITY_HIGH_ACCURACY})
+ public @interface Quality {
+ }
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * providing very accurate locations at the expense of potentially increased power usage. Each
+ * location provider may interpret this field differently, but as an example, the network
+ * provider may choose to return only wifi based locations rather than cell based locations in
+ * order to have greater accuracy when this flag is present.
+ */
+ public static final int QUALITY_HIGH_ACCURACY = LocationRequest.QUALITY_HIGH_ACCURACY;
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * equally balancing power and accuracy constraints. Each location provider may interpret this
+ * field differently, but location providers will generally use their default behavior when this
+ * flag is present.
+ */
+ public static final int QUALITY_BALANCED_POWER_ACCURACY =
+ LocationRequest.QUALITY_BALANCED_POWER_ACCURACY;
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * providing less accurate locations in order to save power. Each location provider may
+ * interpret this field differently, but as an example, the network provider may choose to
+ * return cell based locations rather than wifi based locations in order to save power when this
+ * flag is present.
+ */
+ public static final int QUALITY_LOW_POWER = LocationRequest.QUALITY_LOW_POWER;
+
+ private static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1;
+
+ private static Method sCreateFromDeprecatedProviderMethod;
+ private static Method sSetQualityMethod;
+ private static Method sSetFastestIntervalMethod;
+ private static Method sSetNumUpdatesMethod;
+ private static Method sSetExpireInMethod;
+
+ @Quality
+ final int mQuality;
+ final long mIntervalMillis;
+ final long mMinUpdateIntervalMillis;
+ final long mDurationMillis;
+ final int mMaxUpdates;
+ final float mMinUpdateDistanceMeters;
+ final long mMaxUpdateDelayMillis;
+
+ LocationRequestCompat(
+ long intervalMillis,
+ @Quality int quality,
+ long durationMillis,
+ int maxUpdates,
+ long minUpdateIntervalMillis,
+ float minUpdateDistanceMeters,
+ long maxUpdateDelayMillis) {
+ mIntervalMillis = intervalMillis;
+ mQuality = quality;
+ mMinUpdateIntervalMillis = minUpdateIntervalMillis;
+ mDurationMillis = durationMillis;
+ mMaxUpdates = maxUpdates;
+ mMinUpdateDistanceMeters = minUpdateDistanceMeters;
+ mMaxUpdateDelayMillis = maxUpdateDelayMillis;
+ }
+
+ /**
+ * Returns the quality hint for this location request. The quality hint informs the provider how
+ * it should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
+ * location request.
+ */
+ public @Quality int getQuality() {
+ return mQuality;
+ }
+
+ /**
+ * Returns the desired interval of location updates, or {@link #PASSIVE_INTERVAL} if this is a
+ * passive, no power request. A passive request will not actively generate location updates
+ * (and thus will not be power blamed for location), but may receive location updates generated
+ * as a result of other location requests. A passive request must always have an explicit
+ * minimum update interval set.
+ *
+ * <p>Locations may be available at a faster interval than specified here, see
+ * {@link #getMinUpdateIntervalMillis()} for the behavior in that case.
+ */
+ public @IntRange(from = 0) long getIntervalMillis() {
+ return mIntervalMillis;
+ }
+
+ /**
+ * Returns the minimum update interval. If location updates are available faster than the
+ * request interval then locations will only be updated if the minimum update interval has
+ * expired since the last location update.
+ *
+ * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
+ * minimum update interval, so you need not worry about updates blocked simply because they
+ * arrived a fraction of a second earlier than expected.
+ *
+ * @return the minimum update interval
+ */
+ public @IntRange(from = 0) long getMinUpdateIntervalMillis() {
+ if (mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
+ return mIntervalMillis;
+ } else {
+ return mMinUpdateIntervalMillis;
+ }
+ }
+
+ /**
+ * Returns the duration for which location will be provided before the request is automatically
+ * removed. A duration of <code>Long.MAX_VALUE</code> represents an unlimited duration.
+ *
+ * @return the duration for which location will be provided
+ */
+ public @IntRange(from = 1) long getDurationMillis() {
+ return mDurationMillis;
+ }
+
+ /**
+ * Returns the maximum number of location updates for this request before the request is
+ * automatically removed. A max updates value of <code>Integer.MAX_VALUE</code> represents an
+ * unlimited number of updates.
+ */
+ public @IntRange(from = 1, to = Integer.MAX_VALUE) int getMaxUpdates() {
+ return mMaxUpdates;
+ }
+
+ /**
+ * Returns the minimum distance between location updates. If a potential location update is
+ * closer to the last location update than the minimum update distance, then the potential
+ * location update will not occur. A value of 0 meters implies that no location update will ever
+ * be rejected due to failing this constraint.
+ *
+ * @return the minimum distance between location updates
+ */
+ public @FloatRange(from = 0, to = Float.MAX_VALUE) float getMinUpdateDistanceMeters() {
+ return mMinUpdateDistanceMeters;
+ }
+
+ /**
+ * Returns the maximum time any location update may be delayed, and thus grouped with following
+ * updates to enable location batching. If the maximum update delay is equal to or greater than
+ * twice the interval, then location providers may provide batched results. The maximum batch
+ * size is the maximum update delay divided by the interval. Not all devices or location
+ * providers support batching, and use of this parameter does not guarantee that the client will
+ * see batched results, or that batched results will always be of the maximum size.
+ *
+ * When available, batching can provide substantial power savings to the device, and clients are
+ * encouraged to take advantage where appropriate for the use case.
+ *
+ * @return the maximum time by which a location update may be delayed
+ * @see LocationListenerCompat#onLocationChanged(java.util.List)
+ */
+ public @IntRange(from = 0) long getMaxUpdateDelayMillis() {
+ return mMaxUpdateDelayMillis;
+ }
+
+ @RequiresApi(31)
+ @NonNull
+ LocationRequest toLocationRequest() {
+ return new LocationRequest.Builder(mIntervalMillis)
+ .setQuality(mQuality)
+ .setMinUpdateIntervalMillis(mMinUpdateIntervalMillis)
+ .setDurationMillis(mDurationMillis)
+ .setMaxUpdates(mMaxUpdates)
+ .setMinUpdateDistanceMeters(mMinUpdateDistanceMeters)
+ .setMaxUpdateDelayMillis(mMaxUpdateDelayMillis)
+ .build();
+ }
+
+ @SuppressWarnings("JavaReflectionMemberAccess")
+ @RequiresApi(19)
+ @NonNull
+ LocationRequest toLocationRequest(@NonNull String provider)
+ throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ if (VERSION.SDK_INT >= 31) {
+ return toLocationRequest();
+ } else if (VERSION.SDK_INT >= 19) {
+ if (sCreateFromDeprecatedProviderMethod == null) {
+ sCreateFromDeprecatedProviderMethod = LocationRequest.class.getDeclaredMethod(
+ "createFromDeprecatedProvider", String.class, long.class, float.class,
+ boolean.class);
+ sCreateFromDeprecatedProviderMethod.setAccessible(true);
+ }
+
+ LocationRequest request =
+ (LocationRequest) sCreateFromDeprecatedProviderMethod.invoke(null, provider,
+ mIntervalMillis,
+ mMinUpdateDistanceMeters, false);
+ if (request == null) {
+ // should never happen
+ throw new InvocationTargetException(new NullPointerException());
+ }
+
+ if (sSetQualityMethod == null) {
+ sSetQualityMethod = LocationRequest.class.getDeclaredMethod(
+ "setQuality", int.class);
+ sSetQualityMethod.setAccessible(true);
+ }
+ sSetQualityMethod.invoke(request, mQuality);
+
+ if (getMinUpdateIntervalMillis() != mIntervalMillis) {
+ if (sSetFastestIntervalMethod == null) {
+ sSetFastestIntervalMethod = LocationRequest.class.getDeclaredMethod(
+ "setFastestInterval", long.class);
+ sSetFastestIntervalMethod.setAccessible(true);
+ }
+
+ sSetFastestIntervalMethod.invoke(request, mMinUpdateIntervalMillis);
+ }
+
+ if (mMaxUpdates < Integer.MAX_VALUE) {
+ if (sSetNumUpdatesMethod == null) {
+ sSetNumUpdatesMethod = LocationRequest.class.getDeclaredMethod(
+ "setNumUpdates", int.class);
+ sSetNumUpdatesMethod.setAccessible(true);
+ }
+
+ sSetNumUpdatesMethod.invoke(request, mMaxUpdates);
+ }
+
+ if (mDurationMillis < Long.MAX_VALUE) {
+ if (sSetExpireInMethod == null) {
+ sSetExpireInMethod = LocationRequest.class.getDeclaredMethod(
+ "setExpireIn", long.class);
+ sSetExpireInMethod.setAccessible(true);
+ }
+
+ sSetExpireInMethod.invoke(request, mDurationMillis);
+ }
+ return request;
+ }
+
+ throw new NoClassDefFoundError();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof LocationRequestCompat)) {
+ return false;
+ }
+
+ LocationRequestCompat that = (LocationRequestCompat) o;
+ return mQuality == that.mQuality && mIntervalMillis == that.mIntervalMillis
+ && mMinUpdateIntervalMillis == that.mMinUpdateIntervalMillis
+ && mDurationMillis == that.mDurationMillis && mMaxUpdates == that.mMaxUpdates
+ && Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
+ && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mQuality;
+ result = 31 * result + (int) (mIntervalMillis ^ (mIntervalMillis >>> 32));
+ result = 31 * result + (int) (mMinUpdateIntervalMillis ^ (mMinUpdateIntervalMillis >>> 32));
+ return result;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append("Request[");
+ if (mIntervalMillis != PASSIVE_INTERVAL) {
+ s.append("@");
+ TimeUtils.formatDuration(mIntervalMillis, s);
+
+ switch (mQuality) {
+ case QUALITY_HIGH_ACCURACY:
+ s.append(" HIGH_ACCURACY");
+ break;
+ case QUALITY_BALANCED_POWER_ACCURACY:
+ s.append(" BALANCED");
+ break;
+ case QUALITY_LOW_POWER:
+ s.append(" LOW_POWER");
+ break;
+ }
+ } else {
+ s.append("PASSIVE");
+ }
+ if (mDurationMillis != Long.MAX_VALUE) {
+ s.append(", duration=");
+ TimeUtils.formatDuration(mDurationMillis, s);
+ }
+ if (mMaxUpdates != Integer.MAX_VALUE) {
+ s.append(", maxUpdates=").append(mMaxUpdates);
+ }
+ if (mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL
+ && mMinUpdateIntervalMillis < mIntervalMillis) {
+ s.append(", minUpdateInterval=");
+ TimeUtils.formatDuration(mMinUpdateIntervalMillis, s);
+ }
+ if (mMinUpdateDistanceMeters > 0.0) {
+ s.append(", minUpdateDistance=").append(mMinUpdateDistanceMeters);
+ }
+ if (mMaxUpdateDelayMillis / 2 > mIntervalMillis) {
+ s.append(", maxUpdateDelay=");
+ TimeUtils.formatDuration(mMaxUpdateDelayMillis, s);
+ }
+ s.append(']');
+ return s.toString();
+ }
+
+ /**
+ * A builder class for {@link LocationRequestCompat}.
+ */
+ public static final class Builder {
+
+ private long mIntervalMillis;
+ private @Quality int mQuality;
+ private long mDurationMillis;
+ private int mMaxUpdates;
+ private long mMinUpdateIntervalMillis;
+ private float mMinUpdateDistanceMeters;
+ private long mMaxUpdateDelayMillis;
+
+ /**
+ * Creates a new Builder with the given interval. See {@link #setIntervalMillis(long)} for
+ * more information on the interval. Note that the defaults for various Builder parameters
+ * may be different from the defaults for the framework {@link LocationRequest}.
+ */
+ public Builder(long intervalMillis) {
+ // gives us a range check
+ setIntervalMillis(intervalMillis);
+
+ mQuality = QUALITY_BALANCED_POWER_ACCURACY;
+ mDurationMillis = Long.MAX_VALUE;
+ mMaxUpdates = Integer.MAX_VALUE;
+ mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
+ mMinUpdateDistanceMeters = 0;
+ mMaxUpdateDelayMillis = 0;
+ }
+
+ /**
+ * Creates a new Builder with all parameters copied from the given location request.
+ */
+ public Builder(@NonNull LocationRequestCompat locationRequest) {
+ mIntervalMillis = locationRequest.mIntervalMillis;
+ mQuality = locationRequest.mQuality;
+ mDurationMillis = locationRequest.mDurationMillis;
+ mMaxUpdates = locationRequest.mMaxUpdates;
+ mMinUpdateIntervalMillis = locationRequest.mMinUpdateIntervalMillis;
+ mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
+ mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
+ }
+
+ /**
+ * Sets the request interval. The request interval may be set to {@link #PASSIVE_INTERVAL}
+ * which indicates this request will not actively generate location updates (and thus will
+ * not be power blamed for location), but may receive location updates generated as a result
+ * of other location requests. A passive request must always have an explicit minimum
+ * update interval set.
+ *
+ * <p>Locations may be available at a faster interval than specified here, see
+ * {@link #setMinUpdateIntervalMillis(long)} for the behavior in that case.
+ *
+ * <p class="note"><strong>Note:</strong> On platforms below Android 12, using the
+ * {@link #PASSIVE_INTERVAL} will not result in a truly passive request, but a request with
+ * an extremely long interval. In most cases, this is effectively the same as a passive
+ * request, but this may occasionally result in an initial location calculation for which
+ * the client will be blamed.
+ */
+ public @NonNull Builder setIntervalMillis(@IntRange(from = 0) long intervalMillis) {
+ mIntervalMillis = Preconditions.checkArgumentInRange(intervalMillis, 0, Long
+ .MAX_VALUE,
+ "intervalMillis");
+ return this;
+ }
+
+ /**
+ * Sets the request quality. The quality is a hint to providers on how they should weigh
+ * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and
+ * lower accuracy locations may cost less power to produce. Defaults to
+ * {@link #QUALITY_BALANCED_POWER_ACCURACY}.
+ */
+ public @NonNull Builder setQuality(@Quality int quality) {
+ Preconditions.checkArgument(
+ quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY
+ || quality == QUALITY_HIGH_ACCURACY,
+ "quality must be a defined QUALITY constant, not %d", quality);
+ mQuality = quality;
+ return this;
+ }
+
+ /**
+ * Sets the duration this request will continue before being automatically removed. Defaults
+ * to <code>Long.MAX_VALUE</code>, which represents an unlimited duration.
+ *
+ * <p class="note"><strong>Note:</strong> This parameter will be ignored on platforms below
+ * Android Kitkat, and the request will not be removed after the duration expires.
+ */
+ public @NonNull Builder setDurationMillis(@IntRange(from = 1) long durationMillis) {
+ mDurationMillis = Preconditions.checkArgumentInRange(durationMillis, 1, Long
+ .MAX_VALUE,
+ "durationMillis");
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of location updates for this request before this request is
+ * automatically removed. Defaults to <code>Integer.MAX_VALUE</code>, which represents an
+ * unlimited number of updates.
+ */
+ public @NonNull Builder setMaxUpdates(
+ @IntRange(from = 1, to = Integer.MAX_VALUE) int maxUpdates) {
+ mMaxUpdates = Preconditions.checkArgumentInRange(maxUpdates, 1, Integer.MAX_VALUE,
+ "maxUpdates");
+ return this;
+ }
+
+ /**
+ * Sets an explicit minimum update interval. If location updates are available faster than
+ * the request interval then an update will only occur if the minimum update interval has
+ * expired since the last location update. Defaults to no explicit minimum update interval
+ * set, which means the minimum update interval is the same as the interval.
+ *
+ * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
+ * minimum update interval, so you need not worry about updates blocked simply because they
+ * arrived a fraction of a second earlier than expected.
+ *
+ * <p class="note"><strong>Note:</strong> When {@link #build()} is invoked, the minimum of
+ * the interval and the minimum update interval will be used as the minimum update interval
+ * of the built request.
+ */
+ public @NonNull Builder setMinUpdateIntervalMillis(
+ @IntRange(from = 0) long minUpdateIntervalMillis) {
+ mMinUpdateIntervalMillis = Preconditions.checkArgumentInRange(minUpdateIntervalMillis,
+ 0, Long.MAX_VALUE, "minUpdateIntervalMillis");
+ return this;
+ }
+
+ /**
+ * Clears an explicitly set minimum update interval and reverts to an implicit minimum
+ * update interval (ie, the minimum update interval is the same value as the interval).
+ */
+ public @NonNull Builder clearMinUpdateIntervalMillis() {
+ mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
+ return this;
+ }
+
+ /**
+ * Sets the minimum update distance between location updates. If a potential location
+ * update is closer to the last location update than the minimum update distance, then
+ * the potential location update will not occur. Defaults to 0, which represents no minimum
+ * update distance.
+ */
+ public @NonNull Builder setMinUpdateDistanceMeters(
+ @FloatRange(from = 0, to = Float.MAX_VALUE) float minUpdateDistanceMeters) {
+ mMinUpdateDistanceMeters = minUpdateDistanceMeters;
+ mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minUpdateDistanceMeters,
+ 0, Float.MAX_VALUE, "minUpdateDistanceMeters");
+ return this;
+ }
+
+ /**
+ * Sets the maximum time any location update may be delayed, and thus grouped with following
+ * updates to enable location batching. If the maximum update delay is equal to or greater
+ * than twice the interval, then location providers may provide batched results. Defaults to
+ * 0, which represents no batching allowed.
+ */
+ public @NonNull Builder setMaxUpdateDelayMillis(
+ @IntRange(from = 0) long maxUpdateDelayMillis) {
+ mMaxUpdateDelayMillis = maxUpdateDelayMillis;
+ mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0,
+ Long.MAX_VALUE, "maxUpdateDelayMillis");
+ return this;
+ }
+
+ /**
+ * Builds a location request from this builder. If an explicit minimum update interval is
+ * set, the minimum update interval of the location request will be the minimum of the
+ * interval and minimum update interval.
+ *
+ * <p>If building a passive request then you must have set an explicit minimum update
+ * interval.
+ */
+ public @NonNull LocationRequestCompat build() {
+ Preconditions.checkState(mIntervalMillis != PASSIVE_INTERVAL
+ || mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL,
+ "passive location requests must have an explicit minimum update interval");
+
+ return new LocationRequestCompat(
+ mIntervalMillis,
+ mQuality,
+ mDurationMillis,
+ mMaxUpdates,
+ min(mMinUpdateIntervalMillis, mIntervalMillis),
+ mMinUpdateDistanceMeters,
+ mMaxUpdateDelayMillis);
+ }
+ }
+}
diff --git a/core/core/src/main/java/androidx/core/util/Preconditions.java b/core/core/src/main/java/androidx/core/util/Preconditions.java
index 9a759f8..ce979e0 100644
--- a/core/core/src/main/java/androidx/core/util/Preconditions.java
+++ b/core/core/src/main/java/androidx/core/util/Preconditions.java
@@ -54,6 +54,24 @@
}
/**
+ * Ensures that an expression checking an argument is true.
+ *
+ * @param expression the expression to check
+ * @param messageTemplate a printf-style message template to use if the check fails; will
+ * be converted to a string using {@link String#format(String, Object...)}
+ * @param messageArgs arguments for {@code messageTemplate}
+ * @throws IllegalArgumentException if {@code expression} is false
+ */
+ public static void checkArgument(
+ final boolean expression,
+ final @NonNull String messageTemplate,
+ final @NonNull Object... messageArgs) {
+ if (!expression) {
+ throw new IllegalArgumentException(String.format(messageTemplate, messageArgs));
+ }
+ }
+
+ /**
* Ensures that an string reference passed as a parameter to the calling
* method is not empty.
*
@@ -237,6 +255,87 @@
return value;
}
+ /**
+ * Ensures that the argument long value is within the inclusive range.
+ *
+ * @param value a long value
+ * @param lower the lower endpoint of the inclusive range
+ * @param upper the upper endpoint of the inclusive range
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated long value
+ *
+ * @throws IllegalArgumentException if {@code value} was not within the range
+ */
+ public static long checkArgumentInRange(long value, long lower, long upper,
+ @NonNull String valueName) {
+ if (value < lower) {
+ throw new IllegalArgumentException(
+ String.format(Locale.US,
+ "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
+ } else if (value > upper) {
+ throw new IllegalArgumentException(
+ String.format(Locale.US,
+ "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that the argument float value is within the inclusive range.
+ *
+ * @param value a float value
+ * @param lower the lower endpoint of the inclusive range
+ * @param upper the upper endpoint of the inclusive range
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated float value
+ *
+ * @throws IllegalArgumentException if {@code value} was not within the range
+ */
+ public static float checkArgumentInRange(float value, float lower, float upper,
+ @NonNull String valueName) {
+ if (value < lower) {
+ throw new IllegalArgumentException(
+ String.format(Locale.US,
+ "%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
+ } else if (value > upper) {
+ throw new IllegalArgumentException(
+ String.format(Locale.US,
+ "%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that the argument double value is within the inclusive range.
+ *
+ * @param value a double value
+ * @param lower the lower endpoint of the inclusive range
+ * @param upper the upper endpoint of the inclusive range
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated double value
+ *
+ * @throws IllegalArgumentException if {@code value} was not within the range
+ */
+ public static double checkArgumentInRange(double value, double lower, double upper,
+ @NonNull String valueName) {
+ if (value < lower) {
+ throw new IllegalArgumentException(
+ String.format(Locale.US,
+ "%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
+ } else if (value > upper) {
+ throw new IllegalArgumentException(
+ String.format(Locale.US,
+ "%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
+ }
+
+ return value;
+ }
+
private Preconditions() {
}
}
diff --git a/core/core/src/main/java/androidx/core/view/ContentInfoCompat.java b/core/core/src/main/java/androidx/core/view/ContentInfoCompat.java
index ec5f385..e29026b 100644
--- a/core/core/src/main/java/androidx/core/view/ContentInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ContentInfoCompat.java
@@ -19,12 +19,16 @@
import android.content.ClipData;
import android.content.ClipDescription;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.util.Pair;
+import android.view.ContentInfo;
+import androidx.annotation.DoNotInline;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.util.Preconditions;
@@ -32,12 +36,12 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
/**
- * Holds all the relevant data for a request to {@link OnReceiveContentListener}.
+ * Holds all the relevant data for a request to {@link OnReceiveContentListener}. This is a
+ * backward-compatible wrapper for the platform class {@link ContentInfo}.
*/
-// This class has the "Compat" suffix because it will integrate with (ie, wrap) the SDK API once
-// that is available.
public final class ContentInfoCompat {
/**
@@ -47,7 +51,8 @@
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
- @IntDef(value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD, SOURCE_DRAG_AND_DROP})
+ @IntDef(value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD, SOURCE_DRAG_AND_DROP,
+ SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
@Retention(RetentionPolicy.SOURCE)
public @interface Source {
}
@@ -77,6 +82,19 @@
public static final int SOURCE_DRAG_AND_DROP = 3;
/**
+ * Specifies that the operation was triggered by the autofill framework. See
+ * https://developer.android.com/guide/topics/text/autofill for more info.
+ */
+ public static final int SOURCE_AUTOFILL = 4;
+
+ /**
+ * Specifies that the operation was triggered by a result from a
+ * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
+ * menu.
+ */
+ public static final int SOURCE_PROCESS_TEXT = 5;
+
+ /**
* Returns the symbolic name of the given source.
*
* @hide
@@ -89,6 +107,8 @@
case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
+ case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
+ case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
}
return String.valueOf(source);
}
@@ -124,35 +144,46 @@
}
@NonNull
- final ClipData mClip;
- @Source
- final int mSource;
- @Flags
- final int mFlags;
- @Nullable
- final Uri mLinkUri;
- @Nullable
- final Bundle mExtras;
+ private final Compat mCompat;
- ContentInfoCompat(Builder b) {
- this.mClip = Preconditions.checkNotNull(b.mClip);
- this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_DRAG_AND_DROP,
- "source");
- this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
- this.mLinkUri = b.mLinkUri;
- this.mExtras = b.mExtras;
+ ContentInfoCompat(@NonNull Compat compat) {
+ mCompat = compat;
+ }
+
+ /**
+ * Provides a backward-compatible wrapper for {@link ContentInfo}.
+ *
+ * <p>This method is not supported on devices running SDK <= 30 since the platform
+ * class will not be available.
+ *
+ * @param platContentInfo platform class to wrap, must not be null
+ * @return wrapped class
+ */
+ @RequiresApi(31)
+ @NonNull
+ public static ContentInfoCompat toContentInfoCompat(@NonNull ContentInfo platContentInfo) {
+ return new ContentInfoCompat(new Compat31Impl(platContentInfo));
+ }
+
+ /**
+ * Provides the {@link ContentInfo} represented by this object.
+ *
+ * <p>This method is not supported on devices running SDK <= 30 since the platform
+ * class will not be available.
+ *
+ * @return platform class object
+ * @see ContentInfoCompat#toContentInfoCompat
+ */
+ @RequiresApi(31)
+ @NonNull
+ public ContentInfo toContentInfo() {
+ return mCompat.getWrapped();
}
@NonNull
@Override
public String toString() {
- return "ContentInfoCompat{"
- + "clip=" + mClip.getDescription()
- + ", source=" + sourceToString(mSource)
- + ", flags=" + flagsToString(mFlags)
- + (mLinkUri == null ? "" : ", hasLinkUri(" + mLinkUri.toString().length() + ")")
- + (mExtras == null ? "" : ", hasExtras")
- + "}";
+ return mCompat.toString();
}
/**
@@ -160,7 +191,7 @@
*/
@NonNull
public ClipData getClip() {
- return mClip;
+ return mCompat.getClip();
}
/**
@@ -169,7 +200,7 @@
*/
@Source
public int getSource() {
- return mSource;
+ return mCompat.getSource();
}
/**
@@ -177,7 +208,7 @@
*/
@Flags
public int getFlags() {
- return mFlags;
+ return mCompat.getFlags();
}
/**
@@ -188,7 +219,7 @@
*/
@Nullable
public Uri getLinkUri() {
- return mLinkUri;
+ return mCompat.getLinkUri();
}
/**
@@ -198,7 +229,7 @@
*/
@Nullable
public Bundle getExtras() {
- return mExtras;
+ return mCompat.getExtras();
}
/**
@@ -220,37 +251,51 @@
@NonNull
public Pair<ContentInfoCompat, ContentInfoCompat> partition(
@NonNull androidx.core.util.Predicate<ClipData.Item> itemPredicate) {
- if (mClip.getItemCount() == 1) {
- boolean matched = itemPredicate.test(mClip.getItemAt(0));
+ ClipData clip = mCompat.getClip();
+ if (clip.getItemCount() == 1) {
+ boolean matched = itemPredicate.test(clip.getItemAt(0));
return Pair.create(matched ? this : null, matched ? null : this);
}
- ArrayList<ClipData.Item> acceptedItems = new ArrayList<>();
- ArrayList<ClipData.Item> remainingItems = new ArrayList<>();
- for (int i = 0; i < mClip.getItemCount(); i++) {
- ClipData.Item item = mClip.getItemAt(i);
+ Pair<ClipData, ClipData> split = ContentInfoCompat.partition(clip, itemPredicate);
+ if (split.first == null) {
+ return Pair.create(null, this);
+ } else if (split.second == null) {
+ return Pair.create(this, null);
+ }
+ return Pair.create(
+ new ContentInfoCompat.Builder(this).setClip(split.first).build(),
+ new ContentInfoCompat.Builder(this).setClip(split.second).build());
+ }
+
+ @NonNull
+ static Pair<ClipData, ClipData> partition(@NonNull ClipData clip,
+ @NonNull androidx.core.util.Predicate<ClipData.Item> itemPredicate) {
+ ArrayList<ClipData.Item> acceptedItems = null;
+ ArrayList<ClipData.Item> remainingItems = null;
+ for (int i = 0; i < clip.getItemCount(); i++) {
+ ClipData.Item item = clip.getItemAt(i);
if (itemPredicate.test(item)) {
+ acceptedItems = (acceptedItems == null) ? new ArrayList<>() : acceptedItems;
acceptedItems.add(item);
} else {
+ remainingItems = (remainingItems == null) ? new ArrayList<>() : remainingItems;
remainingItems.add(item);
}
}
- if (acceptedItems.isEmpty()) {
- return Pair.create(null, this);
+ if (acceptedItems == null) {
+ return Pair.create(null, clip);
}
- if (remainingItems.isEmpty()) {
- return Pair.create(this, null);
+ if (remainingItems == null) {
+ return Pair.create(clip, null);
}
- ContentInfoCompat accepted = new Builder(this)
- .setClip(buildClipData(mClip.getDescription(), acceptedItems))
- .build();
- ContentInfoCompat remaining = new Builder(this)
- .setClip(buildClipData(mClip.getDescription(), remainingItems))
- .build();
- return Pair.create(accepted, remaining);
+ return Pair.create(
+ buildClipData(clip.getDescription(), acceptedItems),
+ buildClipData(clip.getDescription(), remainingItems));
}
- private static ClipData buildClipData(ClipDescription description,
- List<ClipData.Item> items) {
+ @NonNull
+ static ClipData buildClipData(@NonNull ClipDescription description,
+ @NonNull List<ClipData.Item> items) {
ClipData clip = new ClipData(new ClipDescription(description), items.get(0));
for (int i = 1; i < items.size(); i++) {
clip.addItem(items.get(i));
@@ -259,29 +304,205 @@
}
/**
+ * Partitions content based on the given predicate.
+ *
+ * <p>This function classifies the content and organizes it into a pair, grouping the items
+ * that matched vs didn't match the predicate.
+ *
+ * <p>Except for the {@link ClipData} items, the returned objects will contain all the same
+ * metadata as the passed-in {@link ContentInfo}.
+ *
+ * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which
+ * partition to place it into.
+ * @return A pair containing the partitioned content. The pair's first object will have the
+ * content that matched the predicate, or null if none of the items matched. The pair's
+ * second object will have the content that didn't match the predicate, or null if all of
+ * the items matched.
+ */
+ @RequiresApi(31)
+ @NonNull
+ public static Pair<ContentInfo, ContentInfo> partition(@NonNull ContentInfo payload,
+ @NonNull Predicate<ClipData.Item> itemPredicate) {
+ return Api31Impl.partition(payload, itemPredicate);
+ }
+
+ @RequiresApi(31)
+ private static final class Api31Impl {
+ private Api31Impl() {}
+
+ @DoNotInline
+ @NonNull
+ public static Pair<ContentInfo, ContentInfo> partition(@NonNull ContentInfo payload,
+ @NonNull Predicate<ClipData.Item> itemPredicate) {
+ ClipData clip = payload.getClip();
+ if (clip.getItemCount() == 1) {
+ boolean matched = itemPredicate.test(clip.getItemAt(0));
+ return Pair.create(matched ? payload : null, matched ? null : payload);
+ }
+ Pair<ClipData, ClipData> split = ContentInfoCompat.partition(clip, itemPredicate::test);
+ if (split.first == null) {
+ return Pair.create(null, payload);
+ } else if (split.second == null) {
+ return Pair.create(payload, null);
+ }
+ return Pair.create(
+ new ContentInfo.Builder(payload).setClip(split.first).build(),
+ new ContentInfo.Builder(payload).setClip(split.second).build());
+ }
+ }
+
+ private interface Compat {
+ @Nullable
+ ContentInfo getWrapped();
+ @NonNull
+ ClipData getClip();
+ @Source
+ int getSource();
+ @Flags
+ int getFlags();
+ @Nullable
+ Uri getLinkUri();
+ @Nullable
+ Bundle getExtras();
+ }
+
+ private static final class CompatImpl implements Compat {
+ @NonNull
+ private final ClipData mClip;
+ @Source
+ private final int mSource;
+ @Flags
+ private final int mFlags;
+ @Nullable
+ private final Uri mLinkUri;
+ @Nullable
+ private final Bundle mExtras;
+
+ CompatImpl(BuilderCompatImpl b) {
+ mClip = Preconditions.checkNotNull(b.mClip);
+ mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
+ "source");
+ mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
+ mLinkUri = b.mLinkUri;
+ mExtras = b.mExtras;
+ }
+
+ @Nullable
+ @Override
+ public ContentInfo getWrapped() {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public ClipData getClip() {
+ return mClip;
+ }
+
+ @Source
+ @Override
+ public int getSource() {
+ return mSource;
+ }
+
+ @Flags
+ @Override
+ public int getFlags() {
+ return mFlags;
+ }
+
+ @Nullable
+ @Override
+ public Uri getLinkUri() {
+ return mLinkUri;
+ }
+
+ @Nullable
+ @Override
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "ContentInfoCompat{"
+ + "clip=" + mClip.getDescription()
+ + ", source=" + sourceToString(mSource)
+ + ", flags=" + flagsToString(mFlags)
+ + (mLinkUri == null ? "" : ", hasLinkUri(" + mLinkUri.toString().length() + ")")
+ + (mExtras == null ? "" : ", hasExtras")
+ + "}";
+ }
+ }
+
+ private static final class Compat31Impl implements Compat {
+ @NonNull
+ private final ContentInfo mWrapped;
+
+ Compat31Impl(@NonNull ContentInfo wrapped) {
+ mWrapped = Preconditions.checkNotNull(wrapped);
+ }
+
+ @NonNull
+ @Override
+ public ContentInfo getWrapped() {
+ return mWrapped;
+ }
+
+ @NonNull
+ @Override
+ public ClipData getClip() {
+ return mWrapped.getClip();
+ }
+
+ @Source
+ @Override
+ public int getSource() {
+ return mWrapped.getSource();
+ }
+
+ @Flags
+ @Override
+ public int getFlags() {
+ return mWrapped.getFlags();
+ }
+
+ @Nullable
+ @Override
+ public Uri getLinkUri() {
+ return mWrapped.getLinkUri();
+ }
+
+ @Nullable
+ @Override
+ public Bundle getExtras() {
+ return mWrapped.getExtras();
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "ContentInfoCompat{" + mWrapped + "}";
+ }
+ }
+
+ /**
* Builder for {@link ContentInfoCompat}.
*/
public static final class Builder {
@NonNull
- ClipData mClip;
- @Source
- int mSource;
- @Flags
- int mFlags;
- @Nullable
- Uri mLinkUri;
- @Nullable
- Bundle mExtras;
+ private final BuilderCompat mBuilderCompat;
/**
- * Creates a new builder initialized with the data from the given builder.
+ * Creates a new builder initialized with the data from the given object (shallow copy).
*/
public Builder(@NonNull ContentInfoCompat other) {
- mClip = other.mClip;
- mSource = other.mSource;
- mFlags = other.mFlags;
- mLinkUri = other.mLinkUri;
- mExtras = other.mExtras;
+ if (Build.VERSION.SDK_INT >= 31) {
+ mBuilderCompat = new BuilderCompat31Impl(other);
+ } else {
+ mBuilderCompat = new BuilderCompatImpl(other);
+ }
}
/**
@@ -291,8 +512,11 @@
* @param source The source of the operation. See {@code SOURCE_} constants.
*/
public Builder(@NonNull ClipData clip, @Source int source) {
- mClip = clip;
- mSource = source;
+ if (Build.VERSION.SDK_INT >= 31) {
+ mBuilderCompat = new BuilderCompat31Impl(clip, source);
+ } else {
+ mBuilderCompat = new BuilderCompatImpl(clip, source);
+ }
}
/**
@@ -303,7 +527,7 @@
*/
@NonNull
public Builder setClip(@NonNull ClipData clip) {
- mClip = clip;
+ mBuilderCompat.setClip(clip);
return this;
}
@@ -315,7 +539,7 @@
*/
@NonNull
public Builder setSource(@Source int source) {
- mSource = source;
+ mBuilderCompat.setSource(source);
return this;
}
@@ -328,7 +552,7 @@
*/
@NonNull
public Builder setFlags(@Flags int flags) {
- mFlags = flags;
+ mBuilderCompat.setFlags(flags);
return this;
}
@@ -341,7 +565,7 @@
*/
@NonNull
public Builder setLinkUri(@Nullable Uri linkUri) {
- mLinkUri = linkUri;
+ mBuilderCompat.setLinkUri(linkUri);
return this;
}
@@ -353,7 +577,7 @@
*/
@NonNull
public Builder setExtras(@Nullable Bundle extras) {
- mExtras = extras;
+ mBuilderCompat.setExtras(extras);
return this;
}
@@ -362,7 +586,119 @@
*/
@NonNull
public ContentInfoCompat build() {
- return new ContentInfoCompat(this);
+ return mBuilderCompat.build();
+ }
+ }
+
+ private interface BuilderCompat {
+ void setClip(@NonNull ClipData clip);
+ void setSource(@Source int source);
+ void setFlags(@Flags int flags);
+ void setLinkUri(@Nullable Uri linkUri);
+ void setExtras(@Nullable Bundle extras);
+ @NonNull
+ ContentInfoCompat build();
+ }
+
+ private static final class BuilderCompatImpl implements BuilderCompat {
+ @NonNull
+ ClipData mClip;
+ @Source
+ int mSource;
+ @Flags
+ int mFlags;
+ @Nullable
+ Uri mLinkUri;
+ @Nullable
+ Bundle mExtras;
+
+ BuilderCompatImpl(@NonNull ClipData clip, int source) {
+ mClip = clip;
+ mSource = source;
+ }
+
+ BuilderCompatImpl(@NonNull ContentInfoCompat other) {
+ mClip = other.getClip();
+ mSource = other.getSource();
+ mFlags = other.getFlags();
+ mLinkUri = other.getLinkUri();
+ mExtras = other.getExtras();
+ }
+
+ @Override
+ public void setClip(@NonNull ClipData clip) {
+ mClip = clip;
+ }
+
+ @Override
+ public void setSource(@Source int source) {
+ mSource = source;
+ }
+
+ @Override
+ public void setFlags(@Flags int flags) {
+ mFlags = flags;
+ }
+
+ @Override
+ public void setLinkUri(@Nullable Uri linkUri) {
+ mLinkUri = linkUri;
+ }
+
+ @Override
+ public void setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ }
+
+ @Override
+ @NonNull
+ public ContentInfoCompat build() {
+ return new ContentInfoCompat(new CompatImpl(this));
+ }
+ }
+
+ @RequiresApi(31)
+ private static final class BuilderCompat31Impl implements BuilderCompat {
+ @NonNull
+ private final ContentInfo.Builder mPlatformBuilder;
+
+ BuilderCompat31Impl(@NonNull ClipData clip, int source) {
+ mPlatformBuilder = new ContentInfo.Builder(clip, source);
+ }
+
+ BuilderCompat31Impl(@NonNull ContentInfoCompat other) {
+ mPlatformBuilder = new ContentInfo.Builder(other.toContentInfo());
+ }
+
+ @Override
+ public void setClip(@NonNull ClipData clip) {
+ mPlatformBuilder.setClip(clip);
+ }
+
+ @Override
+ public void setSource(@Source int source) {
+ mPlatformBuilder.setSource(source);
+ }
+
+ @Override
+ public void setFlags(@Flags int flags) {
+ mPlatformBuilder.setFlags(flags);
+ }
+
+ @Override
+ public void setLinkUri(@Nullable Uri linkUri) {
+ mPlatformBuilder.setLinkUri(linkUri);
+ }
+
+ @Override
+ public void setExtras(@Nullable Bundle extras) {
+ mPlatformBuilder.setExtras(extras);
+ }
+
+ @NonNull
+ @Override
+ public ContentInfoCompat build() {
+ return new ContentInfoCompat(new Compat31Impl(mPlatformBuilder.build()));
}
}
}
diff --git a/core/core/src/main/java/androidx/core/view/OnReceiveContentViewBehavior.java b/core/core/src/main/java/androidx/core/view/OnReceiveContentViewBehavior.java
index 9b67b78..16156c8 100644
--- a/core/core/src/main/java/androidx/core/view/OnReceiveContentViewBehavior.java
+++ b/core/core/src/main/java/androidx/core/view/OnReceiveContentViewBehavior.java
@@ -23,10 +23,13 @@
* Interface for widgets to implement default behavior for receiving content. Content may be both
* text and non-text (plain/styled text, HTML, images, videos, audio files, etc).
*
- * <p>Widgets should implement this interface to define the default behavior for receiving content.
- * Apps wishing to provide custom behavior for receiving content should set a listener via
- * {@link ViewCompat#setOnReceiveContentListener}. See {@link ViewCompat#performReceiveContent} for
- * more info.
+ * <p>Widgets should implement this interface to define the default behavior for receiving content
+ * when the SDK is <= 30. When doing so, widgets should also override
+ * {@link android.view.View#onReceiveContent} for SDK > 30.
+ *
+ * <p>Apps wishing to provide custom behavior for receiving content should not implement this
+ * interface but rather set a listener via {@link ViewCompat#setOnReceiveContentListener}. See
+ * {@link ViewCompat#performReceiveContent} for more info.
*/
public interface OnReceiveContentViewBehavior {
/**
diff --git a/core/core/src/main/java/androidx/core/view/ViewCompat.java b/core/core/src/main/java/androidx/core/view/ViewCompat.java
index 4fb240c..b5225f0 100644
--- a/core/core/src/main/java/androidx/core/view/ViewCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewCompat.java
@@ -38,6 +38,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
+import android.view.ContentInfo;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -1126,6 +1127,7 @@
* @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
* @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
*/
+ @UiThread
public static void setImportantForAccessibility(@NonNull View view,
@ImportantForAccessibility int mode) {
if (Build.VERSION.SDK_INT >= 19) {
@@ -2749,6 +2751,10 @@
*/
public static void setOnReceiveContentListener(@NonNull View view, @Nullable String[] mimeTypes,
@Nullable OnReceiveContentListener listener) {
+ if (Build.VERSION.SDK_INT >= 31) {
+ Api31Impl.setOnReceiveContentListener(view, mimeTypes, listener);
+ return;
+ }
mimeTypes = (mimeTypes == null || mimeTypes.length == 0) ? null : mimeTypes;
if (listener != null) {
Preconditions.checkArgument(mimeTypes != null,
@@ -2794,6 +2800,9 @@
*/
@Nullable
public static String[] getOnReceiveContentMimeTypes(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 31) {
+ return Api31Impl.getReceiveContentMimeTypes(view);
+ }
return (String[]) view.getTag(R.id.tag_on_receive_content_mime_types);
}
@@ -2821,6 +2830,9 @@
Log.d(TAG, "performReceiveContent: " + payload
+ ", view=" + view.getClass().getSimpleName() + "[" + view.getId() + "]");
}
+ if (Build.VERSION.SDK_INT >= 31) {
+ return Api31Impl.performReceiveContent(view, payload);
+ }
OnReceiveContentListener listener =
(OnReceiveContentListener) view.getTag(R.id.tag_on_receive_content_listener);
if (listener != null) {
@@ -2840,6 +2852,71 @@
private static final OnReceiveContentViewBehavior NO_OP_ON_RECEIVE_CONTENT_VIEW_BEHAVIOR =
payload -> payload;
+ @RequiresApi(31)
+ private static final class Api31Impl {
+ private Api31Impl() {}
+
+ @DoNotInline
+ public static void setOnReceiveContentListener(@NonNull View view,
+ @Nullable String[] mimeTypes, @Nullable final OnReceiveContentListener listener) {
+ if (listener == null) {
+ view.setOnReceiveContentListener(mimeTypes, null);
+ } else {
+ view.setOnReceiveContentListener(mimeTypes,
+ new OnReceiveContentListenerAdapter(listener));
+ }
+ }
+
+ @DoNotInline
+ @Nullable
+ public static String[] getReceiveContentMimeTypes(@NonNull View view) {
+ return view.getReceiveContentMimeTypes();
+ }
+
+ @DoNotInline
+ @Nullable
+ public static ContentInfoCompat performReceiveContent(@NonNull View view,
+ @NonNull ContentInfoCompat payload) {
+ ContentInfo platPayload = payload.toContentInfo();
+ ContentInfo platResult = view.performReceiveContent(platPayload);
+ if (platResult == null) {
+ return null;
+ }
+ if (platResult == platPayload) {
+ // Avoid unnecessary conversion when returning the original payload unchanged.
+ return payload;
+ }
+ return ContentInfoCompat.toContentInfoCompat(platResult);
+ }
+ }
+
+ @RequiresApi(31)
+ private static final class OnReceiveContentListenerAdapter implements
+ android.view.OnReceiveContentListener {
+
+ @NonNull
+ private final OnReceiveContentListener mJetpackListener;
+
+ OnReceiveContentListenerAdapter(@NonNull OnReceiveContentListener jetpackListener) {
+ mJetpackListener = jetpackListener;
+ }
+
+ @Nullable
+ @Override
+ public ContentInfo onReceiveContent(@NonNull View view, @NonNull ContentInfo platPayload) {
+ ContentInfoCompat payload = ContentInfoCompat.toContentInfoCompat(platPayload);
+ ContentInfoCompat result = mJetpackListener.onReceiveContent(view, payload);
+ if (result == null) {
+ return null;
+ }
+ if (result == payload) {
+ // Avoid unnecessary conversion when returning the original payload unchanged.
+ return platPayload;
+ }
+ return result.toContentInfo();
+ }
+ }
+
/**
* Controls whether the entire hierarchy under this view will save its
* state when a state saving traversal occurs from its parent.
diff --git a/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java b/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
index dd5bcd3..e499ea4 100644
--- a/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
+++ b/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
@@ -603,8 +603,11 @@
WindowInsetsController.OnControllableInsetsChangedListener>
mListeners = new SimpleArrayMap<>();
+ protected Window mWindow;
+
Impl30(@NonNull Window window, @NonNull WindowInsetsControllerCompat compatController) {
this(window.getInsetsController(), compatController);
+ mWindow = window;
}
Impl30(@NonNull WindowInsetsController insetsController,
@@ -632,6 +635,10 @@
@Override
public void setAppearanceLightStatusBars(boolean isLight) {
if (isLight) {
+ if (mWindow != null) {
+ unsetSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+
mInsetsController.setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
@@ -760,5 +767,12 @@
mInsetsController.removeOnControllableInsetsChangedListener(fwListener);
}
}
+
+ protected void unsetSystemUiFlag(int systemUiFlag) {
+ View decorView = mWindow.getDecorView();
+ decorView.setSystemUiVisibility(
+ decorView.getSystemUiVisibility()
+ & ~systemUiFlag);
+ }
}
}
diff --git a/core/core/src/main/java/androidx/core/widget/EdgeEffectCompat.java b/core/core/src/main/java/androidx/core/widget/EdgeEffectCompat.java
index 4bea6a5..90fbfcb 100644
--- a/core/core/src/main/java/androidx/core/widget/EdgeEffectCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/EdgeEffectCompat.java
@@ -18,9 +18,14 @@
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
+import android.util.AttributeSet;
import android.widget.EdgeEffect;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
/**
* Helper for accessing {@link android.widget.EdgeEffect}.
@@ -41,7 +46,8 @@
*
* @param context Context to use for theming the effect
*
- * @deprecated Use {@link EdgeEffect} constructor directly.
+ * @deprecated Use {@link EdgeEffect} constructor directly or
+ * {@link EdgeEffectCompat#create(Context, AttributeSet)}.
*/
@Deprecated
public EdgeEffectCompat(Context context) {
@@ -49,6 +55,42 @@
}
/**
+ * Constructs and returns a new EdgeEffect themed using the given context, allowing support
+ * for the view attributes.
+ *
+ * @param context Context to use for theming the effect
+ * @param attrs The attributes of the XML tag that is inflating the view
+ */
+ @NonNull
+ public static EdgeEffect create(@NonNull Context context, @Nullable AttributeSet attrs) {
+ if (BuildCompat.isAtLeastS()) {
+ return Api31Impl.create(context, attrs);
+ }
+
+ return new EdgeEffect(context);
+ }
+
+ /**
+ * Returns the pull distance needed to be released to remove the showing effect.
+ * It is determined by the {@link #onPull(float, float)} <code>deltaDistance</code> and
+ * any animating values, including from {@link #onAbsorb(int)} and {@link #onRelease()}.
+ *
+ * This can be used in conjunction with {@link #onPullDistance(EdgeEffect, float, float)} to
+ * release the currently showing effect.
+ *
+ * On {@link Build.VERSION_CODES#R} and earlier, this will return 0.
+ *
+ * @return The pull distance that must be released to remove the showing effect or 0 for
+ * versions {@link Build.VERSION_CODES#R} and earlier.
+ */
+ public static float getDistance(@NonNull EdgeEffect edgeEffect) {
+ if (BuildCompat.isAtLeastS()) {
+ return Api31Impl.getDistance(edgeEffect);
+ }
+ return 0;
+ }
+
+ /**
* Set the size of this edge effect in pixels.
*
* @param width Effect width in pixels
@@ -157,6 +199,51 @@
}
/**
+ * A view should call this when content is pulled away from an edge by the user.
+ * This will update the state of the current visual effect and its associated animation.
+ * The host view should always {@link android.view.View#invalidate()} after this
+ * and draw the results accordingly. This works similarly to {@link #onPull(float, float)},
+ * but returns the amount of <code>deltaDistance</code> that has been consumed. For versions
+ * {@link Build.VERSION_CODES#S} and above, if the {@link #getDistance(EdgeEffect)} is currently
+ * 0 and <code>deltaDistance</code> is negative, this function will return 0 and the drawn value
+ * will remain unchanged. For versions {@link Build.VERSION_CODES#R} and below, this will
+ * consume all of the provided value and return <code>deltaDistance</code>.
+ *
+ * This method can be used to reverse the effect from a pull or absorb and partially consume
+ * some of a motion:
+ *
+ * <pre class="prettyprint">
+ * if (deltaY < 0 && EdgeEffectCompat.getDistance(edgeEffect) != 0) {
+ * float displacement = x / getWidth();
+ * float dist = deltaY / getHeight();
+ * float consumed = EdgeEffectCompat.onPullDistance(edgeEffect, dist, displacement);
+ * deltaY -= consumed * getHeight();
+ * if (edgeEffect.getDistance() == 0f) edgeEffect.onRelease();
+ * }
+ * </pre>
+ *
+ * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+ * 1.f (full length of the view) or negative values to express change
+ * back toward the edge reached to initiate the effect.
+ * @param displacement The displacement from the starting side of the effect of the point
+ * initiating the pull. In the case of touch this is the finger position.
+ * Values may be from 0-1.
+ * @return The amount of <code>deltaDistance</code> that was consumed, a number between
+ * 0 and <code>deltaDistance</code>.
+ */
+ public static float onPullDistance(
+ @NonNull EdgeEffect edgeEffect,
+ float deltaDistance,
+ float displacement
+ ) {
+ if (BuildCompat.isAtLeastS()) {
+ return Api31Impl.onPullDistance(edgeEffect, deltaDistance, displacement);
+ }
+ onPull(edgeEffect, deltaDistance, displacement);
+ return deltaDistance;
+ }
+
+ /**
* Call when the object is released after being pulled.
* This will begin the "decay" phase of the effect. After calling this method
* the host view should {@link android.view.View#invalidate()} if this method
@@ -207,4 +294,42 @@
public boolean draw(Canvas canvas) {
return mEdgeEffect.draw(canvas);
}
+
+ // TODO(b/181171227): This actually requires S, but we don't have a version for S yet.
+ @RequiresApi(Build.VERSION_CODES.R)
+ private static class Api31Impl {
+ private Api31Impl() {}
+
+ @DoNotInline
+ public static EdgeEffect create(Context context, AttributeSet attrs) {
+ try {
+ return new EdgeEffect(context, attrs);
+ } catch (Throwable t) {
+ return new EdgeEffect(context); // Old preview release
+ }
+ }
+
+ @DoNotInline
+ public static float onPullDistance(
+ EdgeEffect edgeEffect,
+ float deltaDistance,
+ float displacement
+ ) {
+ try {
+ return edgeEffect.onPullDistance(deltaDistance, displacement);
+ } catch (Throwable t) {
+ edgeEffect.onPull(deltaDistance, displacement); // Old preview release
+ return 0;
+ }
+ }
+
+ @DoNotInline
+ public static float getDistance(EdgeEffect edgeEffect) {
+ try {
+ return edgeEffect.getDistance();
+ } catch (Throwable t) {
+ return 0; // Old preview release
+ }
+ }
+ }
}
diff --git a/core/core/src/main/java/androidx/core/widget/NestedScrollView.java b/core/core/src/main/java/androidx/core/widget/NestedScrollView.java
index ab9cc52..ab3531c 100644
--- a/core/core/src/main/java/androidx/core/widget/NestedScrollView.java
+++ b/core/core/src/main/java/androidx/core/widget/NestedScrollView.java
@@ -17,6 +17,7 @@
package androidx.core.widget;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
import android.content.Context;
@@ -48,6 +49,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
import androidx.core.R;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.InputDeviceCompat;
@@ -102,8 +104,18 @@
private final Rect mTempRect = new Rect();
private OverScroller mScroller;
- private EdgeEffect mEdgeGlowTop;
- private EdgeEffect mEdgeGlowBottom;
+
+ /** @hide */
+ @RestrictTo(LIBRARY)
+ @VisibleForTesting
+ @NonNull
+ public EdgeEffect mEdgeGlowTop;
+
+ /** @hide */
+ @RestrictTo(LIBRARY)
+ @VisibleForTesting
+ @NonNull
+ public EdgeEffect mEdgeGlowBottom;
/**
* Position of the last motion event.
@@ -198,6 +210,9 @@
public NestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mEdgeGlowTop = EdgeEffectCompat.create(context, attrs);
+ mEdgeGlowBottom = EdgeEffectCompat.create(context, attrs);
+
initScrollView();
final TypedArray a = context.obtainStyledAttributes(
@@ -775,7 +790,7 @@
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
if (!inChild((int) ev.getX(), y)) {
- mIsBeingDragged = false;
+ mIsBeingDragged = stopGlowAnimations(ev) || !mScroller.isFinished();
recycleVelocityTracker();
break;
}
@@ -792,11 +807,12 @@
/*
* If being flinged and user touches the screen, initiate drag;
* otherwise don't. mScroller.isFinished should be false when
- * being flinged. We need to call computeScrollOffset() first so that
+ * being flinged. We also want to catch the edge glow and start dragging
+ * if one is being animated. We need to call computeScrollOffset() first so that
* isFinished() is correct.
*/
mScroller.computeScrollOffset();
- mIsBeingDragged = !mScroller.isFinished();
+ mIsBeingDragged = stopGlowAnimations(ev) || !mScroller.isFinished();
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
break;
}
@@ -842,7 +858,7 @@
if (getChildCount() == 0) {
return false;
}
- if ((mIsBeingDragged = !mScroller.isFinished())) {
+ if (mIsBeingDragged) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
@@ -872,6 +888,7 @@
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
+ deltaY -= releaseVerticalGlow(deltaY, ev.getX(activePointerIndex));
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
final ViewParent parent = getParent();
if (parent != null) {
@@ -903,11 +920,9 @@
// Calling overScrollByCompat will call onOverScrolled, which
// calls onScrollChanged if applicable.
- if (overScrollByCompat(0, deltaY, 0, getScrollY(), 0, range, 0,
- 0, true) && !hasNestedScrollingParent(ViewCompat.TYPE_TOUCH)) {
- // Break our velocity if we hit a scroll barrier.
- mVelocityTracker.clear();
- }
+ boolean clearVelocityTracker =
+ overScrollByCompat(0, deltaY, 0, getScrollY(), 0, range, 0,
+ 0, true) && !hasNestedScrollingParent(ViewCompat.TYPE_TOUCH);
final int scrolledDeltaY = getScrollY() - oldY;
final int unconsumedY = deltaY - scrolledDeltaY;
@@ -922,27 +937,31 @@
if (canOverscroll) {
deltaY -= mScrollConsumed[1];
- ensureGlows();
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
- EdgeEffectCompat.onPull(mEdgeGlowTop, (float) deltaY / getHeight(),
+ EdgeEffectCompat.onPullDistance(mEdgeGlowTop,
+ (float) -deltaY / getHeight(),
ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
} else if (pulledToY > range) {
- EdgeEffectCompat.onPull(mEdgeGlowBottom, (float) deltaY / getHeight(),
- 1.f - ev.getX(activePointerIndex)
- / getWidth());
+ EdgeEffectCompat.onPullDistance(mEdgeGlowBottom,
+ (float) deltaY / getHeight(),
+ 1.f - ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
}
- if (mEdgeGlowTop != null
- && (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())) {
+ if (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished()) {
ViewCompat.postInvalidateOnAnimation(this);
+ clearVelocityTracker = false;
}
}
+ if (clearVelocityTracker) {
+ // Break our velocity if we hit a scroll barrier.
+ mVelocityTracker.clear();
+ }
}
break;
case MotionEvent.ACTION_UP:
@@ -950,7 +969,8 @@
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
if ((Math.abs(initialVelocity) >= mMinimumVelocity)) {
- if (!dispatchNestedPreFling(0, -initialVelocity)) {
+ if (!edgeEffectFling(initialVelocity)
+ && !dispatchNestedPreFling(0, -initialVelocity)) {
dispatchNestedFling(0, -initialVelocity, true);
fling(-initialVelocity);
}
@@ -991,6 +1011,42 @@
return true;
}
+ private boolean edgeEffectFling(int velocityY) {
+ boolean consumed = true;
+ if (EdgeEffectCompat.getDistance(mEdgeGlowTop) != 0) {
+ mEdgeGlowTop.onAbsorb(velocityY);
+ } else if (EdgeEffectCompat.getDistance(mEdgeGlowBottom) != 0) {
+ mEdgeGlowBottom.onAbsorb(-velocityY);
+ } else {
+ consumed = false;
+ }
+ return consumed;
+ }
+
+ /**
+ * This stops any edge glow animation that is currently running by applying a
+ * 0 length pull at the displacement given by the provided MotionEvent. On pre-S devices,
+ * this method does nothing, allowing any animating edge effect to continue animating and
+ * returning <code>false</code> always.
+ *
+ * @param e The motion event to use to indicate the finger position for the displacement of
+ * the current pull.
+ * @return <code>true</code> if any edge effect had an existing effect to be drawn ond the
+ * animation was stopped or <code>false</code> if no edge effect had a value to display.
+ */
+ private boolean stopGlowAnimations(MotionEvent e) {
+ boolean stopped = false;
+ if (EdgeEffectCompat.getDistance(mEdgeGlowTop) != 0) {
+ EdgeEffectCompat.onPullDistance(mEdgeGlowTop, 0, e.getY() / getHeight());
+ stopped = true;
+ }
+ if (EdgeEffectCompat.getDistance(mEdgeGlowBottom) != 0) {
+ EdgeEffectCompat.onPullDistance(mEdgeGlowBottom, 0, 1 - e.getY() / getHeight());
+ stopped = true;
+ }
+ return stopped;
+ }
+
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = ev.getActionIndex();
final int pointerId = ev.getPointerId(pointerIndex);
@@ -1639,7 +1695,6 @@
final boolean canOverscroll = mode == OVER_SCROLL_ALWAYS
|| (mode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
if (canOverscroll) {
- ensureGlows();
if (unconsumed < 0) {
if (mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
@@ -1660,6 +1715,40 @@
}
}
+ /**
+ * If either of the vertical edge glows are currently active, this consumes part or all of
+ * deltaY on the edge glow.
+ *
+ * @param deltaY The pointer motion, in pixels, in the vertical direction, positive
+ * for moving down and negative for moving up.
+ * @param x The vertical position of the pointer.
+ * @return The amount of <code>deltaY</code> that has been consumed by the
+ * edge glow.
+ */
+ private int releaseVerticalGlow(int deltaY, float x) {
+ // First allow releasing existing overscroll effect:
+ float consumed = 0;
+ float displacement = x / getWidth();
+ float pullDistance = (float) deltaY / getHeight();
+ if (EdgeEffectCompat.getDistance(mEdgeGlowTop) != 0) {
+ consumed = -EdgeEffectCompat.onPullDistance(mEdgeGlowTop, -pullDistance, displacement);
+ if (EdgeEffectCompat.getDistance(mEdgeGlowTop) == 0) {
+ mEdgeGlowTop.onRelease();
+ }
+ } else if (EdgeEffectCompat.getDistance(mEdgeGlowBottom) != 0) {
+ consumed = EdgeEffectCompat.onPullDistance(mEdgeGlowBottom, pullDistance,
+ 1 - displacement);
+ if (EdgeEffectCompat.getDistance(mEdgeGlowBottom) == 0) {
+ mEdgeGlowBottom.onRelease();
+ }
+ }
+ int pixelsConsumed = Math.round(consumed * getHeight());
+ if (pixelsConsumed != 0) {
+ invalidate();
+ }
+ return pixelsConsumed;
+ }
+
private void runAnimatedScroll(boolean participateInNestedScrolling) {
if (participateInNestedScrolling) {
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
@@ -1952,10 +2041,8 @@
recycleVelocityTracker();
stopNestedScroll(ViewCompat.TYPE_TOUCH);
- if (mEdgeGlowTop != null) {
- mEdgeGlowTop.onRelease();
- mEdgeGlowBottom.onRelease();
- }
+ mEdgeGlowTop.onRelease();
+ mEdgeGlowBottom.onRelease();
}
/**
@@ -1981,67 +2068,52 @@
}
}
- private void ensureGlows() {
- if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
- if (mEdgeGlowTop == null) {
- Context context = getContext();
- mEdgeGlowTop = new EdgeEffect(context);
- mEdgeGlowBottom = new EdgeEffect(context);
- }
- } else {
- mEdgeGlowTop = null;
- mEdgeGlowBottom = null;
- }
- }
-
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
- if (mEdgeGlowTop != null) {
- final int scrollY = getScrollY();
- if (!mEdgeGlowTop.isFinished()) {
- final int restoreCount = canvas.save();
- int width = getWidth();
- int height = getHeight();
- int xTranslation = 0;
- int yTranslation = Math.min(0, scrollY);
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {
- width -= getPaddingLeft() + getPaddingRight();
- xTranslation += getPaddingLeft();
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {
- height -= getPaddingTop() + getPaddingBottom();
- yTranslation += getPaddingTop();
- }
- canvas.translate(xTranslation, yTranslation);
- mEdgeGlowTop.setSize(width, height);
- if (mEdgeGlowTop.draw(canvas)) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- canvas.restoreToCount(restoreCount);
+ final int scrollY = getScrollY();
+ if (!mEdgeGlowTop.isFinished()) {
+ final int restoreCount = canvas.save();
+ int width = getWidth();
+ int height = getHeight();
+ int xTranslation = 0;
+ int yTranslation = Math.min(0, scrollY);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {
+ width -= getPaddingLeft() + getPaddingRight();
+ xTranslation += getPaddingLeft();
}
- if (!mEdgeGlowBottom.isFinished()) {
- final int restoreCount = canvas.save();
- int width = getWidth();
- int height = getHeight();
- int xTranslation = 0;
- int yTranslation = Math.max(getScrollRange(), scrollY) + height;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {
- width -= getPaddingLeft() + getPaddingRight();
- xTranslation += getPaddingLeft();
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {
- height -= getPaddingTop() + getPaddingBottom();
- yTranslation -= getPaddingBottom();
- }
- canvas.translate(xTranslation - width, yTranslation);
- canvas.rotate(180, width, 0);
- mEdgeGlowBottom.setSize(width, height);
- if (mEdgeGlowBottom.draw(canvas)) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- canvas.restoreToCount(restoreCount);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {
+ height -= getPaddingTop() + getPaddingBottom();
+ yTranslation += getPaddingTop();
}
+ canvas.translate(xTranslation, yTranslation);
+ mEdgeGlowTop.setSize(width, height);
+ if (mEdgeGlowTop.draw(canvas)) {
+ ViewCompat.postInvalidateOnAnimation(this);
+ }
+ canvas.restoreToCount(restoreCount);
+ }
+ if (!mEdgeGlowBottom.isFinished()) {
+ final int restoreCount = canvas.save();
+ int width = getWidth();
+ int height = getHeight();
+ int xTranslation = 0;
+ int yTranslation = Math.max(getScrollRange(), scrollY) + height;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {
+ width -= getPaddingLeft() + getPaddingRight();
+ xTranslation += getPaddingLeft();
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {
+ height -= getPaddingTop() + getPaddingBottom();
+ yTranslation -= getPaddingBottom();
+ }
+ canvas.translate(xTranslation - width, yTranslation);
+ canvas.rotate(180, width, 0);
+ mEdgeGlowBottom.setSize(width, height);
+ if (mEdgeGlowBottom.draw(canvas)) {
+ ViewCompat.postInvalidateOnAnimation(this);
+ }
+ canvas.restoreToCount(restoreCount);
}
}
diff --git a/core/core/src/main/res/values/attrs.xml b/core/core/src/main/res/values/attrs.xml
index 5c644f0..45ab302 100644
--- a/core/core/src/main/res/values/attrs.xml
+++ b/core/core/src/main/res/values/attrs.xml
@@ -110,6 +110,9 @@
<!-- Alpha multiplier applied to the base color. -->
<attr name="alpha" format="float" />
<attr name="android:alpha"/>
+ <!-- Perceptual luminance applied to the base color. From 0 to 100. -->
+ <attr name="lStar" format="float" />
+ <attr name="android:lStar" />
</declare-styleable>
<!-- Used to describe the gradient for fill or stroke in a path of VectorDrawable. -->
diff --git a/core/core/src/main/res/values/public.xml b/core/core/src/main/res/values/public.xml
index 72fa773..9b344c2 100644
--- a/core/core/src/main/res/values/public.xml
+++ b/core/core/src/main/res/values/public.xml
@@ -18,6 +18,7 @@
<resources>
<!-- Definitions of attributes to be exposed as public -->
<public type="attr" name="alpha"/>
+ <public type="attr" name="lStar" />
<public type="attr" name="fontProviderAuthority"/>
<public type="attr" name="fontProviderPackage"/>
<public type="attr" name="fontProviderQuery"/>
diff --git a/datastore/.idea/codeStyles/Project.xml b/datastore/.idea/codeStyles/Project.xml
new file mode 120000
index 0000000..b52b28c
--- /dev/null
+++ b/datastore/.idea/codeStyles/Project.xml
@@ -0,0 +1 @@
+../../../.idea/codeStyles/Project.xml
\ No newline at end of file
diff --git a/datastore/.idea/codeStyles/codeStyleConfig.xml b/datastore/.idea/codeStyles/codeStyleConfig.xml
new file mode 120000
index 0000000..19c4848
--- /dev/null
+++ b/datastore/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1 @@
+../../../.idea/codeStyles/codeStyleConfig.xml
\ No newline at end of file
diff --git a/datastore/.idea/copyright/AndroidCopyright.xml b/datastore/.idea/copyright/AndroidCopyright.xml
new file mode 120000
index 0000000..afbbd04
--- /dev/null
+++ b/datastore/.idea/copyright/AndroidCopyright.xml
@@ -0,0 +1 @@
+../../../.idea/copyright/AndroidCopyright.xml
\ No newline at end of file
diff --git a/datastore/.idea/copyright/profiles_settings.xml b/datastore/.idea/copyright/profiles_settings.xml
new file mode 120000
index 0000000..5996ccd
--- /dev/null
+++ b/datastore/.idea/copyright/profiles_settings.xml
@@ -0,0 +1 @@
+../../../.idea/copyright/profiles_settings.xml
\ No newline at end of file
diff --git a/datastore/.idea/inspectionProfiles/Project_Default.xml b/datastore/.idea/inspectionProfiles/Project_Default.xml
new file mode 120000
index 0000000..a7481f4
--- /dev/null
+++ b/datastore/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1 @@
+../../../.idea/inspectionProfiles/Project_Default.xml
\ No newline at end of file
diff --git a/datastore/.idea/scopes/Ignore_API_Files.xml b/datastore/.idea/scopes/Ignore_API_Files.xml
new file mode 120000
index 0000000..3361ee1
--- /dev/null
+++ b/datastore/.idea/scopes/Ignore_API_Files.xml
@@ -0,0 +1 @@
+../../../.idea/scopes/Ignore_API_Files.xml
\ No newline at end of file
diff --git a/datastore/.idea/scopes/buildSrc.xml b/datastore/.idea/scopes/buildSrc.xml
new file mode 120000
index 0000000..25b7d3b
--- /dev/null
+++ b/datastore/.idea/scopes/buildSrc.xml
@@ -0,0 +1 @@
+../../../.idea/scopes/buildSrc.xml
\ No newline at end of file
diff --git a/datastore/OWNERS b/datastore/OWNERS
index 2fa7fba..12a6371 100644
--- a/datastore/OWNERS
+++ b/datastore/OWNERS
@@ -1,3 +1,5 @@
# Bug component: 907884
spf@google.com
-rohitsat@google.com
\ No newline at end of file
+rohitsat@google.com
+
+per-file settings.gradle = dustinlam@google.com, rahulrav@google.com
diff --git a/datastore/datastore-sampleapp/src/main/AndroidManifest.xml b/datastore/datastore-sampleapp/src/main/AndroidManifest.xml
index fdc1d9e..2aebdbb 100644
--- a/datastore/datastore-sampleapp/src/main/AndroidManifest.xml
+++ b/datastore/datastore-sampleapp/src/main/AndroidManifest.xml
@@ -22,25 +22,33 @@
android:allowBackup="true"
android:supportsRtl="true"
android:theme="@style/Theme.null">
- <activity android:name=".PreferencesDataStoreActivity">
+ <activity
+ android:name=".PreferencesDataStoreActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".ProtoDataStoreActivity">
+ <activity
+ android:name=".ProtoDataStoreActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".SettingsFragmentActivity">
+ <activity
+ android:name=".SettingsFragmentActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".KotlinSerializationActivity">
+ <activity
+ android:name=".KotlinSerializationActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/datastore/gradle b/datastore/gradle
new file mode 120000
index 0000000..a2d256f
--- /dev/null
+++ b/datastore/gradle
@@ -0,0 +1 @@
+./../playground-common/gradle
\ No newline at end of file
diff --git a/datastore/gradle.properties b/datastore/gradle.properties
new file mode 120000
index 0000000..980e688
--- /dev/null
+++ b/datastore/gradle.properties
@@ -0,0 +1 @@
+./../playground-common/androidx-shared.properties
\ No newline at end of file
diff --git a/datastore/gradlew b/datastore/gradlew
new file mode 120000
index 0000000..6f81fc5
--- /dev/null
+++ b/datastore/gradlew
@@ -0,0 +1 @@
+./../playground-common/gradlew
\ No newline at end of file
diff --git a/datastore/gradlew.bat b/datastore/gradlew.bat
new file mode 120000
index 0000000..dc97aff
--- /dev/null
+++ b/datastore/gradlew.bat
@@ -0,0 +1 @@
+./../playground-common/gradlew.bat
\ No newline at end of file
diff --git a/datastore/settings.gradle b/datastore/settings.gradle
new file mode 100644
index 0000000..e8ac9c2c
--- /dev/null
+++ b/datastore/settings.gradle
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// see ../playground-common/README.md for details on how this works
+rootProject.name = "datastore-playground"
+apply from: "../playground-common/playground-include-settings.gradle"
+setupPlayground(this, "..")
+selectProjectsFromAndroidX({ name ->
+ if (name.startsWith(":datastore")) return true
+ if (name == ":annotation:annotation-sampled") return true
+ if (name == ":internal-testutils-truth") return true
+ return false
+})
+
diff --git a/development/auto-version-updater/update_versions_for_release.py b/development/auto-version-updater/update_versions_for_release.py
index 3c0db04..4eddad7 100755
--- a/development/auto-version-updater/update_versions_for_release.py
+++ b/development/auto-version-updater/update_versions_for_release.py
@@ -32,7 +32,7 @@
os.chdir(os.path.dirname(os.path.abspath(__file__)))
FRAMEWORKS_SUPPORT_FP = os.path.abspath(os.path.join(os.getcwd(), '..', '..'))
-LIBRARY_VERSIONS_REL = './buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt'
+LIBRARY_VERSIONS_REL = './buildSrc/public/src/main/kotlin/androidx/build/LibraryVersions.kt'
LIBRARY_VERSIONS_FP = os.path.join(FRAMEWORKS_SUPPORT_FP, LIBRARY_VERSIONS_REL)
# Set up input arguments
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 8b98e9e..af2600d 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -242,12 +242,6 @@
# > Task :startup:integration-tests:first-library:processDebugManifest
\$SUPPORT/startup/integration\-tests/first\-library/src/main/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
meta\-data\#androidx\.work\.WorkManagerInitializer was tagged at AndroidManifest\.xml\:[0-9]+ to remove other declarations but no other declaration present
-# > Task :camera:integration-tests:camera-testapp-extensions:compileDebugJavaWithJavac
-# > Task :camera:integration-tests:camera-testapp-core:compileDebugJavaWithJavac
-# > Task :room:integration-tests:room-testapp:processDebugMainManifest
-\[androidx\.vectordrawable:vectordrawable\-animated:[0-9]+\.[0-9]+\.[0-9]+\] \$GRADLE_USER_HOME/caches/transforms\-[0-9]+/[0-9a-f]{32}/transformed/vectordrawable\-animated\-[0-9]+\.[0-9]+\.[0-9]+/AndroidManifest\.xml Warning:
-Package name 'androidx\.vectordrawable' used in: androidx\.vectordrawable:vectordrawable\-animated:[0-9]+\.[0-9]+\.[0-9]+, androidx\.vectordrawable:vectordrawable:[0-9]+\.[0-9]+\.[0-9]+\.
-# > Task :lifecycle:integration-tests:lifecycle-testapp:compileDebugJavaWithJavac
# > Task :support-slices-demos:compileDebugJavaWithJavac
Note: \$SUPPORT/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser\.java uses unchecked or unsafe operations\.
# > Task :emoji2:emoji2-benchmark:processReleaseAndroidTestManifest
@@ -529,6 +523,8 @@
@param bounds,
\@param defaultPolicy
@param complicationTapFilter
+in DClass UserStyle
+@param copySelectedOptions
in DClass Builder
Did you make a typo\? Are you trying to refer to something not visible to users\?
# Wire proto generation, task :generateDebugProtos
@@ -544,7 +540,7 @@
# https://youtrack.jetbrains.com/issue/KT-30589
WARNING: Illegal reflective access by org\.jetbrains\.kotlin\.kapt3\.base\.javac\.KaptJavaFileManager .* to method com\.sun\.tools\.javac\.file\.BaseFileManager\.handleOption\(com\.sun\.tools\.javac\.main\.Option,java\.lang\.String\)
# > Task :benchmark:benchmark-macro:compileReleaseKotlin
-Execution optimizations have been disabled for task ':benchmark:benchmark\-macro:.*' to ensure correctness due to the following reasons:
+Execution optimizations have been disabled for task ':benchmark:benchmark\-common:.*' to ensure correctness due to the following reasons:
\- Gradle detected a problem with the following location: '\$OUT_DIR/androidx/benchmark/benchmark\-macro/build/generated/source/wire'\. Reason: Task ':benchmark:benchmark\-macro:.*' uses this output of task ':benchmark:benchmark\-macro:.*' without declaring an explicit or implicit dependency\. This can lead to incorrect results being produced, depending on what order the tasks are executed\. Please refer to https://docs\.gradle\.org/[0-9]+\.[0-9]+/userguide/validation_problems\.html\#implicit_dependency for more details about this problem\.
# > Task :profileinstaller:profileinstaller:processDebugUnitTestManifest
Scanning .+: \.*
@@ -607,5 +603,5 @@
WARNING\:The option setting \'android\.dependencyResolutionAtConfigurationTime\.disallow\=true\' is experimental\.
# b/195025261
Unable to detect AGP versions for included builds\. All projects in the build should use the same AGP version\. Class name for the included build .*
-\- Gradle detected a problem with the following location: '\$OUT_DIR/androidx/benchmark/benchmark-macro/build/generated/source/wire'\. Reason: Task ':benchmark:benchmark-macro:.*' uses this output of task ':benchmark:benchmark-macro:generate(Debug|Release)Protos' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. Please refer to .*
+\- Gradle detected a problem with the following location: '\$OUT_DIR/androidx/benchmark/benchmark-common/build/generated/source/wire'\. Reason: Task ':benchmark:benchmark-common:.*' uses this output of task ':benchmark:benchmark-common:generate(Debug|Release)Protos' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. Please refer to .*
To honour the JVM settings for this build a single\-use Daemon process will be forked.*
diff --git a/development/update_playground.sh b/development/update_playground.sh
new file mode 100644
index 0000000..c02a3a5
--- /dev/null
+++ b/development/update_playground.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+BUILDID_ANDROIDX=`curl -s https://androidx.dev/snapshots/builds | sed -nr 's|.*snapshots/builds/([0-9]*).*|\1|gp' | head -n 1`
+BUILDID_METALAVA=`curl -s https://androidx.dev/metalava/builds | sed -nr 's|.*metalava/builds/([0-9]*).*|\1|gp' | head -n 1`
+BUILDID_DOKKA=`curl -s https://androidx.dev/dokka/builds | sed -nr 's|.*dokka/builds/([0-9]*).*|\1|gp' | head -n 1`
+
+echo $BUILDID_ANDROIDX
+echo $BUILDID_METALAVA
+echo $BUILDID_DOKKA
+
+sed -i "s/androidx.playground.snapshotBuildId=[0-9]\+/androidx.playground.snapshotBuildId=$BUILDID_ANDROIDX/g" playground-common/playground.properties
+sed -i "s/androidx.playground.metalavaBuildId=[0-9]\+/androidx.playground.metalavaBuildId=$BUILDID_METALAVA/g" playground-common/playground.properties
+sed -i "s/androidx.playground.dokkaBuildId=[0-9]\+/androidx.playground.dokkaBuildId=$BUILDID_DOKKA/g" playground-common/playground.properties
+sed -i "s|androidx.dev/metalava/builds/[0-9]\+|androidx.dev/metalava/builds/$BUILDID_METALAVA|g" androidx-plugin/build.gradle
+sed -i "s|androidx.dev/dokka/builds/[0-9]\+|androidx.dev/dokka/builds/$BUILDID_METALAVA|g" androidx-plugin/build.gradle
+
diff --git a/development/update_studio.sh b/development/update_studio.sh
index 668e2b8..e4d192c 100755
--- a/development/update_studio.sh
+++ b/development/update_studio.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Get versions
-AGP_VERSION=${1:-7.1.0-alpha06}
-STUDIO_VERSION_STRING=${2:-"Android Studio Bumblebee (2021.1.1) Canary 6"}
+AGP_VERSION=${1:-7.1.0-alpha07}
+STUDIO_VERSION_STRING=${2:-"Android Studio Bumblebee (2021.1.1) Canary 7"}
STUDIO_IFRAME_LINK=`curl "https://developer.android.com/studio/archive.html" | grep iframe | sed "s/.*src=\"\([a-zA-Z0-9\/\._]*\)\".*/https:\/\/android-dot-devsite-v2-prod.appspot.com\1/g"`
STUDIO_LINK=`curl -s $STUDIO_IFRAME_LINK | grep -C30 "$STUDIO_VERSION_STRING" | grep Linux | tail -n 1 | sed 's/.*a href="\(.*\).*"/\1/g'`
STUDIO_VERSION=`echo $STUDIO_LINK | sed "s/.*ide-zips\/\(.*\)\/android-studio-.*/\1/g"`
@@ -37,7 +37,7 @@
./development/importMaven/import_maven_artifacts.py -n "com.android.tools.utp:$ARTIFACT:$ADT_VERSION"
done
-ATP_VERSION=${4:-0.0.8-alpha07}
+ATP_VERSION=${4:-0.0.8-alpha06}
./development/importMaven/import_maven_artifacts.py -n "com.google.testing.platform:android-test-plugin:$ATP_VERSION"
./development/importMaven/import_maven_artifacts.py -n "com.google.testing.platform:launcher:$ATP_VERSION"
./development/importMaven/import_maven_artifacts.py -n "com.google.testing.platform:android-driver-instrumentation:$ATP_VERSION"
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 363785c..ea18191 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -101,6 +101,8 @@
docs(project(":core:core-appdigest"))
docs(project(":core:core-google-shortcuts"))
docs(project(":core:core-ktx"))
+ docs(project(":core:core-remoteviews"))
+ docs(project(":core:core-splashscreen"))
docs(project(":core:core-role"))
docs(project(":cursoradapter:cursoradapter"))
docs(project(":customview:customview"))
diff --git a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionImplementation.java b/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionImplementation.java
deleted file mode 100644
index c0b7a72..0000000
--- a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionImplementation.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.emoji2.benchmark.reflection;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.Method;
-
-public class ReflectionImplementation extends ReflectionParent {
- @Override
- public ReflectionParent actualCall() {
- return super.actualCall();
- }
-
- ReflectionParent staticActualCall() throws Throwable {
- return ParentMethodHandles.staticCall(this);
- }
-
- MethodHandle doMethodLookup() throws NoSuchMethodException, IllegalAccessException {
- return ParentMethodHandles.doMethodLookup();
- }
-
- private static class ParentMethodHandles {
- private static final MethodHandle sMethodHandle;
-
- static {
- MethodHandle sMethodHandle1 = null;
- try {
- sMethodHandle1 = doMethodLookup();
- } catch (Throwable ignored) { }
- sMethodHandle = sMethodHandle1;
- }
-
- private static MethodHandle doMethodLookup() throws IllegalAccessException,
- NoSuchMethodException {
- MethodHandles.Lookup lookup = MethodHandles.lookup().in(ReflectionParent.class);
- Method method = ReflectionParent.class.getDeclaredMethod("actualCall");
- method.setAccessible(true);
- return lookup.unreflectSpecial(method, ReflectionParent.class);
- }
-
- public static ReflectionParent staticCall(ReflectionImplementation reflectionImplementation)
- throws Throwable {
- return (ReflectionParent) sMethodHandle.bindTo(reflectionImplementation)
- .invokeWithArguments();
- }
- }
-
-}
diff --git a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionParent.java b/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionParent.java
deleted file mode 100644
index d297463..0000000
--- a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionParent.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.emoji2.benchmark.reflection;
-
-public class ReflectionParent {
- public ReflectionParent actualCall() {
- return this;
- }
-}
diff --git a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionsBenchmark.java b/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionsBenchmark.java
deleted file mode 100644
index c9e59fa..0000000
--- a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/reflection/ReflectionsBenchmark.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.emoji2.benchmark.reflection;
-
-import static org.junit.Assert.assertNotNull;
-
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.invoke.MethodHandle;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class ReflectionsBenchmark {
- @Rule
- public BenchmarkRule benchmarkRule = new BenchmarkRule();
-
- @Test
- public void static_methodHandle() throws Throwable {
- BenchmarkState state = benchmarkRule.getState();
- ReflectionImplementation subject = new ReflectionImplementation();
- ReflectionParent result = null;
- while (state.keepRunning()) {
- result = subject.staticActualCall();
- }
- assertNotNull(result);
- }
-
- @Test
- public void regularJavaDispatch() {
- BenchmarkState state = benchmarkRule.getState();
- ReflectionImplementation subject = new ReflectionImplementation();
- ReflectionParent result = null;
- while (state.keepRunning()) {
- result = subject.actualCall();
- }
- assertNotNull(result);
- }
-
- /**
- * This test is not an accurate reflection of first lookup cost, as it will warm up caches
- * before the main benchmark starts.
- *
- * However, it is a good _lower bound_ of the cost to do this lookup, with the assumption
- * that real world lookups will always be the same cost or slower.
- */
- @Test
- public void doWarmedUpMethodLookup() throws NoSuchMethodException, IllegalAccessException {
- BenchmarkState state = benchmarkRule.getState();
- ReflectionImplementation subject = new ReflectionImplementation();
- MethodHandle result = null;
- while (state.keepRunning()) {
- result = subject.doMethodLookup();
- }
- assertNotNull(result);
- }
-}
diff --git a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/text/NoFontTestEmojiConfig.java b/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/text/NoFontTestEmojiConfig.java
index f706f84..67ad432 100644
--- a/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/text/NoFontTestEmojiConfig.java
+++ b/emoji2/emoji2-benchmark/src/androidTest/java/androidx/emoji2/benchmark/text/NoFontTestEmojiConfig.java
@@ -21,9 +21,11 @@
import android.graphics.Typeface;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.emoji2.text.EmojiCompat;
import androidx.emoji2.text.MetadataRepo;
+@RequiresApi(19)
public class NoFontTestEmojiConfig extends EmojiCompat.Config {
static EmojiCompat.Config emptyConfig() {
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt
index 5bc6cdf..1d9b21c 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt
@@ -28,7 +28,9 @@
import android.view.WindowInsets
import android.view.animation.Animation
import androidx.core.app.ActivityCompat
+import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.test.FragmentTestActivity
import androidx.fragment.test.R
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -155,12 +157,13 @@
.build()
var dispatchedToChild = 0
- childView.setOnApplyWindowInsetsListener { _, insets ->
- // Ensure insets received by child are not consumed at all by the parent
- assertThat(insets.systemWindowInsets).isEqualTo(sentInsets.systemWindowInsets)
- dispatchedToChild++
- insets
- }
+ childView.setOnApplyWindowInsetsListener(object : View.OnApplyWindowInsetsListener {
+ override fun onApplyWindowInsets(p0: View?, insets: WindowInsets?): WindowInsets {
+ assertThat(insets!!.systemWindowInsets).isEqualTo(sentInsets.systemWindowInsets)
+ dispatchedToChild++
+ return insets
+ }
+ })
childView.setTag(R.id.fragment_container_view_tag, Fragment())
@@ -185,22 +188,24 @@
.build()
var dispatchedToChild = 0
- childView.setOnApplyWindowInsetsListener { _, insets ->
- // Ensure insets received by child are not consumed at all by the parent
- assertThat(insets.systemWindowInsets).isEqualTo(sentInsets.systemWindowInsets)
- dispatchedToChild++
- WindowInsets.Builder()
- .setSystemWindowInsets(Insets.of(0, 0, 0, 0))
- .build()
- }
+ childView.setOnApplyWindowInsetsListener(object : View.OnApplyWindowInsetsListener {
+ override fun onApplyWindowInsets(p0: View?, insets: WindowInsets?): WindowInsets {
+ assertThat(insets!!.systemWindowInsets).isEqualTo(sentInsets.systemWindowInsets)
+ dispatchedToChild++
+ return WindowInsets.Builder()
+ .setSystemWindowInsets(Insets.of(0, 0, 0, 0))
+ .build()
+ }
+ })
var dispatchedToChild2 = 0
- childView2.setOnApplyWindowInsetsListener { _, insets ->
- // Ensure insets received by child are not consumed at all by the parent
- assertThat(insets.systemWindowInsets).isEqualTo(sentInsets.systemWindowInsets)
- dispatchedToChild2++
- insets
- }
+ childView2.setOnApplyWindowInsetsListener(object : View.OnApplyWindowInsetsListener {
+ override fun onApplyWindowInsets(p0: View?, insets: WindowInsets?): WindowInsets {
+ assertThat(insets!!.systemWindowInsets).isEqualTo(sentInsets.systemWindowInsets)
+ dispatchedToChild2++
+ return insets
+ }
+ })
childView.setTag(R.id.fragment_container_view_tag, Fragment())
childView2.setTag(R.id.fragment_container_view_tag, Fragment())
@@ -225,10 +230,18 @@
.setSystemWindowInsets(Insets.of(4, 3, 2, 1))
.build()
- ViewCompat.setOnApplyWindowInsetsListener(fragmentContainerView) { _, insets ->
- calledListener = true
- insets
- }
+ ViewCompat.setOnApplyWindowInsetsListener(
+ fragmentContainerView,
+ object : OnApplyWindowInsetsListener {
+ override fun onApplyWindowInsets(
+ v: View?,
+ insets: WindowInsetsCompat?
+ ): WindowInsetsCompat {
+ calledListener = true
+ return insets!!
+ }
+ }
+ )
fragmentContainerView.onApplyWindowInsets(sentInsets)
diff --git a/fragment/integration-tests/testapp/src/main/AndroidManifest.xml b/fragment/integration-tests/testapp/src/main/AndroidManifest.xml
index 460d479..b6e1c84 100644
--- a/fragment/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/fragment/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -23,15 +23,22 @@
android:label="@string/app_name"
android:supportsRtl="true"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon">
- <activity android:name=".MainFragmentActivity">
+ <activity
+ android:name=".MainFragmentActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT"/>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".doubleTransitionBug.DoubleTransitionBugActivity"/>
- <activity android:name=".kittenfragmenttransitions.KittenTransitionMainActivity"/>
+ <activity
+ android:name=".doubleTransitionBug.DoubleTransitionBugActivity"
+ android:exported="false" />
+ <activity
+ android:name=".kittenfragmenttransitions.KittenTransitionMainActivity"
+ android:exported="false" />
</application>
</manifest>
diff --git a/glance/glance/build.gradle b/glance/glance/build.gradle
index 992f85b..91e7e82 100644
--- a/glance/glance/build.gradle
+++ b/glance/glance/build.gradle
@@ -37,6 +37,7 @@
testImplementation(libs.testRules)
testImplementation(libs.testRunner)
+ testImplementation(libs.truth)
testImplementation(libs.junit)
}
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/Applier.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/Applier.kt
new file mode 100644
index 0000000..78e8dea
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/Applier.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance
+
+import androidx.compose.runtime.AbstractApplier
+import java.lang.IllegalStateException
+
+/** Applier for the Glance composition. */
+@GlanceInternalApi
+class Applier(root: EmittableWithChildren) : AbstractApplier<Emittable>(root) {
+ override fun onClear() {
+ (root as EmittableWithChildren).children.clear()
+ }
+
+ override fun insertBottomUp(index: Int, instance: Emittable) {
+ // Ignored, the tree is built top-down.
+ }
+
+ override fun insertTopDown(index: Int, instance: Emittable) {
+ currentChildren.add(index, instance)
+ }
+
+ override fun move(from: Int, to: Int, count: Int) {
+ currentChildren.move(from, to, count)
+ }
+
+ override fun remove(index: Int, count: Int) {
+ currentChildren.remove(index, count)
+ }
+
+ private val currentChildren: MutableList<Emittable>
+ get() {
+ current.let {
+ if (it is EmittableWithChildren) {
+ return it.children
+ }
+ }
+ throw IllegalStateException("Current node cannot accept children")
+ }
+}
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/Emittables.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/Emittables.kt
new file mode 100644
index 0000000..ea7123d
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/Emittables.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance
+
+@GlanceInternalApi
+interface Emittable {
+ var modifier: Modifier
+}
+
+@GlanceInternalApi
+abstract class EmittableWithChildren : Emittable {
+ val children = mutableListOf<Emittable>()
+
+ protected fun childrenToString(): String =
+ children.joinToString(",\n").prependIndent(" ")
+}
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/GlanceInternalApi.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/GlanceInternalApi.kt
new file mode 100644
index 0000000..606ac67
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/GlanceInternalApi.kt
@@ -0,0 +1,14 @@
+package androidx.glance
+
+/**
+ * Annotation for internal implementation details of the Glance API. This is intended for things we
+ * need to expose to make them available in the same library group, but not intended for API
+ * consumers and hence should not form part of our stable API.
+ */
+@RequiresOptIn(
+ message = "This API is used for the implementation of androidx.glance, and should " +
+ "not be used by API consumers."
+)
+@Retention(AnnotationRetention.BINARY)
+@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
+annotation class GlanceInternalApi
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/Modifier.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/Modifier.kt
new file mode 100644
index 0000000..a7f989c
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/Modifier.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.glance
+
+import androidx.compose.runtime.Stable
+
+/**
+ * An ordered, immutable, collection of modifier element for the Glance library.
+ *
+ * This plays the same role as [androidx.compose.ui.Modifier], but for the Glance composables.
+ */
+@Stable
+interface Modifier {
+ /**
+ * Accumulates a value starting with [initial] and applying [operation] to the current value
+ * and each element from outside in.
+ *
+ * Elements wrap one another in a chain from left to right; an [Element] that appears to the
+ * left of another in a `+` expression or in [operation]'s parameter order affects all
+ * of the elements that appear after it. [foldIn] may be used to accumulate a value starting
+ * from the parent or head of the modifier chain to the final wrapped child.
+ */
+ fun <R> foldIn(initial: R, operation: (R, Element) -> R): R
+
+ /**
+ * Accumulates a value starting with [initial] and applying [operation] to the current value
+ * and each element from inside out.
+ *
+ * Elements wrap one another in a chain from left to right; an [Element] that appears to the
+ * left of another in a `+` expression or in [operation]'s parameter order affects all
+ * of the elements that appear after it. [foldOut] may be used to accumulate a value starting
+ * from the child or tail of the modifier chain up to the parent or head of the chain.
+ */
+ fun <R> foldOut(initial: R, operation: (Element, R) -> R): R
+
+ /**
+ * Returns `true` if [predicate] returns true for any [Element] in this [Modifier].
+ */
+ fun any(predicate: (Element) -> Boolean): Boolean
+
+ /**
+ * Returns `true` if [predicate] returns true for all [Element]s in this [Modifier] or if
+ * this [Modifier] contains no [Element]s.
+ */
+ fun all(predicate: (Element) -> Boolean): Boolean
+
+ /**
+ * Concatenates this modifier with another.
+ *
+ * Returns a [Modifier] representing this modifier followed by [other] in sequence.
+ */
+ infix fun then(other: Modifier): Modifier =
+ if (other === Modifier) this else CombinedModifier(this, other)
+
+ /**
+ * A single element contained within a [Modifier] chain.
+ */
+ interface Element : Modifier {
+ override fun <R> foldIn(initial: R, operation: (R, Element) -> R): R =
+ operation(initial, this)
+
+ override fun <R> foldOut(initial: R, operation: (Element, R) -> R): R =
+ operation(this, initial)
+
+ override fun any(predicate: (Element) -> Boolean): Boolean = predicate(this)
+ override fun all(predicate: (Element) -> Boolean): Boolean = predicate(this)
+ }
+
+ /**
+ * The companion object `Modifier` is the empty, default, or starter [Modifier]
+ * that contains no [elements][Element]. Use it to create a new [Modifier] using
+ * modifier extension factory functions.
+ */
+ // The companion object implements `Modifier` so that it may be used as the start of a
+ // modifier extension factory expression.
+ companion object : Modifier {
+ override fun <R> foldIn(initial: R, operation: (R, Element) -> R): R = initial
+ override fun <R> foldOut(initial: R, operation: (Element, R) -> R): R = initial
+ override fun any(predicate: (Element) -> Boolean): Boolean = false
+ override fun all(predicate: (Element) -> Boolean): Boolean = true
+ override infix fun then(other: Modifier): Modifier = other
+ override fun toString() = "Modifier"
+ }
+}
+
+/**
+ * A node in a [Modifier] chain. A CombinedModifier always contains at least two elements;
+ * a Modifier [outer] that wraps around the Modifier [inner].
+ */
+class CombinedModifier(
+ private val outer: Modifier,
+ private val inner: Modifier
+) : Modifier {
+ override fun <R> foldIn(initial: R, operation: (R, Modifier.Element) -> R): R =
+ inner.foldIn(outer.foldIn(initial, operation), operation)
+
+ override fun <R> foldOut(initial: R, operation: (Modifier.Element, R) -> R): R =
+ outer.foldOut(inner.foldOut(initial, operation), operation)
+
+ override fun any(predicate: (Modifier.Element) -> Boolean): Boolean =
+ outer.any(predicate) || inner.any(predicate)
+
+ override fun all(predicate: (Modifier.Element) -> Boolean): Boolean =
+ outer.all(predicate) && inner.all(predicate)
+
+ override fun equals(other: Any?): Boolean =
+ other is CombinedModifier && outer == other.outer && inner == other.inner
+
+ override fun hashCode(): Int = outer.hashCode() + 31 * inner.hashCode()
+ override fun toString() = "[" + foldIn("") { acc, element ->
+ if (acc.isEmpty()) element.toString() else "$acc, $element"
+ } + "]"
+}
\ No newline at end of file
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/layout/Padding.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/layout/Padding.kt
new file mode 100644
index 0000000..28b0401d
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/layout/Padding.kt
@@ -0,0 +1,101 @@
+@file:OptIn(GlanceInternalApi::class)
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.glance.layout
+
+import androidx.glance.unit.Dp
+import androidx.glance.unit.dp
+import androidx.glance.GlanceInternalApi
+import androidx.glance.Modifier
+
+/**
+ * Apply additional space along each edge of the content in [Dp]: [start], [top], [end] and
+ * [bottom]. The start and end edges will be determined by layout direction of the current locale.
+ * Padding is applied before content measurement and takes precedence; content may only be as large
+ * as the remaining space.
+ */
+fun Modifier.padding(
+ start: Dp = 0.dp,
+ top: Dp = 0.dp,
+ end: Dp = 0.dp,
+ bottom: Dp = 0.dp
+) = this.then(
+ PaddingModifier(
+ start = start,
+ top = top,
+ end = end,
+ bottom = bottom,
+ rtlAware = true
+ )
+)
+
+/**
+ * Apply [horizontal] dp space along the left and right edges of the content, and [vertical] dp
+ * space along the top and bottom edges.
+ */
+fun Modifier.padding(
+ horizontal: Dp = 0.dp,
+ vertical: Dp = 0.dp
+) = this.then(
+ PaddingModifier(
+ start = horizontal,
+ top = vertical,
+ end = horizontal,
+ bottom = vertical,
+ rtlAware = true
+ )
+)
+
+/**
+ * Apply [all] dp of additional space along each edge of the content, left, top, right and bottom.
+ */
+fun Modifier.padding(all: Dp) = this.then(
+ PaddingModifier(
+ start = all,
+ top = all,
+ end = all,
+ bottom = all,
+ rtlAware = true
+ )
+)
+
+/**
+ * Apply additional space along each edge of the content in [Dp]: [left], [top], [right] and
+ * [bottom], ignoring the current locale's layout direction.
+ */
+fun Modifier.absolutePadding(
+ left: Dp = 0.dp,
+ top: Dp = 0.dp,
+ right: Dp = 0.dp,
+ bottom: Dp = 0.dp
+) = this.then(
+ PaddingModifier(
+ start = left,
+ top = top,
+ end = right,
+ bottom = bottom,
+ rtlAware = false
+ )
+)
+
+@GlanceInternalApi
+data class PaddingModifier(
+ val start: Dp = 0.dp,
+ val top: Dp = 0.dp,
+ val end: Dp = 0.dp,
+ val bottom: Dp = 0.dp,
+ val rtlAware: Boolean
+) : Modifier.Element
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/unit/Dp.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/unit/Dp.kt
new file mode 100644
index 0000000..3e59bab
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/unit/Dp.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.unit
+
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * Dimension value representing device-independent pixels (dp). Component APIs specify their
+ * dimensions such as line thickness in DP with Dp objects. Dp are normally defined using [dp],
+ * which can be applied to [Int], [Double], and [Float].
+ * val leftMargin = 10.dp
+ * val rightMargin = 10f.dp
+ * val topMargin = 20.0.dp
+ * val bottomMargin = 10.dp
+ */
+@Suppress("INLINE_CLASS_DEPRECATED", "EXPERIMENTAL_FEATURE_WARNING")
+inline class Dp(val value: Float) : Comparable<Dp> {
+ /**
+ * Add two [Dp]s together.
+ */
+ operator fun plus(other: Dp) =
+ Dp(value = this.value + other.value)
+
+ /**
+ * Subtract a Dp from another one.
+ */
+ operator fun minus(other: Dp) =
+ Dp(value = this.value - other.value)
+
+ /**
+ * This is the same as multiplying the Dp by -1.0.
+ */
+ operator fun unaryMinus() = Dp(-value)
+
+ /**
+ * Divide a Dp by a scalar.
+ */
+ operator fun div(other: Float): Dp =
+ Dp(value = value / other)
+
+ operator fun div(other: Int): Dp =
+ Dp(value = value / other)
+
+ /**
+ * Divide by another Dp to get a scalar.
+ */
+ operator fun div(other: Dp): Float = value / other.value
+
+ /**
+ * Multiply a Dp by a scalar.
+ */
+ operator fun times(other: Float): Dp =
+ Dp(value = value * other)
+
+ operator fun times(other: Int): Dp =
+ Dp(value = value * other)
+
+ /**
+ * Support comparing Dimensions with comparison operators.
+ */
+ override /* TODO: inline */ operator fun compareTo(other: Dp) = value.compareTo(other.value)
+
+ override fun toString() = if (isUnspecified) "Dp.Unspecified" else "$value.dp"
+
+ companion object {
+ /**
+ * Constant that means unspecified Dp
+ */
+ val Unspecified = Dp(value = Float.NaN)
+ }
+}
+
+/**
+ * `false` when this is [Dp.Unspecified].
+ */
+inline val Dp.isSpecified: Boolean
+ get() = !value.isNaN()
+
+/**
+ * `true` when this is [Dp.Unspecified].
+ */
+inline val Dp.isUnspecified: Boolean
+ get() = value.isNaN()
+
+/**
+ * Create a [Dp] using an [Int]:
+ * val left = 10
+ * val x = left.dp
+ * // -- or --
+ * val y = 10.dp
+ */
+inline val Int.dp: Dp get() = Dp(value = this.toFloat())
+
+/**
+ * Create a [Dp] using a [Double]:
+ * val left = 10.0
+ * val x = left.dp
+ * // -- or --
+ * val y = 10.0.dp
+ */
+inline val Double.dp: Dp get() = Dp(value = this.toFloat())
+
+/**
+ * Create a [Dp] using a [Float]:
+ * val left = 10f
+ * val x = left.dp
+ * // -- or --
+ * val y = 10f.dp
+ */
+inline val Float.dp: Dp get() = Dp(value = this)
+
+operator fun Float.times(other: Dp) =
+ Dp(this * other.value)
+
+operator fun Double.times(other: Dp) =
+ Dp(this.toFloat() * other.value)
+
+operator fun Int.times(other: Dp) =
+ Dp(this * other.value)
+
+fun min(a: Dp, b: Dp): Dp = Dp(value = min(a.value, b.value))
+
+fun max(a: Dp, b: Dp): Dp = Dp(value = max(a.value, b.value))
diff --git a/glance/glance/src/test/kotlin/androidx/glance/ApplierTest.kt b/glance/glance/src/test/kotlin/androidx/glance/ApplierTest.kt
new file mode 100644
index 0000000..740994c
--- /dev/null
+++ b/glance/glance/src/test/kotlin/androidx/glance/ApplierTest.kt
@@ -0,0 +1,111 @@
+@file:OptIn(GlanceInternalApi::class)
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ApplierTest {
+
+ @Test
+ fun onClear() {
+ val root = RootEmittable()
+ val applier = Applier(root)
+ updateApplier(applier)
+ applier.clear()
+
+ assertThat(applier.current).isEqualTo(root)
+ assertThat(root.children).isEmpty()
+ }
+
+ @Test
+ fun insertTopDown() {
+ val root = RootEmittable()
+ val applier = Applier(root)
+
+ updateApplier(applier)
+
+ assertThat(root.children).hasSize(3)
+ assertThat(root.children[0]).isInstanceOf(LeafEmittable::class.java)
+ assertThat(root.children[2]).isInstanceOf(LeafEmittable::class.java)
+ assertThat(root.children[1]).isInstanceOf(MiddleEmittable::class.java)
+ assertThat((root.children[1] as MiddleEmittable).children).hasSize(1)
+ }
+
+ @Test
+ fun insertBottomUp() {
+ val root = RootEmittable()
+ val applier = Applier(root)
+
+ applier.insertBottomUp(0, LeafEmittable())
+
+ assertThat(root.children).isEmpty()
+ }
+
+ @Test
+ fun move() {
+ val root = RootEmittable()
+ val applier = Applier(root)
+ updateApplier(applier)
+ applier.up()
+
+ applier.move(0, 2, 1)
+
+ assertThat(root.children).hasSize(3)
+ assertThat(root.children[1]).isInstanceOf(LeafEmittable::class.java)
+ assertThat(root.children[2]).isInstanceOf(LeafEmittable::class.java)
+ assertThat(root.children[0]).isInstanceOf(MiddleEmittable::class.java)
+ assertThat((root.children[0] as MiddleEmittable).children).hasSize(1)
+ }
+
+ @Test
+ fun remove() {
+ val root = RootEmittable()
+ val applier = Applier(root)
+ updateApplier(applier)
+ applier.up()
+
+ applier.remove(1, 2)
+
+ assertThat(root.children).hasSize(1)
+ assertThat(root.children[0]).isInstanceOf(LeafEmittable::class.java)
+ }
+
+ private companion object {
+ fun updateApplier(applier: Applier) {
+ val middle = MiddleEmittable()
+ applier.insertTopDown(0, LeafEmittable())
+ applier.insertTopDown(1, middle)
+ applier.insertTopDown(2, LeafEmittable())
+ applier.down(middle)
+ applier.insertTopDown(0, LeafEmittable())
+ }
+ }
+}
+
+private class RootEmittable : EmittableWithChildren() {
+ override var modifier: Modifier = Modifier
+}
+
+private class MiddleEmittable : EmittableWithChildren() {
+ override var modifier: Modifier = Modifier
+}
+
+private class LeafEmittable : Emittable {
+ override var modifier: Modifier = Modifier
+}
diff --git a/glance/glance/src/test/kotlin/androidx/glance/CombinedModifierTest.kt b/glance/glance/src/test/kotlin/androidx/glance/CombinedModifierTest.kt
new file mode 100644
index 0000000..7eb7b70
--- /dev/null
+++ b/glance/glance/src/test/kotlin/androidx/glance/CombinedModifierTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.glance
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class CombinedModifierTest {
+ @Test
+ fun foldIn() {
+ assertThat(
+ testModifier.foldIn(listOf<Int>()) { lst, m ->
+ if (m is Element) lst + m.value else lst
+ }
+ ).isEqualTo(listOf(1, 2, 3))
+ }
+
+ @Test
+ fun foldOut() {
+ assertThat(
+ testModifier.foldOut(listOf<Int>()) { m, lst ->
+ if (m is Element) lst + m.value else lst
+ }
+ ).isEqualTo(listOf(3, 2, 1))
+ }
+
+ @Test
+ fun any() {
+ assertThat(testModifier.any { it == Element(1) }).isTrue()
+ assertThat(testModifier.any { it == Element(2) }).isTrue()
+ assertThat(testModifier.any { it == Element(3) }).isTrue()
+ assertThat(testModifier.any { it == Element(5) }).isFalse()
+ }
+
+ @Test
+ fun all() {
+ assertThat(testModifier.all { it is Element && it.value < 10 }).isTrue()
+ assertThat(testModifier.all { it is Element && it.value > 2 }).isFalse()
+ }
+
+ @Test
+ fun equals() {
+ assertThat(testModifier).isEqualTo(Modifier.element(1).element(2).element(3))
+ assertThat(testModifier).isNotEqualTo(Modifier.element(1).element(2).element(4))
+ assertThat(testModifier).isNotEqualTo(Modifier.element(1).element(2))
+ assertThat(testModifier).isNotEqualTo(Modifier)
+ }
+
+ private companion object {
+ val testModifier = Modifier.element(1).element(2).element(3)
+ }
+}
+
+private data class Element(val value: Int) : Modifier.Element
+
+private fun Modifier.element(value: Int) =
+ this.then(Element(value))
\ No newline at end of file
diff --git a/glance/glance/src/test/kotlin/androidx/glance/layout/PaddingTest.kt b/glance/glance/src/test/kotlin/androidx/glance/layout/PaddingTest.kt
new file mode 100644
index 0000000..86c2f25
--- /dev/null
+++ b/glance/glance/src/test/kotlin/androidx/glance/layout/PaddingTest.kt
@@ -0,0 +1,102 @@
+@file:OptIn(GlanceInternalApi::class)
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.glance.layout
+
+import androidx.glance.GlanceInternalApi
+import androidx.glance.Modifier
+import androidx.glance.unit.dp
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class PaddingTest {
+ @Test
+ fun buildPadding() {
+ val modifiers = Modifier.padding(
+ start = 1.dp,
+ top = 2.dp,
+ end = 3.dp,
+ bottom = 4.dp
+ )
+
+ // Find the padding modifier...
+ val paddingModifier = modifiers.findPaddingModifier()
+
+ // Use Kotlin require here; it has a non-null contract, so we don't need to qualify
+ // future accesses to paddingModifier.
+ requireNotNull(paddingModifier)
+
+ assertThat(paddingModifier.rtlAware).isTrue()
+ assertThat(paddingModifier.start).isEqualTo(1.dp)
+ assertThat(paddingModifier.top).isEqualTo(2.dp)
+ assertThat(paddingModifier.end).isEqualTo(3.dp)
+ assertThat(paddingModifier.bottom).isEqualTo(4.dp)
+ }
+
+ @Test
+ fun buildVerticalHorizontalPadding() {
+ val modifiers = Modifier.padding(vertical = 2.dp, horizontal = 4.dp)
+
+ val paddingModifier = modifiers.findPaddingModifier()
+ requireNotNull(paddingModifier)
+
+ assertThat(paddingModifier.start).isEqualTo(4.dp)
+ assertThat(paddingModifier.top).isEqualTo(2.dp)
+ assertThat(paddingModifier.end).isEqualTo(4.dp)
+ assertThat(paddingModifier.bottom).isEqualTo(2.dp)
+ }
+
+ @Test
+ fun buildAllPadding() {
+ val modifiers = Modifier.padding(all = 5.dp)
+
+ val paddingModifier = modifiers.findPaddingModifier()
+ requireNotNull(paddingModifier)
+
+ assertThat(paddingModifier.start).isEqualTo(5.dp)
+ assertThat(paddingModifier.top).isEqualTo(5.dp)
+ assertThat(paddingModifier.end).isEqualTo(5.dp)
+ assertThat(paddingModifier.bottom).isEqualTo(5.dp)
+ }
+
+ @Test
+ fun buildAbsolutePadding() {
+ val modifiers = Modifier.absolutePadding(
+ left = 1.dp,
+ top = 2.dp,
+ right = 3.dp,
+ bottom = 4.dp
+ )
+
+ val paddingModifier = modifiers.findPaddingModifier()
+ requireNotNull(paddingModifier)
+
+ assertThat(paddingModifier.rtlAware).isFalse()
+ assertThat(paddingModifier.start).isEqualTo(1.dp)
+ assertThat(paddingModifier.top).isEqualTo(2.dp)
+ assertThat(paddingModifier.end).isEqualTo(3.dp)
+ assertThat(paddingModifier.bottom).isEqualTo(4.dp)
+ }
+
+ private fun Modifier.findPaddingModifier(): PaddingModifier? =
+ this.foldOut<PaddingModifier?>(null) { cur, acc ->
+ if (cur is PaddingModifier) {
+ cur
+ } else {
+ acc
+ }
+ }
+}
diff --git a/glance/glance/src/test/kotlin/androidx/glance/unit/DpTest.kt b/glance/glance/src/test/kotlin/androidx/glance/unit/DpTest.kt
new file mode 100644
index 0000000..c7956af
--- /dev/null
+++ b/glance/glance/src/test/kotlin/androidx/glance/unit/DpTest.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.unit
+
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class DpTest {
+
+ @Test
+ fun constructor() {
+ val dim1 = Dp(value = 5f)
+ assertEquals(5f, dim1.value, 0f)
+
+ val dim2 = Dp(value = Float.POSITIVE_INFINITY)
+ assertEquals(Float.POSITIVE_INFINITY, dim2.value, 0f)
+
+ val dim3 = Dp(value = Float.NaN)
+ assertEquals(Float.NaN, dim3.value, 0f)
+ }
+
+ @Test
+ fun dpIntegerConstruction() {
+ val dim = 10.dp
+ assertEquals(10f, dim.value, 0f)
+ }
+
+ @Test
+ fun dpFloatConstruction() {
+ val dim = 10f.dp
+ assertEquals(10f, dim.value, 0f)
+ }
+
+ @Test
+ fun dpDoubleConstruction() {
+ val dim = 10.0.dp
+ assertEquals(10f, dim.value, 0f)
+ }
+
+ @Test
+ fun subtractOperator() {
+ assertEquals(-1f, (3.dp - 4.dp).value)
+ assertEquals(1f, (10.dp - 9.dp).value, 0f)
+ }
+
+ @Test
+ fun addOperator() {
+ assertEquals(2f, (1.dp + 1.dp).value, 0f)
+ assertEquals(10f, (6.dp + 4.dp).value, 0f)
+ }
+
+ @Test
+ fun multiplyOperator() {
+ assertEquals(0f, (1.dp * 0f).value, 0f)
+ assertEquals(10f, (1.dp * 10f).value, 0f)
+ }
+
+ @Test
+ fun multiplyOperatorScalar() {
+ assertEquals(10f, 10f * 1.dp.value, 0f)
+ assertEquals(10f, 10 * 1.dp.value, 0f)
+ assertEquals(10f, (10.0 * 1.dp).value, 0f)
+ }
+
+ @Test
+ fun divideOperator() {
+ assertEquals(10f, 100.dp / 10f.dp, 0f)
+ assertEquals(0f, 0.dp / 10f.dp, 0f)
+ }
+
+ @Test
+ fun divideToScalar() {
+ assertEquals(1f, 1.dp / 1.dp, 0f)
+ }
+
+ @Suppress("DIVISION_BY_ZERO")
+ @Test
+ fun compare() {
+ assertTrue(0.dp < Float.MIN_VALUE.dp)
+ assertTrue(1.dp < 3.dp)
+ assertEquals(0, 1.dp.compareTo(1.dp))
+ assertTrue(1.dp > 0.dp)
+ assertTrue(Float.NEGATIVE_INFINITY.dp < 0.dp)
+
+ val zeroNaN = 0f / 0f
+ val infNaN = Float.POSITIVE_INFINITY / Float.NEGATIVE_INFINITY
+ assertEquals(0, zeroNaN.dp.compareTo(zeroNaN.dp))
+ assertEquals(0, infNaN.dp.compareTo(infNaN.dp))
+ }
+
+ @Test
+ fun minTest() {
+ assertEquals(10f, min(10.dp, 20.dp).value, 0f)
+ assertEquals(10f, min(20.dp, 10.dp).value, 0f)
+ assertEquals(10f, min(10.dp, 10.dp).value, 0f)
+ }
+
+ @Test
+ fun maxTest() {
+ assertEquals(20f, max(10.dp, 20.dp).value, 0f)
+ assertEquals(20f, max(20.dp, 10.dp).value, 0f)
+ assertEquals(20f, max(20.dp, 20.dp).value, 0f)
+ }
+
+ @Test
+ fun coerceIn() {
+ assertEquals(10f, 10.dp.coerceIn(0.dp, 20.dp).value, 0f)
+ assertEquals(10f, 20.dp.coerceIn(0.dp, 10.dp).value, 0f)
+ assertEquals(10f, 0.dp.coerceIn(10.dp, 20.dp).value, 0f)
+ try {
+ 10.dp.coerceIn(20.dp, 10.dp)
+ fail("Expected an exception here")
+ } catch (e: IllegalArgumentException) {
+ // success!
+ }
+ }
+
+ @Test
+ fun coerceAtLeast() {
+ assertEquals(10f, 0.dp.coerceAtLeast(10.dp).value, 0f)
+ assertEquals(10f, 10.dp.coerceAtLeast(5.dp).value, 0f)
+ assertEquals(10f, 10.dp.coerceAtLeast(10.dp).value, 0f)
+ }
+
+ @Test
+ fun coerceAtMost() {
+ assertEquals(10f, 100.dp.coerceAtMost(10.dp).value, 0f)
+ assertEquals(10f, 10.dp.coerceAtMost(20.dp).value, 0f)
+ assertEquals(10f, 10.dp.coerceAtMost(10.dp).value, 0f)
+ }
+
+ @Test
+ fun testIsSpecified() {
+ Assert.assertFalse(Dp.Unspecified.isSpecified)
+ assertTrue(Dp(1f).isSpecified)
+ }
+
+ @Test
+ fun testIsUnspecified() {
+ assertTrue(Dp.Unspecified.isUnspecified)
+ Assert.assertFalse(Dp(1f).isUnspecified)
+ }
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index aa33055..64c9a2b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,6 +15,8 @@
kotlin.mpp.stability.nowarn=true
# Workaround for b/141364941
android.forceJacocoOutOfProcess=true
+
+# Generate versioned API files
androidx.writeVersionedApiFiles=true
# Disable features we do not use
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 45e5b4e..7adf9d4 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,13 +2,13 @@
# -----------------------------------------------------------------------------
# All of the following should be updated in sync.
# -----------------------------------------------------------------------------
-androidGradlePlugin = "7.1.0-alpha06"
+androidGradlePlugin = "7.1.0-alpha07"
# NOTE: When updating the lint version we also need to update the `api` version
# supported by `IssueRegistry`'s.' For e.g. r.android.com/1331903
-androidLint = "30.1.0-alpha06"
+androidLint = "30.1.0-alpha07"
# Once you have a chosen version of AGP to upgrade to, go to
# https://developer.android.com/studio/archive and find the matching version of Studio.
-androidStudio = "2021.1.1.6"
+androidStudio = "2021.1.1.7"
# -----------------------------------------------------------------------------
androidLintMin = "27.2.1"
diff --git a/health/health-services-client/lint-baseline.xml b/health/health-services-client/lint-baseline.xml
index 2569c46..5171b78 100644
--- a/health/health-services-client/lint-baseline.xml
+++ b/health/health-services-client/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
<issue
id="BanKeepAnnotation"
@@ -475,6 +475,17 @@
</issue>
<issue
+ id="VisibleForTests"
+ message="This method should only be accessed from tests or within private scope"
+ errorLine1=" get() = ServiceBackedMeasureClient.getClient(applicationContext)"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/health/services/client/impl/ServiceBackedHealthServicesClient.kt"
+ line="46"
+ column="44"/>
+ </issue>
+
+ <issue
id="SyntheticAccessor"
message="Access to `private` method `createQueueOperation` of class `Client` requires synthetic accessor"
errorLine1=" createQueueOperation("
diff --git a/jetifier/jetifier/migration.config b/jetifier/jetifier/migration.config
index 9dbd915..758d728 100644
--- a/jetifier/jetifier/migration.config
+++ b/jetifier/jetifier/migration.config
@@ -263,10 +263,6 @@
"to": "androidx/lifecycle/{0}"
},
{
- "from": "android/arch/persistence/room/(.*)",
- "to": "androidx/room/{0}"
- },
- {
"from": "android/support/constraint/solver/(.*)",
"to": "androidx/constraintlayout/solver/{0}"
},
@@ -313,15 +309,19 @@
"to": "ignore"
},
{
+ "from": "androidx/appcompat/view/ContextThemeWrapper(.*)",
+ "to": "ignore"
+ },
+ {
"from": "androidx/core/content/ContextCompat(.*)",
"to": "ignore"
},
{
- "from": "androidx/core/content/CustomUnusedAppRestrictionsBackportService(.*)",
+ "from": "androidx/core/content/UnusedAppRestrictionsBackportCallback(.*)",
"to": "ignore"
},
{
- "from": "androidx/core/content/UnusedAppRestrictionsBackportCallback(.*)",
+ "from": "androidx/core/content/UnusedAppRestrictionsBackportService(.*)",
"to": "ignore"
},
{
@@ -481,6 +481,10 @@
"to": "ignore"
},
{
+ "from": "androidx/room/(.*)",
+ "to": "ignore"
+ },
+ {
"from": "androidx/fragment/app/DefaultSpecialEffectsController(.*)",
"to": "android/support/v4/app/DefaultSpecialEffectsController{0}"
},
@@ -541,6 +545,14 @@
"to": "ignore"
},
{
+ "from": "androidx/lifecycle/LifecycleOwner(.*)",
+ "to": "ignore"
+ },
+ {
+ "from": "androidx/lifecycle/Lifecycle(.*)",
+ "to": "ignore"
+ },
+ {
"from": "androidx/test(.*)",
"to": "ignore"
},
@@ -1053,6 +1065,10 @@
"to": "android/support/v4/widget/annotations"
},
{
+ "from": "androidx/viewpager/widget/annotations",
+ "to": "android/support/v4/view/annotations"
+ },
+ {
"from": "androidx/annotation/experimental/(.*)",
"to": "ignore"
},
@@ -1297,7 +1313,7 @@
{
"from": "androidx/wear/complications",
"to": "androidx/wear/complications"
- },
+ },
{
"from": "androidx/wear/input",
"to": "androidx/wear/input"
@@ -1403,26 +1419,42 @@
"to": "androidx/sqlite/db"
},
{
- "from": "android/arch/persistence/room/rxjava2",
+ "from": "androidx/room/rxjava2",
"to": "androidx/room/rxjava2"
},
{
- "from": "android/arch/persistence/room/rxjava3",
+ "from": "androidx/room/rxjava3",
"to": "androidx/room/rxjava3"
},
{
- "from": "android/arch/persistence/room/guava",
+ "from": "androidx/room/guava",
"to": "androidx/room/guava"
},
{
- "from": "android/arch/persistence/room/testing",
+ "from": "androidx/room/testing",
"to": "androidx/room/testing"
},
{
- "from": "android/arch/persistence/room",
+ "from": "androidx/room",
"to": "androidx/room"
},
{
+ "from": "androidx/room/compiler",
+ "to": "androidx/room/compiler"
+ },
+ {
+ "from": "androidx/room/runtime",
+ "to": "androidx/room/runtime"
+ },
+ {
+ "from": "androidx/room/common",
+ "to": "androidx/room/common"
+ },
+ {
+ "from": "androidx/room/migration",
+ "to": "androidx/room/migration"
+ },
+ {
"from": "android/arch/lifecycle/extensions",
"to": "androidx/lifecycle/extensions"
},
@@ -1790,9 +1822,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
+ "groupId": "androidx.room",
"artifactId": "room-coroutines",
- "version": "{oldRoomVersion}"
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3050,9 +3082,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
+ "groupId": "androidx.room",
"artifactId": "room-ktx",
- "version": "{oldRoomVersion}"
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3170,9 +3202,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "common",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-common",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3182,9 +3214,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "compiler",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-compiler",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3194,9 +3226,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "migration",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-migration",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3206,9 +3238,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "runtime",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-runtime",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3218,9 +3250,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "rxjava2",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-rxjava2",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3230,9 +3262,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "rxjava3",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-rxjava3",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3242,9 +3274,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "testing",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-testing",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3254,9 +3286,9 @@
},
{
"from": {
- "groupId": "android.arch.persistence.room",
- "artifactId": "guava",
- "version": "{oldRoomVersion}"
+ "groupId": "androidx.room",
+ "artifactId": "room-guava",
+ "version": "{newRoomVersion}"
},
"to": {
"groupId": "androidx.room",
@@ -3864,12 +3896,11 @@
"android/arch/lifecycle/GenericLifecycleObserver": "androidx/lifecycle/GenericLifecycleObserver",
"android/arch/lifecycle/HolderFragment": "androidx/lifecycle/HolderFragment",
"android/arch/lifecycle/Input_collectorKt": "androidx/lifecycle/Input_collectorKt",
- "android/arch/lifecycle/Lifecycle": "androidx/lifecycle/Lifecycle",
- "android/arch/lifecycle/LifecycleOwner": "androidx/lifecycle/LifecycleOwner",
"android/arch/lifecycle/LifecycleProcessor": "androidx/lifecycle/LifecycleProcessor",
"android/arch/lifecycle/LifecycleRegistry": "androidx/lifecycle/LifecycleRegistry",
"android/arch/lifecycle/LifecycleRegistryOwner": "androidx/lifecycle/LifecycleRegistryOwner",
"android/arch/lifecycle/LifecycleService": "androidx/lifecycle/LifecycleService",
+ "android/arch/lifecycle/LifecycleEventObserver": "androidx/lifecycle/LifecycleEventObserver",
"android/arch/lifecycle/Lifecycling": "androidx/lifecycle/Lifecycling",
"android/arch/lifecycle/LiveData": "androidx/lifecycle/LiveData",
"android/arch/lifecycle/LiveDataReactiveStreams": "androidx/lifecycle/LiveDataReactiveStreams",
@@ -3898,215 +3929,6 @@
"android/arch/lifecycle/model/EventMethodCall": "androidx/lifecycle/model/EventMethodCall",
"android/arch/lifecycle/model/InputModel": "androidx/lifecycle/model/InputModel",
"android/arch/lifecycle/model/LifecycleObserverInfo": "androidx/lifecycle/model/LifecycleObserverInfo",
- "android/arch/persistence/room/ColumnInfo": "androidx/room/ColumnInfo",
- "android/arch/persistence/room/Dao": "androidx/room/Dao",
- "android/arch/persistence/room/Database": "androidx/room/Database",
- "android/arch/persistence/room/DatabaseConfiguration": "androidx/room/DatabaseConfiguration",
- "android/arch/persistence/room/Delete": "androidx/room/Delete",
- "android/arch/persistence/room/Embedded": "androidx/room/Embedded",
- "android/arch/persistence/room/EmptyResultSetException": "androidx/room/EmptyResultSetException",
- "android/arch/persistence/room/Entity": "androidx/room/Entity",
- "android/arch/persistence/room/EntityDeletionOrUpdateAdapter": "androidx/room/EntityDeletionOrUpdateAdapter",
- "android/arch/persistence/room/EntityInsertionAdapter": "androidx/room/EntityInsertionAdapter",
- "android/arch/persistence/room/ForeignKey": "androidx/room/ForeignKey",
- "android/arch/persistence/room/Ignore": "androidx/room/Ignore",
- "android/arch/persistence/room/Index": "androidx/room/Index",
- "android/arch/persistence/room/Insert": "androidx/room/Insert",
- "android/arch/persistence/room/InvalidationTracker": "androidx/room/InvalidationTracker",
- "android/arch/persistence/room/OnConflictStrategy": "androidx/room/OnConflictStrategy",
- "android/arch/persistence/room/PrimaryKey": "androidx/room/PrimaryKey",
- "android/arch/persistence/room/Query": "androidx/room/Query",
- "android/arch/persistence/room/RawQuery": "androidx/room/RawQuery",
- "android/arch/persistence/room/Relation": "androidx/room/Relation",
- "android/arch/persistence/room/Room": "androidx/room/Room",
- "android/arch/persistence/room/RoomDatabase": "androidx/room/RoomDatabase",
- "android/arch/persistence/room/RoomMasterTable": "androidx/room/RoomMasterTable",
- "android/arch/persistence/room/RoomOpenHelper": "androidx/room/RoomOpenHelper",
- "android/arch/persistence/room/RoomProcessor": "androidx/room/RoomProcessor",
- "android/arch/persistence/room/RoomSQLiteQuery": "androidx/room/RoomSQLiteQuery",
- "android/arch/persistence/room/RoomWarnings": "androidx/room/RoomWarnings",
- "android/arch/persistence/room/RxRoom": "androidx/room/RxRoom",
- "android/arch/persistence/room/SharedSQLiteStatement": "androidx/room/SharedSQLiteStatement",
- "android/arch/persistence/room/SkipQueryVerification": "androidx/room/SkipQueryVerification",
- "android/arch/persistence/room/Transaction": "androidx/room/Transaction",
- "android/arch/persistence/room/TypeConverter": "androidx/room/TypeConverter",
- "android/arch/persistence/room/TypeConverters": "androidx/room/TypeConverters",
- "android/arch/persistence/room/Update": "androidx/room/Update",
- "android/arch/persistence/room/ext/AndroidTypeNames": "androidx/room/ext/AndroidTypeNames",
- "android/arch/persistence/room/ext/ArchTypeNames": "androidx/room/ext/ArchTypeNames",
- "android/arch/persistence/room/ext/CommonTypeNames": "androidx/room/ext/CommonTypeNames",
- "android/arch/persistence/room/ext/Element_extKt": "androidx/room/ext/Element_extKt",
- "android/arch/persistence/room/ext/GuavaBaseTypeNames": "androidx/room/ext/GuavaBaseTypeNames",
- "android/arch/persistence/room/ext/GuavaUtilConcurrentTypeNames": "androidx/room/ext/GuavaUtilConcurrentTypeNames",
- "android/arch/persistence/room/ext/Javapoet_extKt": "androidx/room/ext/Javapoet_extKt",
- "android/arch/persistence/room/ext/KotlinMetadataProcessor": "androidx/room/ext/KotlinMetadataProcessor",
- "android/arch/persistence/room/ext/LifecyclesTypeNames": "androidx/room/ext/LifecyclesTypeNames",
- "android/arch/persistence/room/ext/PagingTypeNames": "androidx/room/ext/PagingTypeNames",
- "android/arch/persistence/room/ext/ReactiveStreamsTypeNames": "androidx/room/ext/ReactiveStreamsTypeNames",
- "android/arch/persistence/room/ext/RoomGuavaTypeNames": "androidx/room/ext/RoomGuavaTypeNames",
- "android/arch/persistence/room/ext/RoomRxJava2TypeNames": "androidx/room/ext/RoomRxJava2TypeNames",
- "android/arch/persistence/room/ext/RoomTypeNames": "androidx/room/ext/RoomTypeNames",
- "android/arch/persistence/room/ext/RxJava2TypeNames": "androidx/room/ext/RxJava2TypeNames",
- "android/arch/persistence/room/ext/SupportDbTypeNames": "androidx/room/ext/SupportDbTypeNames",
- "android/arch/persistence/room/guava/GuavaRoom": "androidx/room/guava/GuavaRoom",
- "android/arch/persistence/room/log/RLog": "androidx/room/log/RLog",
- "android/arch/persistence/room/migration/Migration": "androidx/room/migration/Migration",
- "android/arch/persistence/room/migration/bundle/BundleUtil": "androidx/room/migration/bundle/BundleUtil",
- "android/arch/persistence/room/migration/bundle/DatabaseBundle": "androidx/room/migration/bundle/DatabaseBundle",
- "android/arch/persistence/room/migration/bundle/EntityBundle": "androidx/room/migration/bundle/EntityBundle",
- "android/arch/persistence/room/migration/bundle/FieldBundle": "androidx/room/migration/bundle/FieldBundle",
- "android/arch/persistence/room/migration/bundle/ForeignKeyBundle": "androidx/room/migration/bundle/ForeignKeyBundle",
- "android/arch/persistence/room/migration/bundle/IndexBundle": "androidx/room/migration/bundle/IndexBundle",
- "android/arch/persistence/room/migration/bundle/PrimaryKeyBundle": "androidx/room/migration/bundle/PrimaryKeyBundle",
- "android/arch/persistence/room/migration/bundle/SchemaBundle": "androidx/room/migration/bundle/SchemaBundle",
- "android/arch/persistence/room/migration/bundle/SchemaEquality": "androidx/room/migration/bundle/SchemaEquality",
- "android/arch/persistence/room/migration/bundle/SchemaEqualityUtil": "androidx/room/migration/bundle/SchemaEqualityUtil",
- "android/arch/persistence/room/paging/LimitOffsetDataSource": "androidx/room/paging/LimitOffsetDataSource",
- "android/arch/persistence/room/parser/Collate": "androidx/room/parser/Collate",
- "android/arch/persistence/room/parser/ParsedQuery": "androidx/room/parser/ParsedQuery",
- "android/arch/persistence/room/parser/ParserErrors": "androidx/room/parser/ParserErrors",
- "android/arch/persistence/room/parser/QueryType": "androidx/room/parser/QueryType",
- "android/arch/persistence/room/parser/QueryVisitor": "androidx/room/parser/QueryVisitor",
- "android/arch/persistence/room/parser/SQLTypeAffinity": "androidx/room/parser/SQLTypeAffinity",
- "android/arch/persistence/room/parser/SQLiteBaseListener": "androidx/room/parser/SQLiteBaseListener",
- "android/arch/persistence/room/parser/SQLiteBaseVisitor": "androidx/room/parser/SQLiteBaseVisitor",
- "android/arch/persistence/room/parser/SQLiteLexer": "androidx/room/parser/SQLiteLexer",
- "android/arch/persistence/room/parser/SQLiteListener": "androidx/room/parser/SQLiteListener",
- "android/arch/persistence/room/parser/SQLiteParser": "androidx/room/parser/SQLiteParser",
- "android/arch/persistence/room/parser/SQLiteVisitor": "androidx/room/parser/SQLiteVisitor",
- "android/arch/persistence/room/parser/Section": "androidx/room/parser/Section",
- "android/arch/persistence/room/parser/SectionType": "androidx/room/parser/SectionType",
- "android/arch/persistence/room/parser/SqlParser": "androidx/room/parser/SqlParser",
- "android/arch/persistence/room/parser/Table": "androidx/room/parser/Table",
- "android/arch/persistence/room/preconditions/Checks": "androidx/room/preconditions/Checks",
- "android/arch/persistence/room/processor/Context": "androidx/room/processor/Context",
- "android/arch/persistence/room/processor/CustomConverterProcessor": "androidx/room/processor/CustomConverterProcessor",
- "android/arch/persistence/room/processor/DaoProcessor": "androidx/room/processor/DaoProcessor",
- "android/arch/persistence/room/processor/DatabaseProcessor": "androidx/room/processor/DatabaseProcessor",
- "android/arch/persistence/room/processor/DeletionMethodProcessor": "androidx/room/processor/DeletionMethodProcessor",
- "android/arch/persistence/room/processor/EntityProcessor": "androidx/room/processor/EntityProcessor",
- "android/arch/persistence/room/processor/FieldProcessor": "androidx/room/processor/FieldProcessor",
- "android/arch/persistence/room/processor/InsertionMethodProcessor": "androidx/room/processor/InsertionMethodProcessor",
- "android/arch/persistence/room/processor/OnConflictProcessor": "androidx/room/processor/OnConflictProcessor",
- "android/arch/persistence/room/processor/PojoMethodProcessor": "androidx/room/processor/PojoMethodProcessor",
- "android/arch/persistence/room/processor/PojoProcessor": "androidx/room/processor/PojoProcessor",
- "android/arch/persistence/room/processor/ProcessorErrors": "androidx/room/processor/ProcessorErrors",
- "android/arch/persistence/room/processor/QueryMethodProcessor": "androidx/room/processor/QueryMethodProcessor",
- "android/arch/persistence/room/processor/QueryParameterProcessor": "androidx/room/processor/QueryParameterProcessor",
- "android/arch/persistence/room/processor/RawQueryMethodProcessor": "androidx/room/processor/RawQueryMethodProcessor",
- "android/arch/persistence/room/processor/ShortcutMethodProcessor": "androidx/room/processor/ShortcutMethodProcessor",
- "android/arch/persistence/room/processor/ShortcutParameterProcessor": "androidx/room/processor/ShortcutParameterProcessor",
- "android/arch/persistence/room/processor/SuppressWarningProcessor": "androidx/room/processor/SuppressWarningProcessor",
- "android/arch/persistence/room/processor/TransactionMethodProcessor": "androidx/room/processor/TransactionMethodProcessor",
- "android/arch/persistence/room/processor/UpdateMethodProcessor": "androidx/room/processor/UpdateMethodProcessor",
- "android/arch/persistence/room/processor/cache/Cache": "androidx/room/processor/cache/Cache",
- "android/arch/persistence/room/solver/CodeGenScope": "androidx/room/solver/CodeGenScope",
- "android/arch/persistence/room/solver/ObservableQueryResultBinderProvider": "androidx/room/solver/ObservableQueryResultBinderProvider",
- "android/arch/persistence/room/solver/QueryResultBinderProvider": "androidx/room/solver/QueryResultBinderProvider",
- "android/arch/persistence/room/solver/TypeAdapterStore": "androidx/room/solver/TypeAdapterStore",
- "android/arch/persistence/room/solver/binderprovider/CursorQueryResultBinderProvider": "androidx/room/solver/binderprovider/CursorQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider": "androidx/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider": "androidx/room/solver/binderprovider/DataSourceQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider": "androidx/room/solver/binderprovider/FlowableQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/GuavaListenableFutureQueryResultBinderProvider": "androidx/room/solver/binderprovider/GuavaListenableFutureQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider": "androidx/room/solver/binderprovider/InstantQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider": "androidx/room/solver/binderprovider/LiveDataQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider": "androidx/room/solver/binderprovider/RxCallableQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/RxMaybeQueryResultBinderProvider": "androidx/room/solver/binderprovider/RxMaybeQueryResultBinderProvider",
- "android/arch/persistence/room/solver/binderprovider/RxSingleQueryResultBinderProvider": "androidx/room/solver/binderprovider/RxSingleQueryResultBinderProvider",
- "android/arch/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter": "androidx/room/solver/query/parameter/ArrayQueryParameterAdapter",
- "android/arch/persistence/room/solver/query/parameter/BasicQueryParameterAdapter": "androidx/room/solver/query/parameter/BasicQueryParameterAdapter",
- "android/arch/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter": "androidx/room/solver/query/parameter/CollectionQueryParameterAdapter",
- "android/arch/persistence/room/solver/query/parameter/QueryParameterAdapter": "androidx/room/solver/query/parameter/QueryParameterAdapter",
- "android/arch/persistence/room/solver/query/result/ArrayQueryResultAdapter": "androidx/room/solver/query/result/ArrayQueryResultAdapter",
- "android/arch/persistence/room/solver/query/result/BaseObservableQueryResultBinder": "androidx/room/solver/query/result/BaseObservableQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/CursorQueryResultBinder": "androidx/room/solver/query/result/CursorQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/DataSourceFactoryQueryResultBinder": "androidx/room/solver/query/result/DataSourceFactoryQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/EntityRowAdapter": "androidx/room/solver/query/result/EntityRowAdapter",
- "android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder": "androidx/room/solver/query/result/FlowableQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/GuavaListenableFutureQueryResultBinder": "androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/GuavaOptionalQueryResultAdapter": "androidx/room/solver/query/result/GuavaOptionalQueryResultAdapter",
- "android/arch/persistence/room/solver/query/result/InstantQueryResultBinder": "androidx/room/solver/query/result/InstantQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/ListQueryResultAdapter": "androidx/room/solver/query/result/ListQueryResultAdapter",
- "android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder": "androidx/room/solver/query/result/LiveDataQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/OptionalQueryResultAdapter": "androidx/room/solver/query/result/OptionalQueryResultAdapter",
- "android/arch/persistence/room/solver/query/result/PojoRowAdapter": "androidx/room/solver/query/result/PojoRowAdapter",
- "android/arch/persistence/room/solver/query/result/PositionalDataSourceQueryResultBinder": "androidx/room/solver/query/result/PositionalDataSourceQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/QueryResultAdapter": "androidx/room/solver/query/result/QueryResultAdapter",
- "android/arch/persistence/room/solver/query/result/QueryResultBinder": "androidx/room/solver/query/result/QueryResultBinder",
- "android/arch/persistence/room/solver/query/result/RowAdapter": "androidx/room/solver/query/result/RowAdapter",
- "android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder": "androidx/room/solver/query/result/RxCallableQueryResultBinder",
- "android/arch/persistence/room/solver/query/result/SingleColumnRowAdapter": "androidx/room/solver/query/result/SingleColumnRowAdapter",
- "android/arch/persistence/room/solver/query/result/SingleEntityQueryResultAdapter": "androidx/room/solver/query/result/SingleEntityQueryResultAdapter",
- "android/arch/persistence/room/solver/query/result/TransactionWrapper": "androidx/room/solver/query/result/TransactionWrapper",
- "android/arch/persistence/room/solver/query/result/TransactionWrapperKt": "androidx/room/solver/query/result/TransactionWrapperKt",
- "android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter": "androidx/room/solver/types/BoxedBooleanToBoxedIntConverter",
- "android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter": "androidx/room/solver/types/BoxedPrimitiveColumnTypeAdapter",
- "android/arch/persistence/room/solver/types/ByteArrayColumnTypeAdapter": "androidx/room/solver/types/ByteArrayColumnTypeAdapter",
- "android/arch/persistence/room/solver/types/ColumnTypeAdapter": "androidx/room/solver/types/ColumnTypeAdapter",
- "android/arch/persistence/room/solver/types/CompositeAdapter": "androidx/room/solver/types/CompositeAdapter",
- "android/arch/persistence/room/solver/types/CompositeTypeConverter": "androidx/room/solver/types/CompositeTypeConverter",
- "android/arch/persistence/room/solver/types/CursorValueReader": "androidx/room/solver/types/CursorValueReader",
- "android/arch/persistence/room/solver/types/CustomTypeConverterWrapper": "androidx/room/solver/types/CustomTypeConverterWrapper",
- "android/arch/persistence/room/solver/types/NoOpConverter": "androidx/room/solver/types/NoOpConverter",
- "android/arch/persistence/room/solver/types/PrimitiveBooleanToIntConverter": "androidx/room/solver/types/PrimitiveBooleanToIntConverter",
- "android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter": "androidx/room/solver/types/PrimitiveColumnTypeAdapter",
- "android/arch/persistence/room/solver/types/StatementValueBinder": "androidx/room/solver/types/StatementValueBinder",
- "android/arch/persistence/room/solver/types/StringColumnTypeAdapter": "androidx/room/solver/types/StringColumnTypeAdapter",
- "android/arch/persistence/room/solver/types/TypeConverter": "androidx/room/solver/types/TypeConverter",
- "android/arch/persistence/room/testing/MigrationTestHelper": "androidx/room/testing/MigrationTestHelper",
- "android/arch/persistence/room/util/StringUtil": "androidx/room/util/StringUtil",
- "android/arch/persistence/room/util/TableInfo": "androidx/room/util/TableInfo",
- "android/arch/persistence/room/verifier/ColumnInfo": "androidx/room/verifier/ColumnInfo",
- "android/arch/persistence/room/verifier/DatabaseVerificaitonErrors": "androidx/room/verifier/DatabaseVerificaitonErrors",
- "android/arch/persistence/room/verifier/DatabaseVerifier": "androidx/room/verifier/DatabaseVerifier",
- "android/arch/persistence/room/verifier/QueryResultInfo": "androidx/room/verifier/QueryResultInfo",
- "android/arch/persistence/room/vo/CallType": "androidx/room/vo/CallType",
- "android/arch/persistence/room/vo/Constructor": "androidx/room/vo/Constructor",
- "android/arch/persistence/room/vo/CustomTypeConverter": "androidx/room/vo/CustomTypeConverter",
- "android/arch/persistence/room/vo/Dao": "androidx/room/vo/Dao",
- "android/arch/persistence/room/vo/DaoMethod": "androidx/room/vo/DaoMethod",
- "android/arch/persistence/room/vo/Database": "androidx/room/vo/Database",
- "android/arch/persistence/room/vo/DeletionMethod": "androidx/room/vo/DeletionMethod",
- "android/arch/persistence/room/vo/EmbeddedField": "androidx/room/vo/EmbeddedField",
- "android/arch/persistence/room/vo/Entity": "androidx/room/vo/Entity",
- "android/arch/persistence/room/vo/Field": "androidx/room/vo/Field",
- "android/arch/persistence/room/vo/FieldGetter": "androidx/room/vo/FieldGetter",
- "android/arch/persistence/room/vo/FieldSetter": "androidx/room/vo/FieldSetter",
- "android/arch/persistence/room/vo/FieldWithIndex": "androidx/room/vo/FieldWithIndex",
- "android/arch/persistence/room/vo/ForeignKey": "androidx/room/vo/ForeignKey",
- "android/arch/persistence/room/vo/ForeignKeyAction": "androidx/room/vo/ForeignKeyAction",
- "android/arch/persistence/room/vo/HasSchemaIdentity": "androidx/room/vo/HasSchemaIdentity",
- "android/arch/persistence/room/vo/Index": "androidx/room/vo/Index",
- "android/arch/persistence/room/vo/InsertionMethod": "androidx/room/vo/InsertionMethod",
- "android/arch/persistence/room/vo/Pojo": "androidx/room/vo/Pojo",
- "android/arch/persistence/room/vo/PojoMethod": "androidx/room/vo/PojoMethod",
- "android/arch/persistence/room/vo/PrimaryKey": "androidx/room/vo/PrimaryKey",
- "android/arch/persistence/room/vo/QueryMethod": "androidx/room/vo/QueryMethod",
- "android/arch/persistence/room/vo/QueryParameter": "androidx/room/vo/QueryParameter",
- "android/arch/persistence/room/vo/RawQueryMethod": "androidx/room/vo/RawQueryMethod",
- "android/arch/persistence/room/vo/Relation": "androidx/room/vo/Relation",
- "android/arch/persistence/room/vo/RelationCollector": "androidx/room/vo/RelationCollector",
- "android/arch/persistence/room/vo/SchemaIdentityKey": "androidx/room/vo/SchemaIdentityKey",
- "android/arch/persistence/room/vo/ShortcutMethod": "androidx/room/vo/ShortcutMethod",
- "android/arch/persistence/room/vo/ShortcutQueryParameter": "androidx/room/vo/ShortcutQueryParameter",
- "android/arch/persistence/room/vo/TransactionMethod": "androidx/room/vo/TransactionMethod",
- "android/arch/persistence/room/vo/UpdateMethod": "androidx/room/vo/UpdateMethod",
- "android/arch/persistence/room/vo/Warning": "androidx/room/vo/Warning",
- "android/arch/persistence/room/writer/ClassWriter": "androidx/room/writer/ClassWriter",
- "android/arch/persistence/room/writer/DaoWriter": "androidx/room/writer/DaoWriter",
- "android/arch/persistence/room/writer/DatabaseWriter": "androidx/room/writer/DatabaseWriter",
- "android/arch/persistence/room/writer/EntityCursorConverterWriter": "androidx/room/writer/EntityCursorConverterWriter",
- "android/arch/persistence/room/writer/EntityDeleteComparator": "androidx/room/writer/EntityDeleteComparator",
- "android/arch/persistence/room/writer/EntityDeletionAdapterWriter": "androidx/room/writer/EntityDeletionAdapterWriter",
- "android/arch/persistence/room/writer/EntityInsertionAdapterWriter": "androidx/room/writer/EntityInsertionAdapterWriter",
- "android/arch/persistence/room/writer/EntityUpdateAdapterWriter": "androidx/room/writer/EntityUpdateAdapterWriter",
- "android/arch/persistence/room/writer/FieldReadWriteWriter": "androidx/room/writer/FieldReadWriteWriter",
- "android/arch/persistence/room/writer/PreparedStatementWriter": "androidx/room/writer/PreparedStatementWriter",
- "android/arch/persistence/room/writer/QueryWriter": "androidx/room/writer/QueryWriter",
- "android/arch/persistence/room/writer/RelationCollectorMethodWriter": "androidx/room/writer/RelationCollectorMethodWriter",
- "android/arch/persistence/room/writer/SQLiteOpenHelperWriter": "androidx/room/writer/SQLiteOpenHelperWriter",
- "android/arch/persistence/room/writer/TableInfoValidationWriter": "androidx/room/writer/TableInfoValidationWriter",
"android/databinding/BaseObservable": "androidx/databinding/BaseObservable",
"android/databinding/BaseObservableField": "androidx/databinding/BaseObservableField",
"android/databinding/Bindable": "androidx/databinding/Bindable",
@@ -4483,7 +4305,6 @@
"android/support/v7/view/ActionBarPolicy": "androidx/appcompat/view/ActionBarPolicy",
"android/support/v7/view/ActionMode": "androidx/appcompat/view/ActionMode",
"android/support/v7/view/CollapsibleActionView": "androidx/appcompat/view/CollapsibleActionView",
- "android/support/v7/view/ContextThemeWrapper": "androidx/appcompat/view/ContextThemeWrapper",
"android/support/v7/view/StandaloneActionMode": "androidx/appcompat/view/StandaloneActionMode",
"android/support/v7/view/SupportActionModeWrapper": "androidx/appcompat/view/SupportActionModeWrapper",
"android/support/v7/view/SupportMenuInflater": "androidx/appcompat/view/SupportMenuInflater",
diff --git a/leanback/leanback-paging/build.gradle b/leanback/leanback-paging/build.gradle
index 72cc71c..579f307 100644
--- a/leanback/leanback-paging/build.gradle
+++ b/leanback/leanback-paging/build.gradle
@@ -14,6 +14,10 @@
api("androidx.leanback:leanback:1.1.0-beta01")
api("androidx.paging:paging-runtime:3.0.0")
+ // To avoid manifest merger warnings due to duplicate package names
+ // It can be removed if leanback library is updated to a newer version
+ implementation("androidx.vectordrawable:vectordrawable-animated:1.1.0")
+
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRunner)
diff --git a/leanback/leanback-tab/build.gradle b/leanback/leanback-tab/build.gradle
index f7db959..0f7b64b 100644
--- a/leanback/leanback-tab/build.gradle
+++ b/leanback/leanback-tab/build.gradle
@@ -12,6 +12,10 @@
api("com.google.android.material:material:1.0.0")
api("androidx.viewpager:viewpager:1.0.0")
+ // To avoid manifest merger warnings due to duplicate package names
+ // It can be removed if material library is updated to a newer version
+ implementation("androidx.vectordrawable:vectordrawable-animated:1.1.0")
+
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testRunner)
diff --git a/leanback/leanback/build.gradle b/leanback/leanback/build.gradle
index 7f7d047..b6dc59a 100644
--- a/leanback/leanback/build.gradle
+++ b/leanback/leanback/build.gradle
@@ -17,6 +17,10 @@
api("androidx.recyclerview:recyclerview:1.2.0-rc01")
api("androidx.appcompat:appcompat:1.0.0")
+ // To avoid manifest merger warnings due to duplicate package names
+ // It can be removed if appcompat library is updated to a newer version
+ implementation("androidx.vectordrawable:vectordrawable-animated:1.1.0")
+
androidTestImplementation(libs.kotlinStdlib)
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
diff --git a/leanback/leanback/src/main/res/values-te/strings.xml b/leanback/leanback/src/main/res/values-te/strings.xml
index b3b1751..e56c5cb 100644
--- a/leanback/leanback/src/main/res/values-te/strings.xml
+++ b/leanback/leanback/src/main/res/values-te/strings.xml
@@ -43,8 +43,8 @@
<string name="lb_playback_controls_repeat_one" msgid="676658705837320560">"ఒకదాన్ని పునరావృతం చేయి"</string>
<string name="lb_playback_controls_shuffle_enable" msgid="5151681938752704485">"షఫుల్ చేయడాన్ని ప్రారంభించు"</string>
<string name="lb_playback_controls_shuffle_disable" msgid="6793109999253893369">"షఫుల్ చేయడాన్ని నిలిపివేయి"</string>
- <string name="lb_playback_controls_high_quality_enable" msgid="3057698527166674705">"అధిక నాణ్యతను ప్రారంభించు"</string>
- <string name="lb_playback_controls_high_quality_disable" msgid="1209119371486219736">"అధిక నాణ్యతను నిలిపివేయి"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="3057698527166674705">"అధిక క్వాలిటీని ప్రారంభించు"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="1209119371486219736">"అధిక క్వాలిటీని నిలిపివేయి"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2346334170216706076">"మూసివేసిన శీర్షికలను ప్రారంభించు"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="8691966842977635128">"మూసివేసిన శీర్షికలను నిలిపివేయి"</string>
<string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"చిత్రంలో చిత్రం మోడ్లోకి ప్రవేశించు"</string>
diff --git a/lifecycle/integration-tests/kotlintestapp/src/main/AndroidManifest.xml b/lifecycle/integration-tests/kotlintestapp/src/main/AndroidManifest.xml
index d662e79..629de7d 100644
--- a/lifecycle/integration-tests/kotlintestapp/src/main/AndroidManifest.xml
+++ b/lifecycle/integration-tests/kotlintestapp/src/main/AndroidManifest.xml
@@ -17,7 +17,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.lifecycle.kotlintestapp">
<application>
- <activity android:name="androidx.lifecycle.kotlintestapp.TestActivity">
+ <activity
+ android:name="androidx.lifecycle.kotlintestapp.TestActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml b/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml
index 19166dd..3e6ef7d 100644
--- a/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -11,37 +11,50 @@
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" package="androidx.lifecycle.testapp">
+ xmlns:tools="http://schemas.android.com/tools"
+ package="androidx.lifecycle.testapp">
- <application android:allowBackup="true" android:label="Test App" android:supportsRtl="true"
+ <application
+ android:allowBackup="true"
+ android:label="Test App"
+ android:supportsRtl="true"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon">
- <activity android:name="androidx.lifecycle.testapp.LifecycleTestActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="androidx.lifecycle.testapp.CollectingSupportActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="androidx.lifecycle.testapp.FrameworkLifecycleRegistryActivity">
+ <activity
+ android:name="androidx.lifecycle.testapp.LifecycleTestActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
- android:name="androidx.lifecycle.testapp.SimpleAppLifecycleTestActivity">
+ android:name="androidx.lifecycle.testapp.CollectingSupportActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.lifecycle.testapp.NavigationTestActivityFirst"
+ <activity
+ android:name="androidx.lifecycle.testapp.FrameworkLifecycleRegistryActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="androidx.lifecycle.testapp.SimpleAppLifecycleTestActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="androidx.lifecycle.testapp.NavigationTestActivityFirst"
+ android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -49,16 +62,23 @@
</intent-filter>
</activity>
<activity
- android:name="androidx.lifecycle.testapp.EmptyActivity">
+ android:name="androidx.lifecycle.testapp.EmptyActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".NavigationTestActivitySecond" />
- <activity android:name=".NavigationDialogActivity"
+ <activity
+ android:name=".NavigationTestActivitySecond"
+ android:exported="false" />
+ <activity
+ android:name=".NavigationDialogActivity"
+ android:exported="false"
android:launchMode="singleTask"
android:theme="@android:style/Theme.DeviceDefault.Dialog" />
- <activity android:name=".NonSupportActivity"/>
+ <activity
+ android:name=".NonSupportActivity"
+ android:exported="false" />
</application>
</manifest>
diff --git a/lifecycle/lifecycle-extensions/build.gradle b/lifecycle/lifecycle-extensions/build.gradle
index fd2e937..e2a5747 100644
--- a/lifecycle/lifecycle-extensions/build.gradle
+++ b/lifecycle/lifecycle-extensions/build.gradle
@@ -47,7 +47,7 @@
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.testRules)
androidTestImplementation(libs.espressoCore)
- androidTestImplementation("androidx.appcompat:appcompat:1.0.0")
+ androidTestImplementation("androidx.appcompat:appcompat:1.1.0")
androidTestImplementation(project(":internal-testutils-runtime"))
}
diff --git a/lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt b/lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt
index 5244c46..a6cb3a9 100644
--- a/lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt
+++ b/lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt
@@ -454,7 +454,7 @@
* }
* ```
*
- * * @param context The CoroutineContext to run the given block in. Defaults to
+ * @param context The CoroutineContext to run the given block in. Defaults to
* [EmptyCoroutineContext] combined with
* [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate].
* @param timeout The timeout duration before cancelling the block if there are no active observers
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/current.ignore b/lifecycle/lifecycle-viewmodel-ktx/api/current.ignore
new file mode 100644
index 0000000..9974337
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/current.ignore
@@ -0,0 +1,7 @@
+// Baseline format: 1.0
+RemovedClass: androidx.lifecycle.ViewModelLazy:
+ Removed class androidx.lifecycle.ViewModelLazy
+RemovedClass: androidx.lifecycle.ViewModelProviderKt:
+ Removed class androidx.lifecycle.ViewModelProviderKt
+RemovedClass: androidx.lifecycle.ViewTreeViewModelKt:
+ Removed class androidx.lifecycle.ViewTreeViewModelKt
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/current.txt b/lifecycle/lifecycle-viewmodel-ktx/api/current.txt
index a03be13..1d1d247 100644
--- a/lifecycle/lifecycle-viewmodel-ktx/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/current.txt
@@ -5,20 +5,5 @@
method public static kotlinx.coroutines.CoroutineScope getViewModelScope(androidx.lifecycle.ViewModel);
}
- public final class ViewModelLazy<VM extends androidx.lifecycle.ViewModel> implements kotlin.Lazy<VM> {
- ctor public ViewModelLazy(kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory> factoryProducer);
- method public VM getValue();
- method public boolean isInitialized();
- property public VM value;
- }
-
- public final class ViewModelProviderKt {
- method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> VM! get(androidx.lifecycle.ViewModelProvider);
- }
-
- public final class ViewTreeViewModelKt {
- method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
- }
-
}
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/public_plus_experimental_current.txt b/lifecycle/lifecycle-viewmodel-ktx/api/public_plus_experimental_current.txt
index a03be13..1d1d247 100644
--- a/lifecycle/lifecycle-viewmodel-ktx/api/public_plus_experimental_current.txt
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/public_plus_experimental_current.txt
@@ -5,20 +5,5 @@
method public static kotlinx.coroutines.CoroutineScope getViewModelScope(androidx.lifecycle.ViewModel);
}
- public final class ViewModelLazy<VM extends androidx.lifecycle.ViewModel> implements kotlin.Lazy<VM> {
- ctor public ViewModelLazy(kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory> factoryProducer);
- method public VM getValue();
- method public boolean isInitialized();
- property public VM value;
- }
-
- public final class ViewModelProviderKt {
- method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> VM! get(androidx.lifecycle.ViewModelProvider);
- }
-
- public final class ViewTreeViewModelKt {
- method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
- }
-
}
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/restricted_current.ignore b/lifecycle/lifecycle-viewmodel-ktx/api/restricted_current.ignore
new file mode 100644
index 0000000..9974337
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/restricted_current.ignore
@@ -0,0 +1,7 @@
+// Baseline format: 1.0
+RemovedClass: androidx.lifecycle.ViewModelLazy:
+ Removed class androidx.lifecycle.ViewModelLazy
+RemovedClass: androidx.lifecycle.ViewModelProviderKt:
+ Removed class androidx.lifecycle.ViewModelProviderKt
+RemovedClass: androidx.lifecycle.ViewTreeViewModelKt:
+ Removed class androidx.lifecycle.ViewTreeViewModelKt
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel-ktx/api/restricted_current.txt
index a03be13..1d1d247 100644
--- a/lifecycle/lifecycle-viewmodel-ktx/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/restricted_current.txt
@@ -5,20 +5,5 @@
method public static kotlinx.coroutines.CoroutineScope getViewModelScope(androidx.lifecycle.ViewModel);
}
- public final class ViewModelLazy<VM extends androidx.lifecycle.ViewModel> implements kotlin.Lazy<VM> {
- ctor public ViewModelLazy(kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory> factoryProducer);
- method public VM getValue();
- method public boolean isInitialized();
- property public VM value;
- }
-
- public final class ViewModelProviderKt {
- method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> VM! get(androidx.lifecycle.ViewModelProvider);
- }
-
- public final class ViewTreeViewModelKt {
- method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
- }
-
}
diff --git a/lifecycle/lifecycle-viewmodel-ktx/build.gradle b/lifecycle/lifecycle-viewmodel-ktx/build.gradle
index 43af991..af9ab1f 100644
--- a/lifecycle/lifecycle-viewmodel-ktx/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-ktx/build.gradle
@@ -29,9 +29,6 @@
api(libs.kotlinStdlib)
api(libs.kotlinCoroutinesAndroid)
- testImplementation(libs.junit)
- testImplementation(libs.truth)
-
androidTestImplementation(libs.truth)
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
diff --git a/lifecycle/lifecycle-viewmodel-ktx/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt b/lifecycle/lifecycle-viewmodel-ktx/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
deleted file mode 100644
index 13b6d06..0000000
--- a/lifecycle/lifecycle-viewmodel-ktx/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.lifecycle
-
-import android.view.View
-import android.view.ViewGroup
-import android.widget.FrameLayout
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.google.common.truth.Truth.assertWithMessage
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class ViewTreeViewModelStoreOwnerTest {
- /**
- * Tests that a direct set/get on a single view survives a round trip
- */
- @Test
- fun setGetSameView() {
- val v = View(InstrumentationRegistry.getInstrumentation().context)
-
- assertWithMessage("initial ViewModelStoreOwner expects null")
- .that(v.findViewTreeViewModelStoreOwner())
- .isNull()
-
- val fakeOwner: ViewModelStoreOwner = FakeViewModelStoreOwner()
- ViewTreeViewModelStoreOwner.set(v, fakeOwner)
-
- assertWithMessage("get the ViewModelStoreOwner set directly")
- .that(v.findViewTreeViewModelStoreOwner())
- .isEqualTo(fakeOwner)
- }
-
- /**
- * Tests that the owner set on a root of a subhierarchy is seen by both direct children
- * and other descendants
- */
- @Test
- fun getAncestorOwner() {
- val context = InstrumentationRegistry.getInstrumentation().context
- val root: ViewGroup = FrameLayout(context)
- val parent: ViewGroup = FrameLayout(context)
- val child = View(context)
- root.addView(parent)
- parent.addView(child)
-
- assertWithMessage("initial ViewModelStoreOwner expects null")
- .that(child.findViewTreeViewModelStoreOwner())
- .isNull()
-
- val fakeOwner: ViewModelStoreOwner = FakeViewModelStoreOwner()
- ViewTreeViewModelStoreOwner.set(root, fakeOwner)
-
- assertWithMessage("root sees owner")
- .that(root.findViewTreeViewModelStoreOwner())
- .isEqualTo(fakeOwner)
- assertWithMessage("direct child sees owner")
- .that(parent.findViewTreeViewModelStoreOwner())
- .isEqualTo(fakeOwner)
- assertWithMessage("grandchild sees owner")
- .that(child.findViewTreeViewModelStoreOwner())
- .isEqualTo(fakeOwner)
- }
-
- /**
- * Tests that a new owner set between a root and a descendant is seen by the descendant
- * instead of the root value
- */
- @Test
- fun shadowedOwner() {
- val context =
- InstrumentationRegistry.getInstrumentation().context
- val root: ViewGroup = FrameLayout(context)
- val parent: ViewGroup = FrameLayout(context)
- val child = View(context)
- root.addView(parent)
- parent.addView(child)
-
- assertWithMessage("initial ViewModelStoreOwner expects null")
- .that(child.findViewTreeViewModelStoreOwner())
- .isNull()
-
- val rootFakeOwner: ViewModelStoreOwner = FakeViewModelStoreOwner()
- ViewTreeViewModelStoreOwner.set(root, rootFakeOwner)
-
- val parentFakeOwner: ViewModelStoreOwner = FakeViewModelStoreOwner()
- ViewTreeViewModelStoreOwner.set(parent, parentFakeOwner)
-
- assertWithMessage("root sees owner")
- .that(root.findViewTreeViewModelStoreOwner())
- .isEqualTo(rootFakeOwner)
- assertWithMessage("direct child sees owner")
- .that(parent.findViewTreeViewModelStoreOwner())
- .isEqualTo(parentFakeOwner)
- assertWithMessage("grandchild sees owner")
- .that(child.findViewTreeViewModelStoreOwner())
- .isEqualTo(parentFakeOwner)
- }
-
- internal class FakeViewModelStoreOwner : ViewModelStoreOwner {
- override fun getViewModelStore(): ViewModelStore {
- throw UnsupportedOperationException("not a real ViewModelStoreOwner")
- }
- }
-}
diff --git a/lifecycle/lifecycle-viewmodel-ktx/src/main/java/androidx/lifecycle/ViewModelProviderExtensions.kt b/lifecycle/lifecycle-viewmodel-ktx/src/main/java/androidx/lifecycle/ViewModelProviderExtensions.kt
deleted file mode 100644
index e87e103..0000000
--- a/lifecycle/lifecycle-viewmodel-ktx/src/main/java/androidx/lifecycle/ViewModelProviderExtensions.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 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.
- */
-
-@file:JvmName("ViewModelProviderKt")
-package androidx.lifecycle
-
-import androidx.annotation.MainThread
-import kotlin.reflect.KClass
-
-/**
- * Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or
- * an activity), associated with this `ViewModelProvider`.
- *
- * @see ViewModelProvider.get(Class)
- */
-@MainThread
-public inline fun <reified VM : ViewModel> ViewModelProvider.get(): VM = get(VM::class.java)
-
-/**
- * An implementation of [Lazy] used by [androidx.fragment.app.Fragment.viewModels] and
- * [androidx.activity.ComponentActivity.viewmodels].
- *
- * [storeProducer] is a lambda that will be called during initialization, [VM] will be created
- * in the scope of returned [ViewModelStore].
- *
- * [factoryProducer] is a lambda that will be called during initialization,
- * returned [ViewModelProvider.Factory] will be used for creation of [VM]
- */
-public class ViewModelLazy<VM : ViewModel> (
- private val viewModelClass: KClass<VM>,
- private val storeProducer: () -> ViewModelStore,
- private val factoryProducer: () -> ViewModelProvider.Factory
-) : Lazy<VM> {
- private var cached: VM? = null
-
- override val value: VM
- get() {
- val viewModel = cached
- return if (viewModel == null) {
- val factory = factoryProducer()
- val store = storeProducer()
- ViewModelProvider(store, factory).get(viewModelClass.java).also {
- cached = it
- }
- } else {
- viewModel
- }
- }
-
- override fun isInitialized(): Boolean = cached != null
-}
diff --git a/lifecycle/lifecycle-viewmodel-ktx/src/test/java/androidx/lifecycle/ViewModelProviderTest.kt b/lifecycle/lifecycle-viewmodel-ktx/src/test/java/androidx/lifecycle/ViewModelProviderTest.kt
deleted file mode 100644
index 30650fd..0000000
--- a/lifecycle/lifecycle-viewmodel-ktx/src/test/java/androidx/lifecycle/ViewModelProviderTest.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.lifecycle
-
-import org.junit.Assert.assertNotNull
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ViewModelProviderTest {
- class TestViewModel : ViewModel()
-
- @Test
- fun providerReifiedGet() {
- val factory = object : ViewModelProvider.Factory {
- override fun <T : ViewModel> create(modelClass: Class<T>) = modelClass.newInstance()
- }
- val provider = ViewModelProvider(ViewModelStore(), factory)
-
- val viewModel = provider.get<TestViewModel>()
- assertNotNull(viewModel)
- }
-}
diff --git a/lifecycle/lifecycle-viewmodel/api/current.txt b/lifecycle/lifecycle-viewmodel/api/current.txt
index 2668991..b2a64d8 100644
--- a/lifecycle/lifecycle-viewmodel/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/current.txt
@@ -15,6 +15,13 @@
method protected void onCleared();
}
+ public final class ViewModelLazy<VM extends androidx.lifecycle.ViewModel> implements kotlin.Lazy<VM> {
+ ctor public ViewModelLazy(kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory> factoryProducer);
+ method public VM getValue();
+ method public boolean isInitialized();
+ property public VM value;
+ }
+
public class ViewModelProvider {
ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore store, androidx.lifecycle.ViewModelProvider.Factory factory);
ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner);
@@ -46,6 +53,10 @@
public static final class ViewModelProvider.NewInstanceFactory.Companion {
}
+ public final class ViewModelProviderKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> VM! get(androidx.lifecycle.ViewModelProvider);
+ }
+
public class ViewModelStore {
ctor public ViewModelStore();
method public final void clear();
@@ -55,6 +66,10 @@
method public androidx.lifecycle.ViewModelStore getViewModelStore();
}
+ public final class ViewTreeViewModelKt {
+ method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
+ }
+
public class ViewTreeViewModelStoreOwner {
method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner?);
diff --git a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
index 2668991..b2a64d8 100644
--- a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
@@ -15,6 +15,13 @@
method protected void onCleared();
}
+ public final class ViewModelLazy<VM extends androidx.lifecycle.ViewModel> implements kotlin.Lazy<VM> {
+ ctor public ViewModelLazy(kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory> factoryProducer);
+ method public VM getValue();
+ method public boolean isInitialized();
+ property public VM value;
+ }
+
public class ViewModelProvider {
ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore store, androidx.lifecycle.ViewModelProvider.Factory factory);
ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner);
@@ -46,6 +53,10 @@
public static final class ViewModelProvider.NewInstanceFactory.Companion {
}
+ public final class ViewModelProviderKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> VM! get(androidx.lifecycle.ViewModelProvider);
+ }
+
public class ViewModelStore {
ctor public ViewModelStore();
method public final void clear();
@@ -55,6 +66,10 @@
method public androidx.lifecycle.ViewModelStore getViewModelStore();
}
+ public final class ViewTreeViewModelKt {
+ method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
+ }
+
public class ViewTreeViewModelStoreOwner {
method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner?);
diff --git a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
index 27904ad..13ea048 100644
--- a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
@@ -15,6 +15,13 @@
method protected void onCleared();
}
+ public final class ViewModelLazy<VM extends androidx.lifecycle.ViewModel> implements kotlin.Lazy<VM> {
+ ctor public ViewModelLazy(kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory> factoryProducer);
+ method public VM getValue();
+ method public boolean isInitialized();
+ property public VM value;
+ }
+
public class ViewModelProvider {
ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore store, androidx.lifecycle.ViewModelProvider.Factory factory);
ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner);
@@ -58,6 +65,10 @@
method public void onRequery(androidx.lifecycle.ViewModel viewModel);
}
+ public final class ViewModelProviderKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> VM! get(androidx.lifecycle.ViewModelProvider);
+ }
+
public class ViewModelStore {
ctor public ViewModelStore();
method public final void clear();
@@ -67,6 +78,10 @@
method public androidx.lifecycle.ViewModelStore getViewModelStore();
}
+ public final class ViewTreeViewModelKt {
+ method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
+ }
+
public class ViewTreeViewModelStoreOwner {
method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner?);
diff --git a/lifecycle/lifecycle-viewmodel/build.gradle b/lifecycle/lifecycle-viewmodel/build.gradle
index ca85890..aceb9ec 100644
--- a/lifecycle/lifecycle-viewmodel/build.gradle
+++ b/lifecycle/lifecycle-viewmodel/build.gradle
@@ -35,6 +35,7 @@
api(libs.kotlinStdlib)
testImplementation(libs.junit)
testImplementation(libs.mockitoCore)
+ testImplementation(libs.truth)
androidTestImplementation(libs.truth)
androidTestImplementation(libs.kotlinStdlib)
diff --git a/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt b/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
index 41f5ea4..f466eef 100644
--- a/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
+++ b/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
@@ -48,6 +48,25 @@
}
/**
+ * minimal test that checks View.findViewTreeViewModelStoreOwner works
+ */
+ @Test
+ fun setFindsSameView() {
+ val v = View(InstrumentationRegistry.getInstrumentation().context)
+
+ assertWithMessage("initial ViewModelStoreOwner expects null")
+ .that(v.findViewTreeViewModelStoreOwner())
+ .isNull()
+
+ val fakeOwner: ViewModelStoreOwner = FakeViewModelStoreOwner()
+ ViewTreeViewModelStoreOwner.set(v, fakeOwner)
+
+ assertWithMessage("get the ViewModelStoreOwner set directly")
+ .that(v.findViewTreeViewModelStoreOwner())
+ .isEqualTo(fakeOwner)
+ }
+
+ /**
* Tests that the owner set on a root of a subhierarchy is seen by both direct children
* and other descendants
*/
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelLazy.kt b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelLazy.kt
new file mode 100644
index 0000000..1e29d7f
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelLazy.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.lifecycle
+
+import kotlin.reflect.KClass
+
+/**
+ * An implementation of [Lazy] used by [androidx.fragment.app.Fragment.viewModels] and
+ * [androidx.activity.ComponentActivity.viewmodels].
+ *
+ * [storeProducer] is a lambda that will be called during initialization, [VM] will be created
+ * in the scope of returned [ViewModelStore].
+ *
+ * [factoryProducer] is a lambda that will be called during initialization,
+ * returned [ViewModelProvider.Factory] will be used for creation of [VM]
+ */
+public class ViewModelLazy<VM : ViewModel> (
+ private val viewModelClass: KClass<VM>,
+ private val storeProducer: () -> ViewModelStore,
+ private val factoryProducer: () -> ViewModelProvider.Factory
+) : Lazy<VM> {
+ private var cached: VM? = null
+
+ override val value: VM
+ get() {
+ val viewModel = cached
+ return if (viewModel == null) {
+ val factory = factoryProducer()
+ val store = storeProducer()
+ ViewModelProvider(store, factory).get(viewModelClass.java).also {
+ cached = it
+ }
+ } else {
+ viewModel
+ }
+ }
+
+ override fun isInitialized(): Boolean = cached != null
+}
\ No newline at end of file
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt
index 9911c2a..82a33cc 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt
@@ -263,3 +263,12 @@
}
}
}
+
+/**
+ * Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or
+ * an activity), associated with this `ViewModelProvider`.
+ *
+ * @see ViewModelProvider.get(Class)
+ */
+@MainThread
+public inline fun <reified VM : ViewModel> ViewModelProvider.get(): VM = get(VM::class.java)
diff --git a/lifecycle/lifecycle-viewmodel-ktx/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt
similarity index 100%
rename from lifecycle/lifecycle-viewmodel-ktx/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt
rename to lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt
diff --git a/lifecycle/lifecycle-viewmodel-ktx/src/test/java/androidx/lifecycle/ViewModelLazyTest.kt b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelLazyTest.kt
similarity index 100%
rename from lifecycle/lifecycle-viewmodel-ktx/src/test/java/androidx/lifecycle/ViewModelLazyTest.kt
rename to lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelLazyTest.kt
diff --git a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderReifiedTest.kt b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderReifiedTest.kt
new file mode 100644
index 0000000..0a702cf
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderReifiedTest.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.lifecycle
+
+import org.junit.Assert.assertNotNull
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ViewModelProviderReifiedTest {
+ class TestViewModel : ViewModel()
+
+ @Test
+ fun providerReifiedGet() {
+ val factory = object : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>) = modelClass.newInstance()
+ }
+ val provider = ViewModelProvider(ViewModelStore(), factory)
+
+ val viewModel = provider.get<TestViewModel>()
+ assertNotNull(viewModel)
+ }
+}
diff --git a/lint-demos/lint-demo-appcompat/src/main/AndroidManifest.xml b/lint-demos/lint-demo-appcompat/src/main/AndroidManifest.xml
index fbf85c7..337e3cc 100644
--- a/lint-demos/lint-demo-appcompat/src/main/AndroidManifest.xml
+++ b/lint-demos/lint-demo-appcompat/src/main/AndroidManifest.xml
@@ -16,15 +16,18 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.appcompat">
+
<application
+ android:allowBackup="false"
android:hardwareAccelerated="true"
android:icon="@drawable/app_sample_code"
android:label="@string/activity_sample_code"
- android:allowBackup="false"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat">
- <activity android:name=".AppCompatLintDemo">
+ <activity
+ android:name=".AppCompatLintDemo"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java b/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
index 3547de9..db3b6c6 100644
--- a/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -73,7 +73,6 @@
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.app.BundleCompat;
-import androidx.core.os.BuildCompat;
import androidx.media.MediaSessionManager;
import androidx.media.MediaSessionManager.RemoteUserInfo;
import androidx.media.VolumeProviderCompat;
@@ -126,14 +125,6 @@
public class MediaSessionCompat {
static final String TAG = "MediaSessionCompat";
- // TODO(b/182513352): Use PendingIntent.FLAG_MUTABLE instead from S.
- /**
- * @hide
- */
- @RestrictTo(LIBRARY)
- public static final int PENDING_INTENT_FLAG_MUTABLE =
- BuildCompat.isAtLeastS() ? 0x02000000 : 0;
-
private final MediaSessionImpl mImpl;
private final MediaControllerCompat mController;
private final ArrayList<OnActiveChangeListener> mActiveListeners = new ArrayList<>();
@@ -543,7 +534,6 @@
* @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX) // accessed by media2-session
- @SuppressLint("WrongConstant") // PENDING_INTENT_FLAG_MUTABLE
public MediaSessionCompat(@NonNull Context context, @NonNull String tag,
@Nullable ComponentName mbrComponent, @Nullable PendingIntent mbrIntent,
@Nullable Bundle sessionInfo, @Nullable VersionedParcelable session2Token) {
@@ -568,7 +558,7 @@
mediaButtonIntent.setComponent(mbrComponent);
mbrIntent = PendingIntent.getBroadcast(context,
0/* requestCode, ignored */, mediaButtonIntent,
- PENDING_INTENT_FLAG_MUTABLE);
+ Build.VERSION.SDK_INT >= 31 ? PendingIntent.FLAG_MUTABLE : 0);
}
if (android.os.Build.VERSION.SDK_INT >= 21) {
diff --git a/media/media/src/main/java/androidx/media/session/MediaButtonReceiver.java b/media/media/src/main/java/androidx/media/session/MediaButtonReceiver.java
index 0d8dea6..f131f65 100644
--- a/media/media/src/main/java/androidx/media/session/MediaButtonReceiver.java
+++ b/media/media/src/main/java/androidx/media/session/MediaButtonReceiver.java
@@ -16,11 +16,8 @@
package androidx.media.session;
-import static android.support.v4.media.session.MediaSessionCompat.PENDING_INTENT_FLAG_MUTABLE;
-
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
-import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
@@ -255,7 +252,6 @@
* @return Created pending intent, or null if the given component name is null or the
* {@code action} is unsupported/invalid.
*/
- @SuppressLint("WrongConstant") // PENDING_INTENT_FLAG_MUTABLE
public static PendingIntent buildMediaButtonPendingIntent(Context context,
ComponentName mbrComponent, @MediaKeyAction long action) {
if (mbrComponent == null) {
@@ -274,7 +270,8 @@
if (Build.VERSION.SDK_INT >= 16) {
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
}
- return PendingIntent.getBroadcast(context, keyCode, intent, PENDING_INTENT_FLAG_MUTABLE);
+ return PendingIntent.getBroadcast(context, keyCode, intent,
+ Build.VERSION.SDK_INT >= 31 ? PendingIntent.FLAG_MUTABLE : 0);
}
/**
diff --git a/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
index ded115a..1f737c9 100644
--- a/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
@@ -21,7 +21,7 @@
</queries>
<application android:supportsRtl="true">
- <receiver android:name="android.support.mediacompat.client.ClientBroadcastReceiver">
+ <receiver android:name="android.support.mediacompat.client.ClientBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.support.mediacompat.service.action.CALL_MEDIA_CONTROLLER_METHOD"/>
<action android:name="android.support.mediacompat.service.action.CALL_TRANSPORT_CONTROLS_METHOD"/>
diff --git a/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java b/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
index d76dc5c..e8dfcba 100644
--- a/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
+++ b/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
@@ -381,7 +381,8 @@
Intent intent = new Intent("MEDIA_SESSION_ACTION");
final int requestCode = 555;
final PendingIntent pi =
- PendingIntent.getActivity(getApplicationContext(), requestCode, intent, 0);
+ PendingIntent.getActivity(getApplicationContext(), requestCode, intent,
+ PendingIntent.FLAG_IMMUTABLE);
callMediaSessionMethod(SET_SESSION_ACTIVITY, pi, getApplicationContext());
new PollingCheck(TIME_OUT_MS) {
diff --git a/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
index 0dd080e..344b26a 100644
--- a/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
@@ -15,35 +15,44 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.support.mediacompat.service.test">
- <queries>
- <package android:name="android.support.mediacompat.client.test" />
- </queries>
+ package="android.support.mediacompat.service.test">
<application>
- <receiver android:name="android.support.mediacompat.service.ServiceBroadcastReceiver">
+ <receiver
+ android:name="android.support.mediacompat.service.ServiceBroadcastReceiver"
+ android:exported="true">
<intent-filter>
- <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_BROWSER_SERVICE_METHOD"/>
- <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_SESSION_METHOD"/>
+ <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_BROWSER_SERVICE_METHOD" />
+ <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_SESSION_METHOD" />
</intent-filter>
</receiver>
- <receiver android:name="androidx.media.session.MediaButtonReceiver" >
+ <receiver
+ android:name="androidx.media.session.MediaButtonReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
- <service android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompat">
+ <service
+ android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
+ <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
- <service android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompatWithDelayedMediaSession">
+ <service
+ android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompatWithDelayedMediaSession"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
+ <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
</application>
+
+ <queries>
+ <package android:name="android.support.mediacompat.client.test" />
+ </queries>
</manifest>
diff --git a/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
index 17c3f30..3ec68e1 100644
--- a/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
+++ b/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
@@ -744,7 +744,7 @@
.setComponent(new ComponentName(getApplicationContext(),
getApplicationContext().getClass()));
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent,
- 0);
+ Build.VERSION.SDK_INT >= 31 ? PendingIntent.FLAG_MUTABLE : 0);
mSession.setMediaButtonReceiver(pi);
// Set state to STATE_PLAYING to get higher priority.
diff --git a/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
index ded115a..1f737c9 100644
--- a/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
@@ -21,7 +21,7 @@
</queries>
<application android:supportsRtl="true">
- <receiver android:name="android.support.mediacompat.client.ClientBroadcastReceiver">
+ <receiver android:name="android.support.mediacompat.client.ClientBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.support.mediacompat.service.action.CALL_MEDIA_CONTROLLER_METHOD"/>
<action android:name="android.support.mediacompat.service.action.CALL_TRANSPORT_CONTROLS_METHOD"/>
diff --git a/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java b/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
index d76dc5c..e8dfcba 100644
--- a/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
+++ b/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
@@ -381,7 +381,8 @@
Intent intent = new Intent("MEDIA_SESSION_ACTION");
final int requestCode = 555;
final PendingIntent pi =
- PendingIntent.getActivity(getApplicationContext(), requestCode, intent, 0);
+ PendingIntent.getActivity(getApplicationContext(), requestCode, intent,
+ PendingIntent.FLAG_IMMUTABLE);
callMediaSessionMethod(SET_SESSION_ACTIVITY, pi, getApplicationContext());
new PollingCheck(TIME_OUT_MS) {
diff --git a/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
index 0dd080e..344b26a 100644
--- a/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
@@ -15,35 +15,44 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.support.mediacompat.service.test">
- <queries>
- <package android:name="android.support.mediacompat.client.test" />
- </queries>
+ package="android.support.mediacompat.service.test">
<application>
- <receiver android:name="android.support.mediacompat.service.ServiceBroadcastReceiver">
+ <receiver
+ android:name="android.support.mediacompat.service.ServiceBroadcastReceiver"
+ android:exported="true">
<intent-filter>
- <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_BROWSER_SERVICE_METHOD"/>
- <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_SESSION_METHOD"/>
+ <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_BROWSER_SERVICE_METHOD" />
+ <action android:name="android.support.mediacompat.service.action.CALL_MEDIA_SESSION_METHOD" />
</intent-filter>
</receiver>
- <receiver android:name="androidx.media.session.MediaButtonReceiver" >
+ <receiver
+ android:name="androidx.media.session.MediaButtonReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
- <service android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompat">
+ <service
+ android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
+ <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
- <service android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompatWithDelayedMediaSession">
+ <service
+ android:name="android.support.mediacompat.service.StubMediaBrowserServiceCompatWithDelayedMediaSession"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
+ <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
</application>
+
+ <queries>
+ <package android:name="android.support.mediacompat.client.test" />
+ </queries>
</manifest>
diff --git a/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
index 2c41299..8ab279d 100644
--- a/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
+++ b/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
@@ -744,7 +744,7 @@
.setComponent(new ComponentName(getApplicationContext(),
getApplicationContext().getClass()));
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent,
- 0);
+ Build.VERSION.SDK_INT >= 31 ? PendingIntent.FLAG_MUTABLE : 0);
mSession.setMediaButtonReceiver(pi);
// Set state to STATE_PLAYING to get higher priority.
diff --git a/media2/integration-tests/testapp/src/main/AndroidManifest.xml b/media2/integration-tests/testapp/src/main/AndroidManifest.xml
index b3401c3..a2959fa 100644
--- a/media2/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/media2/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -30,6 +30,7 @@
<activity android:name=".VideoSelectorActivity"
android:theme="@style/Theme.AppCompat"
+ android:exported="true"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -39,6 +40,7 @@
<activity android:name=".VideoPlayerActivity"
android:theme="@style/Theme.AppCompat"
+ android:exported="true"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
diff --git a/media2/media2-player/src/androidTest/AndroidManifest.xml b/media2/media2-player/src/androidTest/AndroidManifest.xml
index 31b53f4..8de57c6 100644
--- a/media2/media2-player/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-player/src/androidTest/AndroidManifest.xml
@@ -15,21 +15,23 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.media2.player.test">
-
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ package="androidx.media2.player.test">
<application>
- <activity android:name="androidx.media2.player.MediaStubActivity"
- android:label="MediaStubActivity"
- android:screenOrientation="nosensor"
- android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
+ <activity
+ android:name="androidx.media2.player.MediaStubActivity"
+ android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
+ android:exported="false"
+ android:label="MediaStubActivity"
+ android:screenOrientation="nosensor">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
</intent-filter>
</activity>
</application>
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>
diff --git a/media2/media2-session/lint-baseline.xml b/media2/media2-session/lint-baseline.xml
index de1bd63..af17e24 100644
--- a/media2/media2-session/lint-baseline.xml
+++ b/media2/media2-session/lint-baseline.xml
@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha03" type="baseline" client="gradle" name="AGP (7.1.0-alpha03)" variant="all" version="7.1.0-alpha03">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: VolumeProviderCompat.VOLUME_CONTROL_FIXED, VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE"
+ errorLine1=" return new VolumeProviderCompat(player.getVolumeControlType(), player.getMaxVolume(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/media2/session/MediaSessionLegacyStub.java"
+ line="630"
+ column="41"/>
+ </issue>
<issue
id="WrongConstant"
diff --git a/media2/media2-session/src/androidTest/AndroidManifest.xml b/media2/media2-session/src/androidTest/AndroidManifest.xml
index 44409fb..b0cee7d 100644
--- a/media2/media2-session/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/src/androidTest/AndroidManifest.xml
@@ -15,40 +15,52 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.media2.session.test">
-
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ package="androidx.media2.session.test">
<application android:usesCleartextTraffic="true">
- <activity android:name="androidx.media2.session.MockActivity" />
- <activity android:name="androidx.media2.session.SurfaceActivity" />
+ <activity
+ android:name="androidx.media2.session.MockActivity"
+ android:exported="false" />
+ <activity
+ android:name="androidx.media2.session.SurfaceActivity"
+ android:exported="false" />
<!-- Keep the test services synced together with the MockMediaSessionService -->
- <service android:name="androidx.media2.session.MockMediaSessionService">
+ <receiver
+ android:name="androidx.media.session.MediaButtonReceiver"
+ android:exported="false">
<intent-filter>
- <action android:name="androidx.media2.session.MediaSessionService" />
- <action android:name="android.media.browse.MediaBrowserService" />
+ <action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
- </service>
+ </receiver>
<!-- Keep the test services synced together with the MockMediaLibraryService -->
- <service android:name="androidx.media2.session.MockMediaLibraryService">
+ <service
+ android:name="androidx.media2.session.MockMediaLibraryService"
+ android:exported="false">
<intent-filter>
<action android:name="androidx.media2.session.MediaLibraryService" />
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<!-- Keep the test services synced together with the MockMediaSessionService -->
- <service android:name="androidx.media2.session.MockMediaBrowserServiceCompat">
+ <service
+ android:name="androidx.media2.session.MockMediaBrowserServiceCompat"
+ android:exported="false">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
- <receiver android:name="androidx.media.session.MediaButtonReceiver" >
+ <service
+ android:name="androidx.media2.session.MockMediaSessionService"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MEDIA_BUTTON" />
+ <action android:name="androidx.media2.session.MediaSessionService" />
+ <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
- </receiver>
+ </service>
</application>
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>
diff --git a/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
index 9b01c01..ce9acde 100644
--- a/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
@@ -15,33 +15,42 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.media2.test.client.test">
- <queries>
- <package android:name="androidx.media2.test.service.test" />
- </queries>
+ package="androidx.media2.test.client.test">
<application android:supportsRtl="true">
- <activity android:name="androidx.media2.test.client.SurfaceActivity" />
+ <activity
+ android:name="androidx.media2.test.client.SurfaceActivity"
+ android:exported="true" />
- <service android:name="androidx.media2.test.client.MediaControllerProviderService">
+ <service
+ android:name="androidx.media2.test.client.MediaControllerProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA2_CONTROLLER" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.client.MediaControllerCompatProviderService">
+ <service
+ android:name="androidx.media2.test.client.MediaControllerCompatProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA_CONTROLLER_COMPAT" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.client.MediaBrowserCompatProviderService">
+ <service
+ android:name="androidx.media2.test.client.MediaBrowserCompatProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA_BROWSER_COMPAT" />
</intent-filter>
</service>
</application>
+
+ <queries>
+ <package android:name="androidx.media2.test.service.test" />
+ </queries>
</manifest>
diff --git a/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
index d033d90..3a1f4f4 100644
--- a/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
@@ -15,51 +15,64 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.media2.test.service.test">
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-
- <queries>
- <package android:name="androidx.media2.test.client.test" />
- </queries>
+ package="androidx.media2.test.service.test">
<application>
- <receiver android:name="androidx.media.session.MediaButtonReceiver" >
+ <receiver
+ android:name="androidx.media.session.MediaButtonReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
- <service android:name="androidx.media2.test.service.MediaSessionProviderService">
+ <service
+ android:name="androidx.media2.test.service.MediaSessionProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA2_SESSION" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MediaSessionCompatProviderService">
+ <service
+ android:name="androidx.media2.test.service.MediaSessionCompatProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA_SESSION_COMPAT" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MockMediaSessionService">
+ <service
+ android:name="androidx.media2.test.service.MockMediaSessionService"
+ android:exported="true">
<intent-filter>
<action android:name="androidx.media2.session.MediaSessionService" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MockMediaLibraryService">
+ <service
+ android:name="androidx.media2.test.service.MockMediaLibraryService"
+ android:exported="true">
<intent-filter>
<action android:name="androidx.media2.session.MediaLibraryService" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MockMediaBrowserServiceCompat">
+ <service
+ android:name="androidx.media2.test.service.MockMediaBrowserServiceCompat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
+ <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
</application>
+
+ <queries>
+ <package android:name="androidx.media2.test.client.test" />
+ </queries>
+
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>
diff --git a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
index 9b01c01..ce9acde 100644
--- a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
@@ -15,33 +15,42 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.media2.test.client.test">
- <queries>
- <package android:name="androidx.media2.test.service.test" />
- </queries>
+ package="androidx.media2.test.client.test">
<application android:supportsRtl="true">
- <activity android:name="androidx.media2.test.client.SurfaceActivity" />
+ <activity
+ android:name="androidx.media2.test.client.SurfaceActivity"
+ android:exported="true" />
- <service android:name="androidx.media2.test.client.MediaControllerProviderService">
+ <service
+ android:name="androidx.media2.test.client.MediaControllerProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA2_CONTROLLER" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.client.MediaControllerCompatProviderService">
+ <service
+ android:name="androidx.media2.test.client.MediaControllerCompatProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA_CONTROLLER_COMPAT" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.client.MediaBrowserCompatProviderService">
+ <service
+ android:name="androidx.media2.test.client.MediaBrowserCompatProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA_BROWSER_COMPAT" />
</intent-filter>
</service>
</application>
+
+ <queries>
+ <package android:name="androidx.media2.test.service.test" />
+ </queries>
</manifest>
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
index d033d90..3a1f4f4 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
@@ -15,51 +15,64 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.media2.test.service.test">
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-
- <queries>
- <package android:name="androidx.media2.test.client.test" />
- </queries>
+ package="androidx.media2.test.service.test">
<application>
- <receiver android:name="androidx.media.session.MediaButtonReceiver" >
+ <receiver
+ android:name="androidx.media.session.MediaButtonReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
- <service android:name="androidx.media2.test.service.MediaSessionProviderService">
+ <service
+ android:name="androidx.media2.test.service.MediaSessionProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA2_SESSION" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MediaSessionCompatProviderService">
+ <service
+ android:name="androidx.media2.test.service.MediaSessionCompatProviderService"
+ android:exported="true">
<intent-filter>
<!-- Keep sync with CommonConstants.java -->
<action android:name="androidx.media.test.action.MEDIA_SESSION_COMPAT" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MockMediaSessionService">
+ <service
+ android:name="androidx.media2.test.service.MockMediaSessionService"
+ android:exported="true">
<intent-filter>
<action android:name="androidx.media2.session.MediaSessionService" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MockMediaLibraryService">
+ <service
+ android:name="androidx.media2.test.service.MockMediaLibraryService"
+ android:exported="true">
<intent-filter>
<action android:name="androidx.media2.session.MediaLibraryService" />
</intent-filter>
</service>
- <service android:name="androidx.media2.test.service.MockMediaBrowserServiceCompat">
+ <service
+ android:name="androidx.media2.test.service.MockMediaBrowserServiceCompat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
+ <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
</application>
+
+ <queries>
+ <package android:name="androidx.media2.test.client.test" />
+ </queries>
+
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>
diff --git a/media2/media2-widget/src/androidTest/AndroidManifest.xml b/media2/media2-widget/src/androidTest/AndroidManifest.xml
index eb21498..7dba215 100644
--- a/media2/media2-widget/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-widget/src/androidTest/AndroidManifest.xml
@@ -18,20 +18,24 @@
package="androidx.media2.widget.test">
<application>
- <activity android:name="androidx.media2.widget.VideoViewTestActivity"
- android:theme="@style/Theme.AppCompat"
+ <activity
+ android:name="androidx.media2.widget.VideoViewTestActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
- android:label="VideoViewTestActivity">
+ android:exported="false"
+ android:label="VideoViewTestActivity"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
</intent-filter>
</activity>
- <activity android:name="androidx.media2.widget.MediaControlViewTestActivity"
- android:theme="@style/Theme.AppCompat"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:label="MediaControlViewTestActivity">
+ <activity
+ android:name="androidx.media2.widget.MediaControlViewTestActivity"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:exported="false"
+ android:label="MediaControlViewTestActivity"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
</intent-filter>
diff --git a/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml b/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
index 38b578c..d0030ee 100644
--- a/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
+++ b/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
@@ -21,6 +21,7 @@
<activity
android:name="androidx.mediarouter.app.MediaRouteChooserDialogTestActivity"
android:label="MediaRouteChooserDialogTestActivity"
+ android:exported="true"
android:theme="@style/Theme.AppCompat" />
<activity android:name="androidx.mediarouter.media.MediaRouter2TestActivity" />
<service
@@ -32,14 +33,16 @@
</intent-filter>
</service>
- <receiver android:name="androidx.media.session.MediaButtonReceiver">
+ <receiver android:name="androidx.media.session.MediaButtonReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON"/>
</intent-filter>
</receiver>
<service android:name="androidx.mediarouter.media.MediaRouteProviderServiceTest$MediaRouteProviderServiceImpl"
- android:enabled="true">
+ android:exported="true"
+ android:enabled="true">
<intent-filter>
<action android:name="aandroid.media.MediaRouteProviderService"/>
</intent-filter>
diff --git a/navigation/integration-tests/testapp/src/main/AndroidManifest.xml b/navigation/integration-tests/testapp/src/main/AndroidManifest.xml
index b867dfb..c1e43c8 100644
--- a/navigation/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/navigation/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -21,7 +21,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon">
- <activity android:name=".NavigationActivity">
+ <activity android:name=".NavigationActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -31,9 +31,9 @@
</activity>
<activity
android:name=".HelpActivity"
- android:label="@string/help"/>
+ android:label="@string/help" android:exported="true"/>
- <receiver android:name=".DeepLinkAppWidgetProvider" >
+ <receiver android:name=".DeepLinkAppWidgetProvider" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
diff --git a/navigation/navigation-common/api/current.txt b/navigation/navigation-common/api/current.txt
index 5ccc622..9f26538 100644
--- a/navigation/navigation-common/api/current.txt
+++ b/navigation/navigation-common/api/current.txt
@@ -487,14 +487,15 @@
ctor public NavigatorState();
method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
- method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+ method public void onLaunchSingleTop();
method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
- property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
}
@androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
diff --git a/navigation/navigation-common/api/public_plus_experimental_current.txt b/navigation/navigation-common/api/public_plus_experimental_current.txt
index 5ccc622..9f26538 100644
--- a/navigation/navigation-common/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-common/api/public_plus_experimental_current.txt
@@ -487,14 +487,15 @@
ctor public NavigatorState();
method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
- method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+ method public void onLaunchSingleTop();
method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
- property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
}
@androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
diff --git a/navigation/navigation-common/api/restricted_current.txt b/navigation/navigation-common/api/restricted_current.txt
index 5ccc622..9f26538 100644
--- a/navigation/navigation-common/api/restricted_current.txt
+++ b/navigation/navigation-common/api/restricted_current.txt
@@ -487,14 +487,15 @@
ctor public NavigatorState();
method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
- method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+ method public void onLaunchSingleTop();
method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
- property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
}
@androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
index b227433..d7eec40 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
@@ -199,7 +199,7 @@
override fun equals(other: Any?): Boolean {
if (other == null || other !is NavBackStackEntry) return false
- return context == other.context && id == other.id && destination == other.destination &&
+ return id == other.id && destination == other.destination &&
(
arguments == other.arguments ||
arguments?.keySet()
@@ -208,8 +208,7 @@
}
override fun hashCode(): Int {
- var result = context.hashCode()
- result = 31 * result + id.hashCode()
+ var result = id.hashCode()
result = 31 * result + destination.hashCode()
arguments?.keySet()?.forEach {
result = 31 * result + arguments!!.get(it).hashCode()
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/Navigator.kt b/navigation/navigation-common/src/main/java/androidx/navigation/Navigator.kt
index aa769b6..85733bf 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/Navigator.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/Navigator.kt
@@ -143,6 +143,7 @@
public open fun onLaunchSingleTop(backStackEntry: NavBackStackEntry) {
val destination = backStackEntry.destination as? D ?: return
navigate(destination, null, navOptions { launchSingleTop = true }, null)
+ state.onLaunchSingleTop()
}
/**
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
index c031139..8267325 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
@@ -31,8 +31,8 @@
public abstract class NavigatorState {
private val backStackLock = ReentrantLock(true)
private val _backStack: MutableStateFlow<List<NavBackStackEntry>> = MutableStateFlow(listOf())
- private val _transitionsInProgress: MutableStateFlow<Set<NavBackStackEntry>> =
- MutableStateFlow(setOf())
+ private val _transitionsInProgress: MutableStateFlow<List<NavBackStackEntry>> =
+ MutableStateFlow(listOf())
/**
* @hide
@@ -53,7 +53,7 @@
* This is the set of currently running transitions. Use this set to retrieve the entry and call
* [markTransitionComplete] once the transition is complete.
*/
- public val transitionsInProgress: StateFlow<Set<NavBackStackEntry>> =
+ public val transitionsInProgress: StateFlow<List<NavBackStackEntry>> =
_transitionsInProgress.asStateFlow()
/**
@@ -133,6 +133,17 @@
pop(popUpTo, saveState)
}
+ public open fun onLaunchSingleTop() {
+ // We need to create a new object and change the value of the back stack to something
+ // different so that Kotlin allows it to be a new object with the same values.
+ // TODO: We should change to just assign to itself this once b/196267358 is addressed
+ val updatedBackStack = mutableListOf<NavBackStackEntry>().apply {
+ addAll(_backStack.value)
+ }
+ _backStack.value = _backStack.value - _backStack.value.last()
+ _backStack.value = updatedBackStack
+ }
+
/**
* This removes the given [NavBackStackEntry] from the [set of the transitions in
* progress][transitionsInProgress]. This should be called in conjunction with
@@ -146,6 +157,6 @@
* @see popWithTransition
*/
public open fun markTransitionComplete(entry: NavBackStackEntry) {
- _transitionsInProgress.value = _transitionsInProgress.value - entry
+ _transitionsInProgress.value = _transitionsInProgress.value.filter { it != entry }
}
}
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt
index e89ce23..2e6ec8f 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt
@@ -23,6 +23,7 @@
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavController
+import androidx.navigation.NavHostController
import androidx.navigation.createGraph
import androidx.navigation.get
import androidx.navigation.plusAssign
@@ -191,6 +192,38 @@
}
@Test
+ fun testNavigateOptionSingleTopDifferentArguments() {
+ var value = ""
+ lateinit var navController: NavHostController
+ composeTestRule.setContent {
+ navController = rememberNavController()
+
+ NavHost(navController, startDestination = "first?arg={arg}") {
+ composable("first?arg={arg}") { entry ->
+ if (entry.arguments?.containsKey("arg") == true) {
+ value = entry.arguments?.getString("arg", "").toString()
+ }
+ }
+ }
+ }
+
+ composeTestRule.runOnUiThread {
+ navController.navigate("first?arg=value2") {
+ launchSingleTop = true
+ }
+ }
+ composeTestRule.runOnIdle {
+ val navigator = navController.navigatorProvider.get<ComposeNavigator>(
+ navController.currentDestination?.navigatorName!!
+ )
+ assertWithMessage("there should be 1 destination on back stack when using singleTop")
+ .that(navigator.backStack.value.size)
+ .isEqualTo(1)
+ assertThat(value).isEqualTo("value2")
+ }
+ }
+
+ @Test
fun testGetBackStackEntry() {
lateinit var navController: NavController
composeTestRule.setContent {
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
index 242b6da..a278702 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
@@ -27,6 +27,7 @@
import androidx.compose.foundation.text.BasicText
import androidx.compose.material.Button
import androidx.compose.material.Text
+import androidx.compose.material.TextField
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -44,6 +45,7 @@
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.navigation.NavGraph
+import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.contains
import androidx.navigation.createGraph
@@ -558,6 +560,55 @@
}
}
+ @Test
+ fun testStateSavedByCrossFade() {
+ lateinit var navController: NavHostController
+ lateinit var text: MutableState<String>
+
+ composeTestRule.setContent {
+ navController = rememberNavController()
+ NavHost(navController, "start") {
+ composable("start") {
+ text = rememberSaveable { mutableStateOf("") }
+ Column {
+ TextField(value = text.value, onValueChange = { text.value = it })
+ }
+ }
+ composable("second") { }
+ }
+ }
+
+ composeTestRule.onNodeWithText("test").assertDoesNotExist()
+
+ text.value = "test"
+
+ composeTestRule.onNodeWithText("test").assertExists()
+
+ composeTestRule.runOnIdle {
+ navController.navigate("second") {
+ popUpTo(navController.graph.findStartDestination().id) {
+ saveState = true
+ }
+
+ launchSingleTop = true
+ restoreState = true
+ }
+ }
+
+ composeTestRule.runOnIdle {
+ navController.navigate("start") {
+ popUpTo(navController.graph.findStartDestination().id) {
+ saveState = true
+ }
+
+ launchSingleTop = true
+ restoreState = true
+ }
+ }
+
+ composeTestRule.onNodeWithText("test").assertExists()
+ }
+
private fun createNavController(context: Context): TestNavHostController {
val navController = TestNavHostController(context)
val navigator = TestNavigator()
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
index 986422c..b43df46 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
@@ -22,6 +22,7 @@
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
@@ -29,7 +30,9 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
+import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination
import androidx.navigation.NavGraph
import androidx.navigation.NavGraphBuilder
@@ -117,22 +120,28 @@
) as? ComposeNavigator ?: return
val backStack by composeNavigator.backStack.collectAsState()
val transitionsInProgress by composeNavigator.transitionsInProgress.collectAsState()
+ val visibleTransitionsInProgress = rememberVisibleList(transitionsInProgress)
+ val visibleBackStack = rememberVisibleList(backStack)
+ visibleTransitionsInProgress.PopulateVisibleList(transitionsInProgress)
+ visibleBackStack.PopulateVisibleList(backStack)
- val backStackEntry = transitionsInProgress.lastOrNull { entry ->
- entry.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
- } ?: backStack.lastOrNull { entry ->
- entry.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
- }
+ val backStackEntry = visibleTransitionsInProgress.lastOrNull() ?: visibleBackStack.lastOrNull()
var initialCrossfade by remember { mutableStateOf(true) }
if (backStackEntry != null) {
// while in the scope of the composable, we provide the navBackStackEntry as the
// ViewModelStoreOwner and LifecycleOwner
- Crossfade(backStackEntry, modifier) { currentEntry ->
- currentEntry.LocalOwnersProvider(saveableStateHolder) {
- (currentEntry.destination as ComposeNavigator.Destination).content(currentEntry)
+ Crossfade(backStackEntry.id, modifier) {
+ val lastEntry = transitionsInProgress.lastOrNull { entry ->
+ it == entry.id
+ } ?: backStack.lastOrNull { entry ->
+ it == entry.id
}
- DisposableEffect(currentEntry) {
+
+ lastEntry?.LocalOwnersProvider(saveableStateHolder) {
+ (lastEntry.destination as ComposeNavigator.Destination).content(lastEntry)
+ }
+ DisposableEffect(lastEntry) {
if (initialCrossfade) {
// There's no animation for the initial crossfade,
// so we can instantly mark the transition as complete
@@ -157,3 +166,38 @@
// Show any dialog destinations
DialogHost(dialogNavigator)
}
+
+@Composable
+private fun MutableList<NavBackStackEntry>.PopulateVisibleList(
+ transitionsInProgress: Collection<NavBackStackEntry>
+) {
+ transitionsInProgress.forEach { entry ->
+ DisposableEffect(entry.lifecycle) {
+ val observer = LifecycleEventObserver { _, event ->
+ // ON_START -> add to visibleBackStack, ON_STOP -> remove from visibleBackStack
+ if (event == Lifecycle.Event.ON_START) {
+ add(entry)
+ }
+ if (event == Lifecycle.Event.ON_STOP) {
+ remove(entry)
+ }
+ }
+ entry.lifecycle.addObserver(observer)
+ onDispose {
+ entry.lifecycle.removeObserver(observer)
+ }
+ }
+ }
+}
+
+@Composable
+private fun rememberVisibleList(transitionsInProgress: Collection<NavBackStackEntry>) =
+ remember(transitionsInProgress) {
+ mutableStateListOf<NavBackStackEntry>().also {
+ it.addAll(
+ transitionsInProgress.filter { entry ->
+ entry.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
+ }
+ )
+ }
+ }
diff --git a/navigation/navigation-fragment/build.gradle b/navigation/navigation-fragment/build.gradle
index 1b90feb..8d49434 100644
--- a/navigation/navigation-fragment/build.gradle
+++ b/navigation/navigation-fragment/build.gradle
@@ -26,7 +26,7 @@
dependencies {
api(projectOrArtifact(":fragment:fragment-ktx"))
api(project(":navigation:navigation-runtime"))
- api("androidx.slidingpanelayout:slidingpanelayout:1.2.0-alpha03")
+ api(projectOrArtifact(":slidingpanelayout:slidingpanelayout"))
api(libs.kotlinStdlib)
androidTestImplementation(project(":navigation:navigation-testing"))
androidTestImplementation(projectOrArtifact(":fragment:fragment-testing"))
diff --git a/navigation/navigation-runtime/build.gradle b/navigation/navigation-runtime/build.gradle
index 8f32de3..0b51398 100644
--- a/navigation/navigation-runtime/build.gradle
+++ b/navigation/navigation-runtime/build.gradle
@@ -44,6 +44,13 @@
androidTestImplementation(libs.mockitoCore, excludes.bytebuddy)
androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy)
androidTestImplementation(libs.kotlinStdlib)
+ androidTestImplementation(libs.multidex)
+}
+
+android {
+ defaultConfig {
+ multiDexEnabled = true
+ }
}
androidx {
diff --git a/navigation/navigation-runtime/src/androidTest/AndroidManifest.xml b/navigation/navigation-runtime/src/androidTest/AndroidManifest.xml
index 44a4d96..87d1e54 100644
--- a/navigation/navigation-runtime/src/androidTest/AndroidManifest.xml
+++ b/navigation/navigation-runtime/src/androidTest/AndroidManifest.xml
@@ -18,7 +18,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.navigation">
- <application>
+ <application
+ android:name="androidx.multidex.MultiDexApplication">
<activity android:name="androidx.navigation.ActivityNavigatorActivity"/>
<activity android:name="androidx.navigation.TargetActivity"/>
<activity android:name="androidx.navigation.NavControllerActivity"/>
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
index 63c95d2..25f2d60 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
@@ -27,11 +27,13 @@
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.navigation.test.R
import androidx.test.annotation.UiThreadTest
+import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.testutils.TestNavigator
import androidx.testutils.test
+import androidx.testutils.withActivity
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Assert.fail
@@ -83,6 +85,36 @@
assertThat(viewModel).isNotNull()
}
+ @Test
+ fun testEqualsOnRestore() {
+ with(ActivityScenario.launch(NavControllerActivity::class.java)) {
+ val navController = withActivity { NavController(this) }
+ navController.navigatorProvider.addNavigator(TestNavigator())
+
+ val navGraph = navController.navigatorProvider.navigation(
+ route = "start",
+ startDestination = "first"
+ ) {
+ test("first")
+ }
+ withActivity { navController.setGraph(navGraph, null) }
+
+ val entry = navController.currentBackStackEntry
+
+ val savedState = navController.saveState()
+
+ recreate()
+
+ val restoredNavController = withActivity { NavController(this) }
+ restoredNavController.navigatorProvider.addNavigator(TestNavigator())
+
+ restoredNavController.restoreState(savedState)
+ withActivity { restoredNavController.graph = navGraph }
+
+ assertThat(restoredNavController.currentBackStackEntry).isEqualTo(entry)
+ }
+ }
+
@Suppress("DEPRECATION")
@UiThreadTest
@Test
diff --git a/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavigatorStateTest.kt b/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavigatorStateTest.kt
index 7be84d4..8cf19f5 100644
--- a/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavigatorStateTest.kt
+++ b/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavigatorStateTest.kt
@@ -147,6 +147,46 @@
.isEqualTo(Lifecycle.State.RESUMED)
}
+ @Test
+ fun testSameEntry() {
+ val navigator = TestTransitionNavigator()
+ navigator.onAttach(state)
+ val firstEntry = state.createBackStackEntry(navigator.createDestination(), null)
+
+ navigator.navigate(listOf(firstEntry), null, null)
+
+ val secondEntry = state.createBackStackEntry(navigator.createDestination(), null)
+ navigator.navigate(listOf(secondEntry), null, null)
+ assertThat(state.transitionsInProgress.value.contains(firstEntry)).isTrue()
+
+ state.markTransitionComplete(firstEntry)
+ state.markTransitionComplete(secondEntry)
+
+ navigator.popBackStack(secondEntry, true)
+ assertThat(state.transitionsInProgress.value.contains(firstEntry)).isTrue()
+ assertThat(state.transitionsInProgress.value.contains(secondEntry)).isTrue()
+ val restoredSecondEntry = state.restoreBackStackEntry(secondEntry)
+ navigator.navigate(listOf(restoredSecondEntry), null, null)
+ assertThat(
+ state.transitionsInProgress.value.firstOrNull { it === restoredSecondEntry }
+ ).isNotNull()
+
+ state.markTransitionComplete(firstEntry)
+ assertThat(state.transitionsInProgress.value.contains(firstEntry)).isFalse()
+
+ state.markTransitionComplete(restoredSecondEntry)
+ assertThat(state.transitionsInProgress.value.firstOrNull { it === secondEntry }).isNull()
+
+ assertThat(firstEntry.lifecycle.currentState)
+ .isEqualTo(Lifecycle.State.CREATED)
+ assertThat(restoredSecondEntry.lifecycle.currentState)
+ .isEqualTo(Lifecycle.State.RESUMED)
+
+ state.markTransitionComplete(secondEntry)
+ assertThat(secondEntry.lifecycle.currentState)
+ .isEqualTo(Lifecycle.State.DESTROYED)
+ }
+
@Navigator.Name("test")
internal class TestNavigator : Navigator<NavDestination>() {
override fun createDestination(): NavDestination = NavDestination(this)
diff --git a/navigation/navigation-testing/src/main/java/androidx/navigation/testing/TestNavigatorState.kt b/navigation/navigation-testing/src/main/java/androidx/navigation/testing/TestNavigatorState.kt
index c146ce31..3e57ebe 100644
--- a/navigation/navigation-testing/src/main/java/androidx/navigation/testing/TestNavigatorState.kt
+++ b/navigation/navigation-testing/src/main/java/androidx/navigation/testing/TestNavigatorState.kt
@@ -112,7 +112,9 @@
val savedState = entrySavedState[entry] == true
super.markTransitionComplete(entry)
entrySavedState.remove(entry)
- if (!backStack.value.contains(entry)) {
+ if (!backStack.value.contains(entry) ||
+ backStack.value[backStack.value.indexOf(entry)] !== entry
+ ) {
updateMaxLifecycle(listOf(entry), savedState)
} else {
updateMaxLifecycle()
diff --git a/paging/integration-tests/testapp/src/main/AndroidManifest.xml b/paging/integration-tests/testapp/src/main/AndroidManifest.xml
index d82aa06..8bd2d51 100644
--- a/paging/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/paging/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -22,6 +22,7 @@
android:theme="@style/Theme.AppCompat">
<activity
android:name=".custom.PagedListSampleActivity"
+ android:exported="true"
android:label="PagedList Sample">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -30,6 +31,7 @@
</activity>
<activity
android:name=".v3.V3Activity"
+ android:exported="true"
android:label="V3">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -39,6 +41,7 @@
<activity
android:name=".room.RoomPagedListActivity"
android:label="Room Live PagedList"
+ android:exported="true"
android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -48,6 +51,7 @@
<activity
android:name=".room.RoomKeyedPagedListActivity"
android:label="Keyed Live PagedList"
+ android:exported="true"
android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -57,6 +61,7 @@
<activity
android:name=".room.RoomPagedListRxActivity"
android:label="PagedList Observable"
+ android:exported="true"
android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -65,6 +70,7 @@
</activity>
<activity
android:name=".v3room.V3RoomActivity"
+ android:exported="true"
android:label="V3 Room">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/paging/paging-common/src/main/kotlin/androidx/paging/InvalidatingPagingSourceFactory.kt b/paging/paging-common/src/main/kotlin/androidx/paging/InvalidatingPagingSourceFactory.kt
index e184127..93ddb2d 100644
--- a/paging/paging-common/src/main/kotlin/androidx/paging/InvalidatingPagingSourceFactory.kt
+++ b/paging/paging-common/src/main/kotlin/androidx/paging/InvalidatingPagingSourceFactory.kt
@@ -17,14 +17,16 @@
package androidx.paging
import androidx.annotation.VisibleForTesting
+import java.util.concurrent.CopyOnWriteArrayList
/**
- * Wrapper class for [PagingSource] factory intended for usage in [Pager] construction.
- * Stores reference to the [PagingSource] factory and the [PagingSource]s it produces for
- * invalidation when the backing dataset is updated.
+ * Wrapper class for a [PagingSource] factory intended for usage in [Pager] construction.
*
- * Calling [invalidate] on this [InvalidatingPagingSourceFactory] will automatically forward
- * invalidate signals to all active [PagingSource]s.
+ * Calling [invalidate] on this [InvalidatingPagingSourceFactory] will forward invalidate signals
+ * to all active [PagingSource]s that were produced by calling [invoke].
+ *
+ * This class is backed by a [CopyOnWriteArrayList], which is thread-safe for concurrent calls to
+ * any mutative operations including both [invoke] and [invalidate].
*
* @param pagingSourceFactory The [PagingSource] factory that returns a PagingSource when called
*/
@@ -33,7 +35,7 @@
) : () -> PagingSource<Key, Value> {
@VisibleForTesting
- internal val pagingSources = mutableListOf<PagingSource<Key, Value>>()
+ internal val pagingSources = CopyOnWriteArrayList<PagingSource<Key, Value>>()
/**
* @return [PagingSource] which will be invalidated when this factory's [invalidate] method
@@ -48,7 +50,7 @@
* [InvalidatingPagingSourceFactory]
*/
public fun invalidate() {
- for (pagingSource in pagingSources.toList()) {
+ for (pagingSource in pagingSources) {
if (!pagingSource.invalid) {
pagingSource.invalidate()
}
diff --git a/paging/paging-common/src/main/kotlin/androidx/paging/Pager.kt b/paging/paging-common/src/main/kotlin/androidx/paging/Pager.kt
index 3513a38..55dedbd 100644
--- a/paging/paging-common/src/main/kotlin/androidx/paging/Pager.kt
+++ b/paging/paging-common/src/main/kotlin/androidx/paging/Pager.kt
@@ -58,6 +58,16 @@
* A cold [Flow] of [PagingData], which emits new instances of [PagingData] once they become
* invalidated by [PagingSource.invalidate] or calls to [AsyncPagingDataDiffer.refresh] or
* [PagingDataAdapter.refresh].
+ *
+ * To consume this stream as a LiveData or in Rx, you may use the extensions available in the
+ * paging-runtime or paging-rxjava* artifacts.
+ *
+ * NOTE: Instances of [PagingData] emitted by this [Flow] are not re-usable and cannot be
+ * submitted multiple times. This is especially relevant for transforms such as
+ * [Flow.combine][kotlinx.coroutines.flow.combine], which would replay the latest value
+ * downstream. To ensure you get a new instance of [PagingData] for each downstream observer,
+ * you should use the [cachedIn] operator which multicasts the [Flow] in a way that returns a
+ * new instance of [PagingData] with cached data pre-loaded.
*/
public val flow: Flow<PagingData<Value>> = PageFetcher(
pagingSourceFactory = if (
diff --git a/paging/paging-common/src/test/kotlin/androidx/paging/InvalidatingPagingSourceFactoryTest.kt b/paging/paging-common/src/test/kotlin/androidx/paging/InvalidatingPagingSourceFactoryTest.kt
index 8b8a377..a3b431a 100644
--- a/paging/paging-common/src/test/kotlin/androidx/paging/InvalidatingPagingSourceFactoryTest.kt
+++ b/paging/paging-common/src/test/kotlin/androidx/paging/InvalidatingPagingSourceFactoryTest.kt
@@ -90,4 +90,19 @@
// after .invalidate() is called as it would result in an infinite loop.
factory.invalidate()
}
+
+ @Test
+ fun invalidate_threadSafe() {
+ val factory = InvalidatingPagingSourceFactory { TestPagingSource() }
+
+ // Check for concurrent modification when invalidating paging sources.
+ repeat(2) {
+ factory().registerInvalidatedCallback {
+ factory()
+ factory.invalidate()
+ factory()
+ }
+ }
+ factory.invalidate()
+ }
}
diff --git a/paging/paging-runtime/src/main/java/androidx/paging/PagingLiveData.kt b/paging/paging-runtime/src/main/java/androidx/paging/PagingLiveData.kt
index caed0dd..51126b8 100644
--- a/paging/paging-runtime/src/main/java/androidx/paging/PagingLiveData.kt
+++ b/paging/paging-runtime/src/main/java/androidx/paging/PagingLiveData.kt
@@ -30,6 +30,12 @@
/**
* A [LiveData] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes it
* as a [LiveData].
+ *
+ * NOTE: Instances of [PagingData] emitted by this [LiveData] are not re-usable and cannot be
+ * submitted multiple times. This is especially relevant because [LiveData] will replays the latest
+ * value downstream. To ensure you get a new instance of [PagingData] for each downstream
+ * observer, you should use the [cachedIn] operator which multicasts the [LiveData] in a way that
+ * returns a new instance of [PagingData] with cached data pre-loaded.
*/
val <Key : Any, Value : Any> Pager<Key, Value>.liveData: LiveData<PagingData<Value>>
get() = flow.asLiveData()
diff --git a/paging/paging-rxjava2/api/current.txt b/paging/paging-rxjava2/api/current.txt
index edfcce1..afe197e 100644
--- a/paging/paging-rxjava2/api/current.txt
+++ b/paging/paging-rxjava2/api/current.txt
@@ -32,6 +32,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
}
@@ -39,6 +41,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
}
diff --git a/paging/paging-rxjava2/api/public_plus_experimental_current.txt b/paging/paging-rxjava2/api/public_plus_experimental_current.txt
index ca0b62228..89bd6c6 100644
--- a/paging/paging-rxjava2/api/public_plus_experimental_current.txt
+++ b/paging/paging-rxjava2/api/public_plus_experimental_current.txt
@@ -34,8 +34,8 @@
method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
}
@@ -45,8 +45,8 @@
method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
}
diff --git a/paging/paging-rxjava2/api/restricted_current.txt b/paging/paging-rxjava2/api/restricted_current.txt
index edfcce1..afe197e 100644
--- a/paging/paging-rxjava2/api/restricted_current.txt
+++ b/paging/paging-rxjava2/api/restricted_current.txt
@@ -32,6 +32,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
}
@@ -39,6 +41,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
}
diff --git a/paging/paging-rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt b/paging/paging-rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt
index d6ba2d9..d86ce89 100644
--- a/paging/paging-rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt
+++ b/paging/paging-rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt
@@ -35,10 +35,13 @@
/**
* An [Observable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
* it as an [Observable].
+ *
+ * NOTE: Instances of [PagingData] emitted by this [Observable] are not re-usable and cannot be
+ * submitted multiple times. This is especially relevant for transforms, which would replay the
+ * latest value downstream. To ensure you get a new instance of [PagingData] for each downstream
+ * observer, you should use the [cachedIn] operator which multicasts the [Observable] in a way that
+ * returns a new instance of [PagingData] with cached data pre-loaded.
*/
-// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
-@ExperimentalCoroutinesApi
-@get:ExperimentalCoroutinesApi
val <Key : Any, Value : Any> Pager<Key, Value>.observable: Observable<PagingData<Value>>
get() = flow
.conflate()
@@ -47,10 +50,13 @@
/**
* A [Flowable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
* it as a [Flowable].
+ *
+ * NOTE: Instances of [PagingData] emitted by this [Flowable] are not re-usable and cannot be
+ * submitted multiple times. This is especially relevant for transforms, which would replay the
+ * latest value downstream. To ensure you get a new instance of [PagingData] for each downstream
+ * observer, you should use the [cachedIn] operator which multicasts the [Flowable] in a way that
+ * returns a new instance of [PagingData] with cached data pre-loaded.
*/
-// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
-@ExperimentalCoroutinesApi
-@get:ExperimentalCoroutinesApi
val <Key : Any, Value : Any> Pager<Key, Value>.flowable: Flowable<PagingData<Value>>
get() = flow
.conflate()
diff --git a/paging/paging-rxjava3/api/current.txt b/paging/paging-rxjava3/api/current.txt
index d59dff25..304fe98 100644
--- a/paging/paging-rxjava3/api/current.txt
+++ b/paging/paging-rxjava3/api/current.txt
@@ -4,6 +4,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
}
@@ -11,6 +13,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
}
diff --git a/paging/paging-rxjava3/api/public_plus_experimental_current.txt b/paging/paging-rxjava3/api/public_plus_experimental_current.txt
index c6dfe9c..f847113 100644
--- a/paging/paging-rxjava3/api/public_plus_experimental_current.txt
+++ b/paging/paging-rxjava3/api/public_plus_experimental_current.txt
@@ -6,8 +6,8 @@
method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
}
@@ -17,8 +17,8 @@
method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
- method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
}
diff --git a/paging/paging-rxjava3/api/restricted_current.txt b/paging/paging-rxjava3/api/restricted_current.txt
index d59dff25..304fe98 100644
--- a/paging/paging-rxjava3/api/restricted_current.txt
+++ b/paging/paging-rxjava3/api/restricted_current.txt
@@ -4,6 +4,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
}
@@ -11,6 +13,8 @@
public final class PagingRx {
method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
}
diff --git a/paging/paging-rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt b/paging/paging-rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt
index 2d76681..df1e230 100644
--- a/paging/paging-rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt
+++ b/paging/paging-rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt
@@ -35,10 +35,13 @@
/**
* An [Observable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
* it as an [Observable].
+ *
+ * NOTE: Instances of [PagingData] emitted by this [Observable] are not re-usable and cannot be
+ * submitted multiple times. This is especially relevant for transforms, which would replay the
+ * latest value downstream. To ensure you get a new instance of [PagingData] for each downstream
+ * observer, you should use the [cachedIn] operator which multicasts the [Observable] in a way that
+ * returns a new instance of [PagingData] with cached data pre-loaded.
*/
-// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
-@ExperimentalCoroutinesApi
-@get:ExperimentalCoroutinesApi
val <Key : Any, Value : Any> Pager<Key, Value>.observable: Observable<PagingData<Value>>
get() = flow
.conflate()
@@ -47,10 +50,13 @@
/**
* A [Flowable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
* it as a [Flowable].
+ *
+ * NOTE: Instances of [PagingData] emitted by this [Flowable] are not re-usable and cannot be
+ * submitted multiple times. This is especially relevant for transforms, which would replay the
+ * latest value downstream. To ensure you get a new instance of [PagingData] for each downstream
+ * observer, you should use the [cachedIn] operator which multicasts the [Flowable] in a way that
+ * returns a new instance of [PagingData] with cached data pre-loaded.
*/
-// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
-@ExperimentalCoroutinesApi
-@get:ExperimentalCoroutinesApi
val <Key : Any, Value : Any> Pager<Key, Value>.flowable: Flowable<PagingData<Value>>
get() = flow
.conflate()
diff --git a/playground-common/gradle/wrapper/gradle-wrapper.jar b/playground-common/gradle/wrapper/gradle-wrapper.jar
index f6b961f..7454180 100644
--- a/playground-common/gradle/wrapper/gradle-wrapper.jar
+++ b/playground-common/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/playground-common/gradle/wrapper/gradle-wrapper.properties b/playground-common/gradle/wrapper/gradle-wrapper.properties
index ddac36c..81350b5 100644
--- a/playground-common/gradle/wrapper/gradle-wrapper.properties
+++ b/playground-common/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sat Apr 04 20:07:27 PDT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-rc-2-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip
diff --git a/playground-common/gradlew b/playground-common/gradlew
index e42ea8e..1b6c787 100755
--- a/playground-common/gradlew
+++ b/playground-common/gradlew
@@ -1,78 +1,129 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS="-Dorg.gradle.jvmargs=-Xmx3g"
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,7 +132,7 @@
location of your Java installation."
fi
else
- JAVACMD="java"
+ JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -89,84 +140,95 @@
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
fi
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
exec "$JAVACMD" "$@"
diff --git a/playground-common/gradlew.bat b/playground-common/gradlew.bat
index e95643d..ac1b06f 100644
--- a/playground-common/gradlew.bat
+++ b/playground-common/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -13,15 +29,18 @@
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/playground-common/playground-build.gradle b/playground-common/playground-build.gradle
index f8be44e..9e82386 100644
--- a/playground-common/playground-build.gradle
+++ b/playground-common/playground-build.gradle
@@ -34,7 +34,6 @@
repositories {
google()
mavenCentral()
- jcenter()
maven {
url metalavaRepo
metadataSources {
@@ -54,13 +53,16 @@
ext.repos = [:]
dependencies {
- classpath(libs.androidGradlePlugin)
- classpath(libs.kotlinGradlePlugin)
- classpath(libs.kspGradlePlugin)
+ // NOTE: It's not really clear why asm:9.1 must be explicitly declared here since it should
+ // be provided transitively.
+ classpath("org.ow2.asm:asm:9.1")
+ classpath(libs.androidGradlePluginz)
+ classpath(libs.kotlinGradlePluginz)
+ classpath(libs.kspGradlePluginz)
classpath(libs.gson)
classpath "androidx.build:gradle-plugin:0.1.0"
classpath(libs.shadow)
- classpath(libs.japicmpPlugin)
+ classpath(libs.japicmpPluginz)
}
}
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index 5e47960..e1eeea1 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -26,7 +26,7 @@
kotlin.code.style=official
# Disable docs
androidx.enableDocumentation=false
-androidx.playground.snapshotBuildId=7599279
+androidx.playground.snapshotBuildId=7636480
androidx.playground.metalavaBuildId=7610917
androidx.playground.dokkaBuildId=7472101
androidx.studio.type=playground
diff --git a/profileinstaller/integration-tests/testapp/build.gradle b/profileinstaller/integration-tests/testapp/build.gradle
index 91dbea3..e8f97cc 100644
--- a/profileinstaller/integration-tests/testapp/build.gradle
+++ b/profileinstaller/integration-tests/testapp/build.gradle
@@ -37,6 +37,7 @@
implementation(project(":profileinstaller:profileinstaller"))
androidTestImplementation(project(":compose:ui:ui-test-junit4"))
androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testCore)
}
android {
diff --git a/profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml b/profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml
index 62e9058..ffa6ce6 100644
--- a/profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -3,7 +3,7 @@
package="androidx.profileinstaller.integration.testapp">
<application android:label="profileinstaller test app">
- <activity android:name=".MainActivity">
+ <activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/Encoding.java b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/Encoding.java
index fb41106..bdb7263 100644
--- a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/Encoding.java
+++ b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/Encoding.java
@@ -169,13 +169,17 @@
static void writeCompressed(@NonNull OutputStream os, byte[] data) throws IOException {
writeUInt32(os, data.length); // uncompressed size
Deflater deflater = new Deflater(Deflater.BEST_SPEED);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- try(DeflaterOutputStream dos = new DeflaterOutputStream(bos, deflater)) {
- dos.write(data);
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (DeflaterOutputStream dos = new DeflaterOutputStream(bos, deflater)) {
+ dos.write(data);
+ }
+ byte[] outputData = bos.toByteArray();
+ writeUInt32(os, outputData.length); // compressed size
+ os.write(outputData); // compressed body
+ } finally {
+ deflater.end();
}
- byte[] outputData = bos.toByteArray();
- writeUInt32(os, outputData.length); // compressed size
- os.write(outputData); // compressed body
}
static void writeAll(@NonNull InputStream is, @NonNull OutputStream os) throws IOException {
diff --git a/recyclerview/recyclerview/build.gradle b/recyclerview/recyclerview/build.gradle
index 657d48e..8738cc7 100644
--- a/recyclerview/recyclerview/build.gradle
+++ b/recyclerview/recyclerview/build.gradle
@@ -10,7 +10,7 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
- api("androidx.core:core:1.3.2")
+ api project(":core:core")
implementation("androidx.collection:collection:1.0.0")
api("androidx.customview:customview:1.0.0")
@@ -24,6 +24,7 @@
androidTestImplementation(libs.truth)
androidTestImplementation(libs.junit)
androidTestImplementation(libs.kotlinStdlib)
+ androidTestImplementation(libs.multidex)
androidTestImplementation(project(":internal-testutils-espresso"))
androidTestImplementation(project(":internal-testutils-runtime"))
androidTestImplementation(project(":internal-testutils-common"))
@@ -47,6 +48,7 @@
defaultConfig {
multiDexEnabled = true
testInstrumentationRunner "androidx.testutils.ActivityRecyclingAndroidJUnitRunner"
+ multiDexEnabled true
}
}
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/CustomEdgeEffectTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/CustomEdgeEffectTest.java
index 0153bb90..495e073 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/CustomEdgeEffectTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/CustomEdgeEffectTest.java
@@ -84,6 +84,7 @@
assertNull(factory.mBottom);
assertNotNull(factory.mTop);
assertTrue(factory.mTop.mPullDistance > 0);
+ scrollViewBy(-3);
scrollToPosition(NUM_ITEMS - 1);
waitForIdleScroll(mRecyclerView);
@@ -144,6 +145,7 @@
private class TestEdgeEffect extends EdgeEffect {
private float mPullDistance;
+ private float mDistance;
TestEdgeEffect(Context context) {
super(context);
@@ -157,6 +159,19 @@
@Override
public void onPull(float deltaDistance) {
mPullDistance = deltaDistance;
+ mDistance += deltaDistance;
+ }
+
+ @Override
+ public float onPullDistance(float deltaDistance, float displacement) {
+ float maxDelta = Math.max(-mDistance, deltaDistance);
+ onPull(maxDelta);
+ return maxDelta;
+ }
+
+ @Override
+ public float getDistance() {
+ return mDistance;
}
}
}
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewNestedScrollingChildTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewNestedScrollingChildTest.java
index 5a27004..b26c074 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewNestedScrollingChildTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewNestedScrollingChildTest.java
@@ -80,6 +80,7 @@
ApplicationProvider.getApplicationContext()).getScaledTouchSlop();
mRecyclerView = new RecyclerView(context);
+ mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
mRecyclerView.setMinimumWidth(1000);
mRecyclerView.setMinimumHeight(1000);
@@ -663,4 +664,5 @@
super(itemView);
}
}
+
}
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/StretchEdgeEffectTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/StretchEdgeEffectTest.java
new file mode 100644
index 0000000..c2a6ee2
--- /dev/null
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/StretchEdgeEffectTest.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.recyclerview.widget;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Build;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.EdgeEffect;
+
+import androidx.annotation.NonNull;
+import androidx.core.view.InputDeviceCompat;
+import androidx.core.widget.EdgeEffectCompat;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class StretchEdgeEffectTest extends BaseRecyclerViewInstrumentationTest {
+ private static final int NUM_ITEMS = 10;
+
+ private RecyclerView mRecyclerView;
+ private LinearLayoutManager mLayoutManager;
+
+ @Before
+ public void setup() throws Throwable {
+ mLayoutManager = new LinearLayoutManager(getActivity());
+ mLayoutManager.ensureLayoutState();
+
+ mRecyclerView = new RecyclerView(getActivity());
+ mRecyclerView.setLayoutManager(mLayoutManager);
+ mRecyclerView.setAdapter(new TestAdapter(NUM_ITEMS) {
+
+ @Override
+ public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+ int viewType) {
+ TestViewHolder holder = super.onCreateViewHolder(parent, viewType);
+ holder.itemView.setMinimumHeight(mRecyclerView.getMeasuredHeight() * 2 / NUM_ITEMS);
+ holder.itemView.setMinimumWidth(mRecyclerView.getMeasuredWidth() * 2 / NUM_ITEMS);
+ return holder;
+ }
+ });
+ setRecyclerView(mRecyclerView);
+ getInstrumentation().waitForIdleSync();
+ assertThat("Assumption check", mRecyclerView.getChildCount() > 0, is(true));
+ }
+
+ /**
+ * After pulling the edge effect, releasing should return the edge effect to 0.
+ */
+ @Test
+ public void testLeftEdgeEffectRetract() throws Throwable {
+ mActivityRule.runOnUiThread(
+ () -> mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL));
+ TestEdgeEffectFactory
+ factory = new TestEdgeEffectFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(0);
+ waitForIdleScroll(mRecyclerView);
+ scrollHorizontalBy(-3);
+ if (isSOrHigher()) {
+ assertTrue(EdgeEffectCompat.getDistance(factory.mLeft) > 0);
+ }
+ scrollHorizontalBy(4);
+ assertEquals(0f, EdgeEffectCompat.getDistance(factory.mLeft), 0f);
+ if (isSOrHigher()) {
+ assertTrue(factory.mLeft.isFinished());
+ }
+ }
+
+ /**
+ * After pulling the edge effect, releasing should return the edge effect to 0.
+ */
+ @Test
+ public void testTopEdgeEffectRetract() throws Throwable {
+ TestEdgeEffectFactory
+ factory = new TestEdgeEffectFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(0);
+ waitForIdleScroll(mRecyclerView);
+ scrollVerticalBy(3);
+ if (isSOrHigher()) {
+ assertTrue(EdgeEffectCompat.getDistance(factory.mTop) > 0);
+ }
+ scrollVerticalBy(-4);
+ assertEquals(0f, EdgeEffectCompat.getDistance(factory.mTop), 0f);
+ if (isSOrHigher()) {
+ assertTrue(factory.mTop.isFinished());
+ }
+ }
+
+ /**
+ * After pulling the edge effect, releasing should return the edge effect to 0.
+ */
+ @Test
+ public void testRightEdgeEffectRetract() throws Throwable {
+ mActivityRule.runOnUiThread(
+ () -> mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL));
+ TestEdgeEffectFactory
+ factory = new TestEdgeEffectFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(NUM_ITEMS - 1);
+ waitForIdleScroll(mRecyclerView);
+ scrollHorizontalBy(3);
+ if (isSOrHigher()) {
+ assertTrue(EdgeEffectCompat.getDistance(factory.mRight) > 0);
+ }
+ scrollHorizontalBy(-4);
+ assertEquals(0f, EdgeEffectCompat.getDistance(factory.mRight), 0f);
+ if (isSOrHigher()) {
+ assertTrue(factory.mRight.isFinished());
+ }
+ }
+
+ /**
+ * After pulling the edge effect, releasing should return the edge effect to 0.
+ */
+ @Test
+ public void testBottomEdgeEffectRetract() throws Throwable {
+ TestEdgeEffectFactory factory = new TestEdgeEffectFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(NUM_ITEMS - 1);
+ waitForIdleScroll(mRecyclerView);
+ scrollVerticalBy(-3);
+ if (isSOrHigher()) {
+ assertTrue(EdgeEffectCompat.getDistance(factory.mBottom) > 0);
+ }
+
+ scrollVerticalBy(4);
+ if (isSOrHigher()) {
+ assertEquals(0f, EdgeEffectCompat.getDistance(factory.mBottom), 0f);
+ assertTrue(factory.mBottom.isFinished());
+ }
+ }
+
+ /**
+ * A fling should be allowed during pull, but only for and earlier
+ */
+ @Test
+ public void testFlingAfterStretchLeft() throws Throwable {
+ mActivityRule.runOnUiThread(
+ () -> mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL));
+ CaptureOnAbsorbFactory factory = new CaptureOnAbsorbFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(0);
+ waitForIdleScroll(mRecyclerView);
+ scrollHorizontalBy(-3);
+
+ if (isSOrHigher()) {
+ // test flinging right
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mLeft);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(-1000, 0));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mLeft), 0.01f);
+ assertEquals(1000, factory.mLeft.mAbsorbVelocity);
+ // reset the edge effect
+ factory.mLeft.finish();
+ });
+
+ scrollHorizontalBy(-3);
+
+ // test flinging left
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mLeft);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(1000, 0));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mLeft), 0.01f);
+ assertEquals(-1000, factory.mLeft.mAbsorbVelocity);
+ });
+ } else {
+ // fling left and it should just scroll
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(0, mLayoutManager.findFirstVisibleItemPosition());
+ assertTrue(mRecyclerView.fling(5000, 0));
+ assertEquals(0, factory.mLeft.mAbsorbVelocity);
+ });
+ waitForIdleScroll(mRecyclerView);
+ mActivityRule.runOnUiThread(() -> {
+ assertTrue(mLayoutManager.findFirstVisibleItemPosition() > 0);
+ });
+ }
+ }
+
+ /**
+ * A fling should be allowed during pull.
+ */
+ @Test
+ public void testFlingAfterStretchTop() throws Throwable {
+ CaptureOnAbsorbFactory factory = new CaptureOnAbsorbFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(0);
+ waitForIdleScroll(mRecyclerView);
+ scrollVerticalBy(3);
+
+ if (isSOrHigher()) {
+ // test flinging down
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mTop);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(0, -1000));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mTop), 0.01f);
+ assertEquals(1000, factory.mTop.mAbsorbVelocity);
+ // reset the edge effect
+ factory.mTop.finish();
+ });
+
+ scrollVerticalBy(3);
+
+ // test flinging up
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mTop);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(0, 1000));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mTop), 0.01f);
+ assertEquals(-1000, factory.mTop.mAbsorbVelocity);
+ });
+ } else {
+ // fling up and it should just scroll
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(0, mLayoutManager.findFirstVisibleItemPosition());
+ assertTrue(mRecyclerView.fling(0, 5000));
+ assertEquals(0, factory.mTop.mAbsorbVelocity);
+ });
+ waitForIdleScroll(mRecyclerView);
+ mActivityRule.runOnUiThread(() -> {
+ assertTrue(mLayoutManager.findFirstVisibleItemPosition() > 0);
+ });
+ }
+ }
+
+ /**
+ * A fling should be allowed during pull.
+ */
+ @Test
+ public void testFlingAfterStretchRight() throws Throwable {
+ mActivityRule.runOnUiThread(
+ () -> mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL));
+ CaptureOnAbsorbFactory factory = new CaptureOnAbsorbFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(NUM_ITEMS - 1);
+ waitForIdleScroll(mRecyclerView);
+ scrollHorizontalBy(3);
+
+ if (isSOrHigher()) {
+ // test flinging left
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mRight);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(1000, 0));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mRight), 0.01f);
+ assertEquals(1000, factory.mRight.mAbsorbVelocity);
+ // reset the edge effect
+ factory.mRight.finish();
+ });
+
+ scrollHorizontalBy(3);
+
+ // test flinging right
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mRight);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(-1000, 0));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mRight), 0.01f);
+ assertEquals(-1000, factory.mRight.mAbsorbVelocity);
+ });
+ } else {
+ // fling right and it should just scroll
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(mRecyclerView.getAdapter().getItemCount() - 1,
+ mLayoutManager.findLastVisibleItemPosition());
+ assertTrue(mRecyclerView.fling(-5000, 0));
+ assertEquals(0, factory.mRight.mAbsorbVelocity);
+ });
+ waitForIdleScroll(mRecyclerView);
+ mActivityRule.runOnUiThread(() -> {
+ assertTrue(mLayoutManager.findLastVisibleItemPosition()
+ < mRecyclerView.getAdapter().getItemCount() - 1);
+ });
+
+ }
+ }
+
+ /**
+ * A fling should be allowed during pull.
+ */
+ @Test
+ public void testFlingAfterStretchBottom() throws Throwable {
+ CaptureOnAbsorbFactory factory = new CaptureOnAbsorbFactory();
+ mRecyclerView.setEdgeEffectFactory(factory);
+ scrollToPosition(NUM_ITEMS - 1);
+ waitForIdleScroll(mRecyclerView);
+ scrollVerticalBy(-3);
+
+ if (isSOrHigher()) {
+ // test flinging up
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mBottom);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(0, 1000));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mBottom), 0.01f);
+ assertEquals(1000, factory.mBottom.mAbsorbVelocity);
+ // reset the edge effect
+ factory.mBottom.finish();
+ });
+
+ scrollVerticalBy(-3);
+
+ // test flinging down
+ mActivityRule.runOnUiThread(() -> {
+ float pullDistance = EdgeEffectCompat.getDistance(factory.mBottom);
+ assertTrue(pullDistance > 0);
+ assertTrue(mRecyclerView.fling(0, -1000));
+ assertEquals(pullDistance, EdgeEffectCompat.getDistance(factory.mBottom), 0.01f);
+ assertEquals(-1000, factory.mBottom.mAbsorbVelocity);
+ });
+ } else {
+ // fling up and it should just scroll
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(mRecyclerView.getAdapter().getItemCount() - 1,
+ mLayoutManager.findLastVisibleItemPosition());
+ assertTrue(mRecyclerView.fling(0, -5000));
+ assertEquals(0, factory.mBottom.mAbsorbVelocity);
+ });
+ waitForIdleScroll(mRecyclerView);
+ mActivityRule.runOnUiThread(() -> {
+ assertTrue(mLayoutManager.findLastVisibleItemPosition()
+ < mRecyclerView.getAdapter().getItemCount() - 1);
+ });
+ }
+ }
+
+ private static boolean isSOrHigher() {
+ // TODO(b/181171227): Simplify this
+ int sdk = Build.VERSION.SDK_INT;
+ return sdk > Build.VERSION_CODES.R
+ || (sdk == Build.VERSION_CODES.R && Build.VERSION.PREVIEW_SDK_INT != 0);
+ }
+
+ private void scrollVerticalBy(final int value) throws Throwable {
+ mActivityRule.runOnUiThread(() -> TouchUtils.scrollView(MotionEvent.AXIS_VSCROLL, value,
+ InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView));
+ }
+
+ private void scrollHorizontalBy(final int value) throws Throwable {
+ mActivityRule.runOnUiThread(() -> TouchUtils.scrollView(MotionEvent.AXIS_HSCROLL, value,
+ InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView));
+ }
+
+ private class TestEdgeEffectFactory extends RecyclerView.EdgeEffectFactory {
+ TestEdgeEffect mTop, mBottom, mLeft, mRight;
+
+ @NonNull
+ @Override
+ protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
+ TestEdgeEffect effect = new TestEdgeEffect(view.getContext());
+ switch (direction) {
+ case DIRECTION_LEFT:
+ mLeft = effect;
+ break;
+ case DIRECTION_TOP:
+ mTop = effect;
+ break;
+ case DIRECTION_RIGHT:
+ mRight = effect;
+ break;
+ case DIRECTION_BOTTOM:
+ mBottom = effect;
+ break;
+ }
+ return effect;
+ }
+ }
+
+ private class TestEdgeEffect extends EdgeEffect {
+
+ private float mDistance;
+
+ TestEdgeEffect(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onPull(float deltaDistance, float displacement) {
+ onPull(deltaDistance);
+ }
+
+ @Override
+ public void onPull(float deltaDistance) {
+ mDistance += deltaDistance;
+ }
+
+ @Override
+ public float onPullDistance(float deltaDistance, float displacement) {
+ float maxDelta = Math.max(-mDistance, deltaDistance);
+ onPull(maxDelta);
+ return maxDelta;
+ }
+
+ @Override
+ public float getDistance() {
+ return mDistance;
+ }
+ }
+
+ private class CaptureOnAbsorbFactory extends RecyclerView.EdgeEffectFactory {
+ CaptureOnAbsorb mTop, mBottom, mLeft, mRight;
+
+ @NonNull
+ @Override
+ protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
+ CaptureOnAbsorb effect = new CaptureOnAbsorb(view.getContext());
+ switch (direction) {
+ case DIRECTION_LEFT:
+ mLeft = effect;
+ break;
+ case DIRECTION_TOP:
+ mTop = effect;
+ break;
+ case DIRECTION_RIGHT:
+ mRight = effect;
+ break;
+ case DIRECTION_BOTTOM:
+ mBottom = effect;
+ break;
+ }
+ return effect;
+ }
+ }
+
+ private static class CaptureOnAbsorb extends EdgeEffect {
+ public int mAbsorbVelocity;
+
+ CaptureOnAbsorb(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onAbsorb(int velocity) {
+ super.onAbsorb(velocity);
+ mAbsorbVelocity = velocity;
+ }
+
+ }
+}
diff --git a/recyclerview/recyclerview/src/androidTest/res/layout/stretch_rv.xml b/recyclerview/recyclerview/src/androidTest/res/layout/stretch_rv.xml
new file mode 100644
index 0000000..133ae7b
--- /dev/null
+++ b/recyclerview/recyclerview/src/androidTest/res/layout/stretch_rv.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<androidx.recyclerview.widget.RecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recycler_view"
+ android:layout_width="90px"
+ android:layout_height="90px" />
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
index a29811d..f227606 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
@@ -506,7 +506,7 @@
private int mDispatchScrollCounter = 0;
@NonNull
- private EdgeEffectFactory mEdgeEffectFactory = new EdgeEffectFactory();
+ private EdgeEffectFactory mEdgeEffectFactory = sDefaultEdgeEffectFactory;
private EdgeEffect mLeftGlow, mTopGlow, mRightGlow, mBottomGlow;
ItemAnimator mItemAnimator = new DefaultItemAnimator();
@@ -614,6 +614,9 @@
}
};
+ static final StretchEdgeEffectFactory sDefaultEdgeEffectFactory =
+ new StretchEdgeEffectFactory();
+
// These fields are only used to track whether we need to layout and measure RV children in
// onLayout.
//
@@ -716,6 +719,7 @@
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecyclerView,
defStyleAttr, 0);
+
ViewCompat.saveAttributeDataForStyleable(this, context, R.styleable.RecyclerView,
attrs, a, defStyleAttr, 0);
String layoutManagerName = a.getString(R.styleable.RecyclerView_layoutManager);
@@ -1924,6 +1928,12 @@
if (canScrollVertical) {
nestedScrollAxis |= ViewCompat.SCROLL_AXIS_VERTICAL;
}
+
+ // If there is no MotionEvent, treat it as center-aligned edge effect:
+ float verticalDisplacement = motionEvent == null ? getHeight() / 2f : motionEvent.getY();
+ float horizontalDisplacement = motionEvent == null ? getWidth() / 2f : motionEvent.getX();
+ x -= releaseHorizontalGlow(x, verticalDisplacement);
+ y -= releaseVerticalGlow(y, horizontalDisplacement);
startNestedScroll(nestedScrollAxis, type);
if (dispatchNestedPreScroll(
canScrollHorizontal ? x : 0,
@@ -2108,6 +2118,73 @@
}
/**
+ * If either of the horizontal edge glows are currently active, this consumes part or all of
+ * deltaX on the edge glow.
+ *
+ * @param deltaX The pointer motion, in pixels, in the horizontal direction, positive
+ * for moving down and negative for moving up.
+ * @param y The vertical position of the pointer.
+ * @return The amount of <code>deltaX</code> that has been consumed by the
+ * edge glow.
+ */
+ private int releaseHorizontalGlow(int deltaX, float y) {
+ // First allow releasing existing overscroll effect:
+ float consumed = 0;
+ float displacement = y / getHeight();
+ float pullDistance = (float) deltaX / getWidth();
+ if (mLeftGlow != null && EdgeEffectCompat.getDistance(mLeftGlow) != 0) {
+ consumed = -EdgeEffectCompat.onPullDistance(mLeftGlow, -pullDistance, 1 - displacement);
+ if (EdgeEffectCompat.getDistance(mLeftGlow) == 0) {
+ mLeftGlow.onRelease();
+ }
+ } else if (mRightGlow != null && EdgeEffectCompat.getDistance(mRightGlow) != 0) {
+ consumed = EdgeEffectCompat.onPullDistance(mRightGlow, pullDistance, displacement);
+ if (EdgeEffectCompat.getDistance(mRightGlow) == 0) {
+ mRightGlow.onRelease();
+ }
+ }
+ int pixelsConsumed = Math.round(consumed * getWidth());
+ if (pixelsConsumed != 0) {
+ invalidate();
+ }
+ return pixelsConsumed;
+ }
+
+ /**
+ * If either of the vertical edge glows are currently active, this consumes part or all of
+ * deltaY on the edge glow.
+ *
+ * @param deltaY The pointer motion, in pixels, in the vertical direction, positive
+ * for moving down and negative for moving up.
+ * @param x The vertical position of the pointer.
+ * @return The amount of <code>deltaY</code> that has been consumed by the
+ * edge glow.
+ */
+ private int releaseVerticalGlow(int deltaY, float x) {
+ // First allow releasing existing overscroll effect:
+ float consumed = 0;
+ float displacement = x / getWidth();
+ float pullDistance = (float) deltaY / getHeight();
+ if (mTopGlow != null && EdgeEffectCompat.getDistance(mTopGlow) != 0) {
+ consumed = -EdgeEffectCompat.onPullDistance(mTopGlow, -pullDistance, displacement);
+ if (EdgeEffectCompat.getDistance(mTopGlow) == 0) {
+ mTopGlow.onRelease();
+ }
+ } else if (mBottomGlow != null && EdgeEffectCompat.getDistance(mBottomGlow) != 0) {
+ consumed = EdgeEffectCompat.onPullDistance(mBottomGlow, pullDistance,
+ 1 - displacement);
+ if (EdgeEffectCompat.getDistance(mBottomGlow) == 0) {
+ mBottomGlow.onRelease();
+ }
+ }
+ int pixelsConsumed = Math.round(consumed * getHeight());
+ if (pixelsConsumed != 0) {
+ invalidate();
+ }
+ return pixelsConsumed;
+ }
+
+ /**
* <p>Compute the horizontal offset of the horizontal scrollbar's thumb within the horizontal
* range. This value is used to compute the length of the thumb within the scrollbar's track.
* </p>
@@ -2591,6 +2668,35 @@
return false;
}
+ // Flinging while the edge effect is active should affect the edge effect,
+ // not scrolling.
+ boolean flung = false;
+ if (velocityX != 0) {
+ if (mLeftGlow != null && EdgeEffectCompat.getDistance(mLeftGlow) != 0) {
+ mLeftGlow.onAbsorb(-velocityX);
+ velocityX = 0;
+ flung = true;
+ } else if (mRightGlow != null && EdgeEffectCompat.getDistance(mRightGlow) != 0) {
+ mRightGlow.onAbsorb(velocityX);
+ velocityX = 0;
+ flung = true;
+ }
+ }
+ if (velocityY != 0) {
+ if (mTopGlow != null && EdgeEffectCompat.getDistance(mTopGlow) != 0) {
+ mTopGlow.onAbsorb(-velocityY);
+ velocityY = 0;
+ flung = true;
+ } else if (mBottomGlow != null && EdgeEffectCompat.getDistance(mBottomGlow) != 0) {
+ mBottomGlow.onAbsorb(velocityY);
+ velocityY = 0;
+ flung = true;
+ }
+ }
+ if (velocityX == 0 && velocityY == 0) {
+ return true; // consumed all the velocity in the overscroll fling
+ }
+
if (!dispatchNestedPreFling(velocityX, velocityY)) {
final boolean canScroll = canScrollHorizontal || canScrollVertical;
dispatchNestedFling(velocityX, velocityY, canScroll);
@@ -2615,7 +2721,7 @@
return true;
}
}
- return false;
+ return flung;
}
/**
@@ -2663,21 +2769,23 @@
boolean invalidate = false;
if (overscrollX < 0) {
ensureLeftGlow();
- EdgeEffectCompat.onPull(mLeftGlow, -overscrollX / getWidth(), 1f - y / getHeight());
+ EdgeEffectCompat.onPullDistance(mLeftGlow, -overscrollX / getWidth(),
+ 1f - y / getHeight());
invalidate = true;
} else if (overscrollX > 0) {
ensureRightGlow();
- EdgeEffectCompat.onPull(mRightGlow, overscrollX / getWidth(), y / getHeight());
+ EdgeEffectCompat.onPullDistance(mRightGlow, overscrollX / getWidth(), y / getHeight());
invalidate = true;
}
if (overscrollY < 0) {
ensureTopGlow();
- EdgeEffectCompat.onPull(mTopGlow, -overscrollY / getHeight(), x / getWidth());
+ EdgeEffectCompat.onPullDistance(mTopGlow, -overscrollY / getHeight(), x / getWidth());
invalidate = true;
} else if (overscrollY > 0) {
ensureBottomGlow();
- EdgeEffectCompat.onPull(mBottomGlow, overscrollY / getHeight(), 1f - x / getWidth());
+ EdgeEffectCompat.onPullDistance(mBottomGlow, overscrollY / getHeight(),
+ 1f - x / getWidth());
invalidate = true;
}
@@ -2735,26 +2843,18 @@
void absorbGlows(int velocityX, int velocityY) {
if (velocityX < 0) {
ensureLeftGlow();
- if (mLeftGlow.isFinished()) {
- mLeftGlow.onAbsorb(-velocityX);
- }
+ mLeftGlow.onAbsorb(-velocityX);
} else if (velocityX > 0) {
ensureRightGlow();
- if (mRightGlow.isFinished()) {
- mRightGlow.onAbsorb(velocityX);
- }
+ mRightGlow.onAbsorb(velocityX);
}
if (velocityY < 0) {
ensureTopGlow();
- if (mTopGlow.isFinished()) {
- mTopGlow.onAbsorb(-velocityY);
- }
+ mTopGlow.onAbsorb(-velocityY);
} else if (velocityY > 0) {
ensureBottomGlow();
- if (mBottomGlow.isFinished()) {
- mBottomGlow.onAbsorb(velocityY);
- }
+ mBottomGlow.onAbsorb(velocityY);
}
if (velocityX != 0 || velocityY != 0) {
@@ -3331,7 +3431,7 @@
mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f);
mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f);
- if (mScrollState == SCROLL_STATE_SETTLING) {
+ if (stopGlowAnimations(e) || mScrollState == SCROLL_STATE_SETTLING) {
getParent().requestDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
stopNestedScroll(TYPE_NON_TOUCH);
@@ -3403,6 +3503,38 @@
return mScrollState == SCROLL_STATE_DRAGGING;
}
+ /**
+ * This stops any edge glow animation that is currently running by applying a
+ * 0 length pull at the displacement given by the provided MotionEvent. On pre-S devices,
+ * this method does nothing, allowing any animating edge effect to continue animating and
+ * returning <code>false</code> always.
+ *
+ * @param e The motion event to use to indicate the finger position for the displacement of
+ * the current pull.
+ * @return <code>true</code> if any edge effect had an existing effect to be drawn ond the
+ * animation was stopped or <code>false</code> if no edge effect had a value to display.
+ */
+ private boolean stopGlowAnimations(MotionEvent e) {
+ boolean stopped = false;
+ if (mLeftGlow != null && EdgeEffectCompat.getDistance(mLeftGlow) != 0) {
+ EdgeEffectCompat.onPullDistance(mLeftGlow, 0, 1 - (e.getY() / getHeight()));
+ stopped = true;
+ }
+ if (mRightGlow != null && EdgeEffectCompat.getDistance(mRightGlow) != 0) {
+ EdgeEffectCompat.onPullDistance(mRightGlow, 0, e.getY() / getHeight());
+ stopped = true;
+ }
+ if (mTopGlow != null && EdgeEffectCompat.getDistance(mTopGlow) != 0) {
+ EdgeEffectCompat.onPullDistance(mTopGlow, 0, e.getX() / getWidth());
+ stopped = true;
+ }
+ if (mBottomGlow != null && EdgeEffectCompat.getDistance(mBottomGlow) != 0) {
+ EdgeEffectCompat.onPullDistance(mBottomGlow, 0, 1 - e.getX() / getWidth());
+ stopped = true;
+ }
+ return stopped;
+ }
+
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
final int listenerCount = mOnItemTouchListeners.size();
@@ -3511,6 +3643,9 @@
if (mScrollState == SCROLL_STATE_DRAGGING) {
mReusableIntPair[0] = 0;
mReusableIntPair[1] = 0;
+ dx -= releaseHorizontalGlow(dx, e.getY());
+ dy -= releaseVerticalGlow(dy, e.getX());
+
if (dispatchNestedPreScroll(
canScrollHorizontally ? dx : 0,
canScrollVertically ? dy : 0,
@@ -5806,6 +5941,17 @@
}
/**
+ * The default EdgeEffectFactory sets the edge effect type of the EdgeEffect.
+ */
+ static class StretchEdgeEffectFactory extends EdgeEffectFactory {
+ @NonNull
+ @Override
+ protected EdgeEffect createEdgeEffect(@NonNull RecyclerView view, int direction) {
+ return new EdgeEffect(view.getContext());
+ }
+ }
+
+ /**
* RecycledViewPool lets you share Views between multiple RecyclerViews.
* <p>
* If you want to recycle views across RecyclerViews, create an instance of RecycledViewPool
diff --git a/remotecallback/remotecallback/lint-baseline.xml b/remotecallback/remotecallback/lint-baseline.xml
index bbc44f4..7e104d2 100644
--- a/remotecallback/remotecallback/lint-baseline.xml
+++ b/remotecallback/remotecallback/lint-baseline.xml
@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="gradle" dependencies="false" name="AGP (7.1.0-dev)" variant="all" version="7.1.0-dev">
+
+ <issue
+ id="WrongConstant"
+ message="Must be one of: RemoteCallback.TYPE_RECEIVER, RemoteCallback.TYPE_PROVIDER"
+ errorLine1=" public static final RemoteCallback LOCAL = new RemoteCallback(null, -1, null, null, null) {"
+ errorLine2=" ~~">
+ <location
+ file="src/main/java/androidx/remotecallback/RemoteCallback.java"
+ line="151"
+ column="73"/>
+ </issue>
<issue
id="LambdaLast"
@@ -19,7 +30,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="40"
+ line="41"
column="27"/>
</issue>
@@ -30,7 +41,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="40"
+ line="41"
column="44"/>
</issue>
@@ -41,7 +52,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="49"
+ line="50"
column="35"/>
</issue>
@@ -52,7 +63,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="58"
+ line="59"
column="12"/>
</issue>
@@ -63,7 +74,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="58"
+ line="59"
column="44"/>
</issue>
@@ -74,7 +85,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="58"
+ line="59"
column="58"/>
</issue>
@@ -85,7 +96,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="58"
+ line="59"
column="75"/>
</issue>
@@ -96,7 +107,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="59"
+ line="60"
column="13"/>
</issue>
@@ -107,7 +118,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"
- line="59"
+ line="60"
column="26"/>
</issue>
@@ -118,7 +129,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="48"
+ line="49"
column="27"/>
</issue>
@@ -129,7 +140,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="48"
+ line="49"
column="44"/>
</issue>
@@ -140,7 +151,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="55"
+ line="56"
column="35"/>
</issue>
@@ -151,7 +162,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="64"
+ line="65"
column="12"/>
</issue>
@@ -162,7 +173,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="64"
+ line="65"
column="44"/>
</issue>
@@ -173,7 +184,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="64"
+ line="65"
column="58"/>
</issue>
@@ -184,7 +195,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="64"
+ line="65"
column="75"/>
</issue>
@@ -195,7 +206,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="65"
+ line="66"
column="13"/>
</issue>
@@ -206,7 +217,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"
- line="65"
+ line="66"
column="26"/>
</issue>
@@ -481,7 +492,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="47"
+ line="48"
column="28"/>
</issue>
@@ -492,7 +503,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="47"
+ line="48"
column="45"/>
</issue>
@@ -503,7 +514,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="53"
+ line="54"
column="12"/>
</issue>
@@ -514,7 +525,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="53"
+ line="54"
column="24"/>
</issue>
@@ -525,7 +536,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="53"
+ line="54"
column="39"/>
</issue>
@@ -536,7 +547,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="53"
+ line="54"
column="51"/>
</issue>
@@ -547,7 +558,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="62"
+ line="63"
column="35"/>
</issue>
@@ -558,7 +569,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="71"
+ line="72"
column="12"/>
</issue>
@@ -569,7 +580,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="71"
+ line="72"
column="44"/>
</issue>
@@ -580,7 +591,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="71"
+ line="72"
column="58"/>
</issue>
@@ -591,7 +602,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="71"
+ line="72"
column="75"/>
</issue>
@@ -602,7 +613,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="72"
+ line="73"
column="13"/>
</issue>
@@ -613,7 +624,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/remotecallback/ContentProviderWithCallbacks.java"
- line="72"
+ line="73"
column="26"/>
</issue>
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index b68217d..3f9b1b1 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -85,7 +85,7 @@
// libs.findbugs dependency resolves an app/testapp version conflict.
implementation(libs.findbugs)
implementation("androidx.recyclerview:recyclerview:1.0.0")
- implementation("androidx.appcompat:appcompat:1.0.0")
+ implementation("androidx.appcompat:appcompat:1.3.1")
// use the shadowed dependency in tests so that if the shadowing does not work properly,
// our tests fail.
annotationProcessor project(path: ":room:room-compiler",
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
index f42dc03..6733fc2 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
@@ -16,6 +16,7 @@
package androidx.room.compiler.processing
+import com.squareup.javapoet.ClassName
import kotlin.reflect.KClass
/**
@@ -23,6 +24,21 @@
*/
interface XAnnotated {
/**
+ * Returns the list of [XAnnotation] elements that have the same qualified name as the given
+ * [annotationName]. Otherwise, returns an empty list.
+ *
+ * For repeated annotations declared in Java code, please use the repeated annotation type,
+ * not the container. Calling this method with a container annotation will have inconsistent
+ * behaviour between Java AP and KSP.
+ *
+ * @see [hasAnnotation]
+ * @see [hasAnnotationWithPackage]
+ */
+ fun getAnnotations(annotationName: ClassName): List<XAnnotation> {
+ return getAllAnnotations().filter { annotationName.canonicalName() == it.qualifiedName }
+ }
+
+ /**
* Gets the list of annotations with the given type.
*
* For repeated annotations declared in Java code, please use the repeated annotation type,
@@ -63,6 +79,16 @@
): Boolean
/**
+ * Returns `true` if this element is annotated with an [XAnnotation] that has the same
+ * qualified name as the given [annotationName].
+ *
+ * @see [hasAnyOf]
+ */
+ fun hasAnnotation(annotationName: ClassName): Boolean {
+ return getAnnotations(annotationName).isNotEmpty()
+ }
+
+ /**
* Returns `true` if this element has an annotation that is declared in the given package.
* Alternatively, all annotations can be accessed with [getAllAnnotations].
*/
@@ -91,4 +117,27 @@
fun <T : Annotation> getAnnotation(annotation: KClass<T>): XAnnotationBox<T>? {
return getAnnotations(annotation).firstOrNull()
}
+
+ /**
+ * Returns the [XAnnotation] that has the same qualified name as [annotationName].
+ * Otherwise, `null` value is returned.
+ *
+ * @see [hasAnnotation]
+ * @see [getAnnotations]
+ * @see [hasAnnotationWithPackage]
+ */
+ fun getAnnotation(annotationName: ClassName): XAnnotation? {
+ return getAnnotations(annotationName).firstOrNull()
+ }
+
+ /**
+ * Returns the [XAnnotation] that has the same qualified name as [annotationName].
+ *
+ * @see [hasAnnotation]
+ * @see [getAnnotations]
+ * @see [hasAnnotationWithPackage]
+ */
+ fun requireAnnotation(annotationName: ClassName): XAnnotation {
+ return getAnnotation(annotationName)!!
+ }
}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
index c3cadc6..6bc891a 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
@@ -16,21 +16,34 @@
package androidx.room.compiler.processing.compat
+import androidx.room.compiler.processing.XAnnotation
+import androidx.room.compiler.processing.XAnnotationValue
import androidx.room.compiler.processing.XElement
import androidx.room.compiler.processing.XExecutableElement
+import androidx.room.compiler.processing.XFiler
+import androidx.room.compiler.processing.XMessager
import androidx.room.compiler.processing.XProcessingEnv
import androidx.room.compiler.processing.XRoundEnv
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
import androidx.room.compiler.processing.XVariableElement
+import androidx.room.compiler.processing.javac.JavacAnnotation
+import androidx.room.compiler.processing.javac.JavacAnnotationValue
import androidx.room.compiler.processing.javac.JavacElement
import androidx.room.compiler.processing.javac.JavacExecutableElement
+import androidx.room.compiler.processing.javac.JavacFiler
import androidx.room.compiler.processing.javac.JavacProcessingEnv
+import androidx.room.compiler.processing.javac.JavacProcessingEnvMessager
import androidx.room.compiler.processing.javac.JavacRoundEnv
import androidx.room.compiler.processing.javac.JavacType
import androidx.room.compiler.processing.javac.JavacTypeElement
import androidx.room.compiler.processing.javac.JavacVariableElement
+import javax.annotation.processing.Filer
+import javax.annotation.processing.Messager
+import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.element.AnnotationMirror
+import javax.lang.model.element.AnnotationValue
import javax.lang.model.element.Element
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.TypeElement
@@ -39,11 +52,19 @@
// Migration APIs for converting between Javac and XProcessing types.
object XConverters {
+ @JvmStatic
+ fun XProcessingEnv.toJavac(): ProcessingEnvironment = (this as JavacProcessingEnv).delegate
@JvmStatic
fun XRoundEnv.toJavac(): RoundEnvironment = (this as JavacRoundEnv).delegate
@JvmStatic
+ fun XMessager.toJavac(): Messager = (this as JavacProcessingEnvMessager).delegate
+
+ @JvmStatic
+ fun XFiler.toJavac(): Filer = (this as JavacFiler).delegate
+
+ @JvmStatic
fun XElement.toJavac(): Element = (this as JavacElement).element
@JvmStatic
@@ -56,6 +77,12 @@
fun XVariableElement.toJavac(): VariableElement = (this as JavacVariableElement).element
@JvmStatic
+ fun XAnnotation.toJavac(): AnnotationMirror = (this as JavacAnnotation).mirror
+
+ @JvmStatic
+ fun XAnnotationValue.toJavac(): AnnotationValue = (this as JavacAnnotationValue).annotationValue
+
+ @JvmStatic
fun XType.toJavac(): TypeMirror = (this as JavacType).typeMirror
@JvmStatic
@@ -82,5 +109,17 @@
fun VariableElement.toXProcessing(env: XProcessingEnv): XVariableElement =
(env as JavacProcessingEnv).wrapVariableElement(this)
+ @JvmStatic
+ fun AnnotationMirror.toXProcessing(env: XProcessingEnv): XAnnotation =
+ JavacAnnotation(env as JavacProcessingEnv, this)
+
+ @JvmStatic
+ fun Filer.toXProcessing(env: XProcessingEnv): XFiler =
+ JavacFiler(env as JavacProcessingEnv, this)
+
+ @JvmStatic
+ fun Messager.toXProcessing(): XMessager =
+ JavacProcessingEnvMessager(this)
+
// TODO: TypeMirror to XType, this will be more complicated since location context is lost...
}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFiler.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFiler.kt
index 484ed66..d61dc26c 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFiler.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFiler.kt
@@ -17,15 +17,19 @@
package androidx.room.compiler.processing.javac
import androidx.room.compiler.processing.XFiler
+import androidx.room.compiler.processing.XProcessingEnv
import com.squareup.javapoet.JavaFile
import com.squareup.kotlinpoet.FileSpec
-import javax.annotation.processing.ProcessingEnvironment
+import javax.annotation.processing.Filer
-internal class JavacFiler(val processingEnv: ProcessingEnvironment) : XFiler {
+internal class JavacFiler(
+ private val processingEnv: XProcessingEnv,
+ val delegate: Filer
+) : XFiler {
// "mode" is ignored in javac, and only applicable in KSP
override fun write(javaFile: JavaFile, mode: XFiler.Mode) {
- javaFile.writeTo(processingEnv.filer)
+ javaFile.writeTo(delegate)
}
override fun write(fileSpec: FileSpec, mode: XFiler.Mode) {
@@ -34,6 +38,6 @@
"Could not generate kotlin file $filePath/${fileSpec.name}.kt. The " +
"annotation processing environment is not set to generate Kotlin files."
}
- fileSpec.writeTo(processingEnv.filer)
+ fileSpec.writeTo(delegate)
}
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt
index b689751..aa80f8c 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt
@@ -61,10 +61,10 @@
)
override val messager: XMessager by lazy {
- JavacProcessingEnvMessager(delegate)
+ JavacProcessingEnvMessager(delegate.messager)
}
- override val filer = JavacFiler(delegate)
+ override val filer = JavacFiler(this, delegate.filer)
override val options: Map<String, String>
get() = delegate.options
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnvMessager.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnvMessager.kt
index e4a2811..8021645 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnvMessager.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnvMessager.kt
@@ -20,12 +20,12 @@
import androidx.room.compiler.processing.XAnnotationValue
import androidx.room.compiler.processing.XElement
import androidx.room.compiler.processing.XMessager
-import javax.annotation.processing.ProcessingEnvironment
+import javax.annotation.processing.Messager
import javax.lang.model.element.Element
import javax.tools.Diagnostic
internal class JavacProcessingEnvMessager(
- private val processingEnv: ProcessingEnvironment
+ val delegate: Messager
) : XMessager() {
override fun onPrintMessage(
kind: Diagnostic.Kind,
@@ -35,7 +35,7 @@
annotationValue: XAnnotationValue?
) {
if (element == null) {
- processingEnv.messager.printMessage(kind, msg)
+ delegate.printMessage(kind, msg)
return
}
@@ -47,18 +47,18 @@
msg
}
if (annotation == null) {
- processingEnv.messager.printMessage(kind, msg, javacElement)
+ delegate.printMessage(kind, msg, javacElement)
return
}
val javacAnnotation = (annotation as JavacAnnotation).mirror
if (annotationValue == null) {
- processingEnv.messager.printMessage(kind, msg, javacElement, javacAnnotation)
+ delegate.printMessage(kind, msg, javacElement, javacAnnotation)
return
}
val javacAnnotationValue = (annotationValue as JavacAnnotationValue).annotationValue
- processingEnv.messager.printMessage(
+ delegate.printMessage(
kind, msg, javacElement, javacAnnotation, javacAnnotationValue
)
}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
index f7b5a10..5b2295a 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
@@ -174,6 +174,35 @@
}
@Test
+ fun readSimpleAnnotationValueFromClassName() {
+ val source = Source.java(
+ "foo.bar.Baz",
+ """
+ package foo.bar;
+ import androidx.room.compiler.processing.testcode.TestSuppressWarnings;
+ @TestSuppressWarnings({"warning1", "warning 2"})
+ public class Baz {
+ }
+ """.trimIndent()
+ )
+ runTest(
+ sources = listOf(source)
+ ) { invocation ->
+ val element = invocation.processingEnv.requireTypeElement("foo.bar.Baz")
+ val annotation =
+ element.requireAnnotation(ClassName.get(TestSuppressWarnings::class.java))
+
+ val argument = annotation.annotationValues.single()
+ assertThat(argument.name).isEqualTo("value")
+ assertThat(
+ argument.value
+ ).isEqualTo(
+ listOf("warning1", "warning 2")
+ )
+ }
+ }
+
+ @Test
fun typeReference_javac() {
val mySource = Source.java(
"foo.bar.Baz",
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt
index 3c4b793..5e09bf5 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt
@@ -19,20 +19,29 @@
import androidx.room.compiler.processing.compat.XConverters.toJavac
import androidx.room.compiler.processing.compat.XConverters.toXProcessing
import androidx.room.compiler.processing.javac.JavacProcessingEnv
+import androidx.room.compiler.processing.testcode.TestSuppressWarnings
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.getDeclaredField
import androidx.room.compiler.processing.util.getDeclaredMethod
import androidx.room.compiler.processing.util.runKaptTest
+import com.google.auto.common.MoreElements
import com.google.common.truth.Truth.assertThat
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.JavaFile
+import com.squareup.javapoet.TypeSpec
import org.junit.Test
+import javax.annotation.processing.Filer
+import javax.annotation.processing.Messager
import javax.lang.model.util.ElementFilter
+import javax.tools.Diagnostic
class XConvertersTest {
val kotlinSrc = Source.kotlin(
"KotlinClass.kt",
"""
+ @androidx.room.compiler.processing.testcode.TestSuppressWarnings("warning1")
class KotlinClass {
var field = 1
fun foo(param: Int) {
@@ -43,6 +52,7 @@
val javaSrc = Source.java(
"JavaClass",
"""
+ @androidx.room.compiler.processing.testcode.TestSuppressWarnings("warning1")
public class JavaClass {
public int field = 1;
public void foo(int param) {
@@ -183,6 +193,93 @@
}
}
+ @Suppress("UnstableApiUsage")
+ @Test
+ fun annotation() {
+ runKaptTest(
+ sources = listOf(kotlinSrc, javaSrc)
+ ) { invocation ->
+ val kotlinClass = invocation.processingEnv.requireTypeElement("KotlinClass")
+ val javaClass = invocation.processingEnv.requireTypeElement("JavaClass")
+
+ assertThat(
+ kotlinClass.requireAnnotation(ClassName.get(TestSuppressWarnings::class.java))
+ .toJavac()
+ ).isEqualTo(
+ MoreElements.getAnnotationMirror(
+ invocation.getJavacTypeElement("KotlinClass"),
+ TestSuppressWarnings::class.java
+ ).get()
+ )
+ assertThat(
+ javaClass.requireAnnotation(ClassName.get(TestSuppressWarnings::class.java))
+ .toJavac()
+ ).isEqualTo(
+ MoreElements.getAnnotationMirror(
+ invocation.getJavacTypeElement("JavaClass"),
+ TestSuppressWarnings::class.java
+ ).get()
+ )
+ }
+ }
+
+ @Suppress("UnstableApiUsage")
+ @Test
+ fun customFiler() {
+ var runCount = 0
+ runKaptTest(
+ sources = listOf(kotlinSrc, javaSrc)
+ ) { invocation ->
+ val className = ClassName.get("foo.bar", "ToBeGenerated")
+ if (invocation.processingEnv.findTypeElement(className) == null) {
+ // Assert that this is only run only on the first round
+ assertThat(++runCount).isEqualTo(1)
+
+ // Check that we can create a custom filer and toJavac() returns it
+ val filer = invocation.processingEnv.filer.toJavac()
+ val customFiler = object : Filer by filer {}
+ val customXFiler = customFiler.toXProcessing(invocation.processingEnv)
+ assertThat(customXFiler.toJavac()).isEqualTo(customFiler)
+ val spec = TypeSpec.classBuilder(className).build()
+ customXFiler.write(JavaFile.builder(className.packageName(), spec).build())
+ } else {
+ // Asserts that the class was generated in the second round
+ assertThat(++runCount).isEqualTo(2)
+ assertThat(invocation.processingEnv.findTypeElement(className)).isNotNull()
+ }
+ }
+ }
+
+ @Suppress("UnstableApiUsage")
+ @Test
+ fun customMessager() {
+ runKaptTest(
+ sources = listOf(kotlinSrc, javaSrc)
+ ) { invocation ->
+ // Check that we can create a custom messager and toJavac() returns it
+ val customMessager = object : Messager by invocation.processingEnv.messager.toJavac() {
+ override fun printMessage(kind: Diagnostic.Kind?, msg: CharSequence?) {
+ // We have to use the XMessager from XProcessingEnv here so that it runs the
+ // hooks that are attached to the testing infrastructure. Otherwise, the error
+ // is produced by not recorded. We may want to add a method to XMessager to copy
+ // the watchers from another messager, e.g. XMessager#copyWatchers(XMessager)
+ invocation.processingEnv.messager.printMessage(kind!!, "Custom: $msg")
+ }
+ }
+ val customXMessager = customMessager.toXProcessing()
+ assertThat(customXMessager.toJavac()).isEqualTo(customMessager)
+
+ // Check that the custom messager prints the proper message
+ customXMessager.printMessage(Diagnostic.Kind.ERROR, "error msg")
+ invocation.assertCompilationResult {
+ compilationDidFail()
+ hasErrorCount(1)
+ hasWarningCount(0)
+ hasError("Custom: error msg")
+ }
+ }
+ }
+
private fun XTestInvocation.getJavacTypeElement(fqn: String) =
(this.processingEnv as JavacProcessingEnv).delegate.elementUtils.getTypeElement(fqn)
}
\ No newline at end of file
diff --git a/room/room-compiler/build.gradle b/room/room-compiler/build.gradle
index d2b5199..94604f8 100644
--- a/room/room-compiler/build.gradle
+++ b/room/room-compiler/build.gradle
@@ -19,7 +19,8 @@
import androidx.build.LibraryType
import androidx.build.SupportConfig
import androidx.build.SdkHelperKt
-import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
+import java.util.zip.ZipEntry
+import java.util.zip.ZipFile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
@@ -61,6 +62,8 @@
exclude(dependency("org.glassfish:.*"))
exclude(dependency("com.ibm.icu:.*"))
}
+ relocate("org.antlr", "androidx.room.jarjarred.org.antlr")
+ relocate("org.stringtemplate", "androidx.room.jarjarred.org.stringtemplate")
}
jar {
@@ -70,14 +73,6 @@
archiveClassifier = "before-jarjar"
}
-// relocate all shadow dependencies
-task relocateShadowJar(type: ConfigureShadowRelocation) {
- target = tasks.shadowJar
- prefix = "androidx.room.jarjarred"
-}
-
-tasks.shadowJar.dependsOn(tasks.relocateShadowJar)
-
configurations {
// replace the standard jar with the one built by 'shadowJar' in both api and runtime variants
apiElements.outgoing.artifacts.clear()
@@ -166,17 +161,27 @@
* their location.
*/
def validateJarContents(File jarFile) {
- FileTree jarFiles = project.zipTree(jarFile)
- def found = false
- jarFiles.files.each {
- if (it.path.contains("/org/antlr")) {
- found = true
- if (!it.path.contains("androidx/room/jarjarred/org/antlr")) {
- throw new GradleException("Any Antlr class included in the Room Compiler's" +
- " jar file should be moved into androidx/room/jarjarred.\n" +
- "Looks like $it has not been moved")
+ Boolean found = false
+ ZipFile zip = new ZipFile(jarFile)
+ try {
+ for (Enumeration list = zip.entries(); list.hasMoreElements(); ) {
+ String entry = ((ZipEntry) list.nextElement()).name
+ if (!entry.endsWith(".class")) continue
+ if (entry.contains("org/antlr")) {
+ found = true
+ if (!entry.contains("androidx/room/jarjarred/org/antlr")) {
+ throw new GradleException("Any Antlr class included in the Room Compiler's" +
+ " jar file should be moved into androidx/room/jarjarred.\n" +
+ "Looks like $entry has not been moved")
+ }
+ }
+ if (!entry.startsWith("androidx/room/")) {
+ throw new GradleException("Found a class that is not in androidx.room " +
+ "package: $entry")
}
}
+ } finally {
+ zip.close()
}
if (!found) {
throw new GradleException("Couldn't find any Antlr classes in room-compiler artifact" +
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/parser/optimization/RemoveUnusedColumnQueryRewriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/parser/optimization/RemoveUnusedColumnQueryRewriter.kt
index 56264f6..d3af5f2 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/parser/optimization/RemoveUnusedColumnQueryRewriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/parser/optimization/RemoveUnusedColumnQueryRewriter.kt
@@ -36,9 +36,7 @@
if (resultAdapter.mappings.isEmpty()) {
return query
}
- val usedColumns = resultAdapter.mappings.flatMap { mapping ->
- mapping.matchedFields.map { it.columnName }
- }
+ val usedColumns = resultAdapter.mappings.flatMap { it.usedColumns }
val columnNames = resultInfo.columns.map { it.name }
val unusedColumns = columnNames - usedColumns
if (unusedColumns.isEmpty()) {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
index 55b23e7..ca71c90 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
@@ -224,15 +224,15 @@
}
query.resultInfo?.let { queryResultInfo ->
- val mappings = resultBinder.adapter?.mappings ?: return@let
+ val mappings =
+ resultBinder.adapter?.mappings?.filterIsInstance<PojoRowAdapter.PojoMapping>()
+ ?: return@let
// If there are no mapping (e.g. might be a primitive return type result), then we
// can't reasonable determine cursor mismatch.
if (mappings.isEmpty()) {
return@let
}
- val usedColumns = mappings.flatMap { mapping ->
- mapping.matchedFields.map { it.columnName }
- }
+ val usedColumns = mappings.flatMap { it.usedColumns }
val columnNames = queryResultInfo.columns.map { it.name }
val unusedColumns = columnNames - usedColumns
val pojoUnusedFields = mappings
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
index 89b89f5..03bd06d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
@@ -46,8 +46,8 @@
private val info: QueryResultInfo?,
val pojo: Pojo,
out: XType
-) : RowAdapter(out) {
- val mapping: QueryMappedResultAdapter.Mapping
+) : RowAdapter(out), QueryMappedRowAdapter {
+ override val mapping: PojoMapping
val relationCollectors: List<RelationCollector>
// Set when cursor is ready.
@@ -92,7 +92,7 @@
}
relationCollectors = RelationCollector.createCollectors(context, pojo.relations)
- mapping = QueryMappedResultAdapter.Mapping(
+ mapping = PojoMapping(
pojo = pojo,
matchedFields = matchedFields,
unusedColumns = unusedColumns,
@@ -155,4 +155,13 @@
)
}
}
+
+ data class PojoMapping(
+ val pojo: Pojo,
+ val matchedFields: List<Field>,
+ val unusedColumns: List<String>,
+ val unusedFields: List<Field>
+ ) : QueryMappedRowAdapter.Mapping() {
+ override val usedColumns = matchedFields.map { it.columnName }
+ }
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryMappedResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryMappedResultAdapter.kt
deleted file mode 100644
index 0c54ef7..0000000
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryMappedResultAdapter.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.room.solver.query.result
-
-import androidx.room.vo.Field
-import androidx.room.vo.Pojo
-
-/**
- * Interface that defines a result adapter containing mapping information of the query and its
- * result POJOs if any.
- */
-interface QueryMappedResultAdapter {
- val mappings: List<Mapping>
-
- data class Mapping(
- val pojo: Pojo,
- val matchedFields: List<Field>,
- val unusedColumns: List<String>,
- val unusedFields: List<Field>
- )
-}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryMappedRowAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryMappedRowAdapter.kt
new file mode 100644
index 0000000..af3f6cf
--- /dev/null
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryMappedRowAdapter.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.solver.query.result
+
+/**
+ * Interface that defines a row adapter containing mapping information of the query and its
+ * result usage.
+ */
+interface QueryMappedRowAdapter {
+ val mapping: Mapping
+
+ /**
+ * Base class of an adapter mapping declaring the used columns by the adapter.
+ */
+ abstract class Mapping {
+ abstract val usedColumns: List<String>
+ }
+}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultAdapter.kt
index fce3604..f6cb819 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultAdapter.kt
@@ -21,10 +21,10 @@
/**
* Gets a Cursor and converts it into the return type of a method annotated with @Query.
*/
-abstract class QueryResultAdapter(val rowAdapters: List<RowAdapter>) : QueryMappedResultAdapter {
+abstract class QueryResultAdapter(val rowAdapters: List<RowAdapter>) {
- override val mappings: List<QueryMappedResultAdapter.Mapping>
- get() = rowAdapters.filterIsInstance<PojoRowAdapter>().map { it.mapping }
+ val mappings: List<QueryMappedRowAdapter.Mapping>
+ get() = rowAdapters.filterIsInstance<QueryMappedRowAdapter>().map { it.mapping }
abstract fun convert(outVarName: String, cursorVarName: String, scope: CodeGenScope)
@@ -33,6 +33,8 @@
fun shouldCopyCursor(): Boolean =
rowAdapters.filterIsInstance<PojoRowAdapter>().any { it.relationCollectors.isNotEmpty() }
+ // Gets a list of additionally accessed table names in sub queries done by the adapter
+ // (e.g. does done to satisfy @Relation fields).
fun accessedTableNames(): List<String> =
rowAdapters.filterIsInstance<PojoRowAdapter>().flatMap { it.relationTableNames() }
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt b/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
index d7fd403..07b664e 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
@@ -24,7 +24,6 @@
import androidx.room.vo.FtsEntity
import androidx.room.vo.FtsOptions
import androidx.room.vo.Warning
-import columnInfo
import org.sqlite.JDBC
import org.sqlite.SQLiteJDBCLoader
import java.io.File
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt
index 63ac0bf..a5da941 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt
@@ -14,9 +14,10 @@
* limitations under the License.
*/
+package androidx.room.verifier
+
import androidx.room.ext.capitalize
import androidx.room.parser.SQLTypeAffinity
-import androidx.room.verifier.ColumnInfo
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.ResultSetMetaData
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/verifier/DatabaseVerifierTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/verifier/DatabaseVerifierTest.kt
index 0154059..51c6f6a 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/verifier/DatabaseVerifierTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/verifier/DatabaseVerifierTest.kt
@@ -38,8 +38,6 @@
import androidx.room.vo.FieldSetter
import androidx.room.vo.Fields
import androidx.room.vo.PrimaryKey
-import collect
-import columnNames
import com.squareup.javapoet.TypeName
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.containsString
diff --git a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
index abcf013..0b2d513 100644
--- a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
+++ b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
@@ -172,11 +172,15 @@
// now add items
dao.addAllItems(itemsList)
- // the db write should cause pagingSource to realize it is invalid
+ // invalidate pagingSource to imitate invalidation from running refreshVersionSync
+ pagingSource.invalidate()
+ assertTrue(pagingSource.invalid)
+
+ // this refresh should check pagingSource's invalid status, realize it is invalid, and
+ // return a LoadResult.Invalid
assertThat(pagingSource.refresh()).isInstanceOf(
LoadResult.Invalid::class.java
)
- assertTrue(pagingSource.invalid)
}
}
diff --git a/samples/Support4Demos/src/main/AndroidManifest.xml b/samples/Support4Demos/src/main/AndroidManifest.xml
index 98fc5b7..4ee5389 100644
--- a/samples/Support4Demos/src/main/AndroidManifest.xml
+++ b/samples/Support4Demos/src/main/AndroidManifest.xml
@@ -22,153 +22,178 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.supportv4">
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <application
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/app_sample_code"
+ android:label="@string/activity_sample_code"
+ android:supportsRtl="true">
- <!-- The smallest screen this app works on is a phone. The app will
- scale its UI to larger screens but doesn't make good use of them
- so allow the compatibility mode button to be shown (mostly because
- this is just convenient for testing). -->
- <supports-screens android:requiresSmallestWidthDp="320"
- android:compatibleWidthLimitDp="480" />
-
- <application android:label="@string/activity_sample_code"
- android:icon="@drawable/app_sample_code"
- android:hardwareAccelerated="true"
- android:supportsRtl="true">
-
- <activity android:name="Support4Demos">
+ <activity
+ android:name="Support4Demos"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".app.SendResult"
- android:theme="@style/ThemeDialogWhenLarge">
- </activity>
+ <activity
+ android:name=".app.SendResult"
+ android:exported="true"
+ android:theme="@style/ThemeDialogWhenLarge"></activity>
<!-- Fragment Support Samples -->
- <activity android:name=".app.FragmentAlertDialogSupport"
- android:label="@string/fragment_alert_dialog_support">
+ <activity
+ android:name=".app.FragmentAlertDialogSupport"
+ android:exported="true"
+ android:label="@string/fragment_alert_dialog_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentArgumentsSupport"
- android:label="@string/fragment_arguments_support">
+ <activity
+ android:name=".app.FragmentArgumentsSupport"
+ android:exported="true"
+ android:label="@string/fragment_arguments_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentCustomAnimationSupport"
- android:label="@string/fragment_custom_animation_support">
+ <activity
+ android:name=".app.FragmentCustomAnimationSupport"
+ android:exported="true"
+ android:label="@string/fragment_custom_animation_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentHideShowSupport"
- android:label="@string/fragment_hide_show_support"
- android:windowSoftInputMode="stateUnchanged">
+ <activity
+ android:name=".app.FragmentHideShowSupport"
+ android:exported="true"
+ android:label="@string/fragment_hide_show_support"
+ android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentContextMenuSupport"
- android:label="@string/fragment_context_menu_support">
+ <activity
+ android:name=".app.FragmentContextMenuSupport"
+ android:exported="true"
+ android:label="@string/fragment_context_menu_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentDialogSupport"
- android:label="@string/fragment_dialog_support">
+ <activity
+ android:name=".app.FragmentDialogSupport"
+ android:exported="true"
+ android:label="@string/fragment_dialog_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentDialogOrActivitySupport"
- android:label="@string/fragment_dialog_or_activity_support">
+ <activity
+ android:name=".app.FragmentDialogOrActivitySupport"
+ android:exported="true"
+ android:label="@string/fragment_dialog_or_activity_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentLayoutSupport"
- android:label="@string/fragment_layout_support">
+ <activity
+ android:name=".app.FragmentLayoutSupport"
+ android:exported="true"
+ android:label="@string/fragment_layout_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentListArraySupport"
- android:label="@string/fragment_list_array_support">
+ <activity
+ android:name=".app.FragmentListArraySupport"
+ android:exported="true"
+ android:label="@string/fragment_list_array_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentLayoutSupport$DetailsActivity" />
+ <activity
+ android:name=".app.FragmentLayoutSupport$DetailsActivity"
+ android:exported="true" />
- <activity android:name=".app.FragmentMenuSupport"
- android:label="@string/fragment_menu_support">
+ <activity
+ android:name=".app.FragmentMenuSupport"
+ android:exported="true"
+ android:label="@string/fragment_menu_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentReceiveResultSupport"
- android:label="@string/fragment_receive_result_support">
+ <activity
+ android:name=".app.FragmentReceiveResultSupport"
+ android:exported="true"
+ android:label="@string/fragment_receive_result_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentStackSupport"
- android:label="@string/fragment_stack_support">
+ <activity
+ android:name=".app.FragmentStackSupport"
+ android:exported="true"
+ android:label="@string/fragment_stack_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentPagerSupport"
- android:label="@string/fragment_pager_support">
+ <activity
+ android:name=".app.FragmentPagerSupport"
+ android:exported="true"
+ android:label="@string/fragment_pager_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentStatePagerSupport"
- android:label="@string/fragment_state_pager_support">
+ <activity
+ android:name=".app.FragmentStatePagerSupport"
+ android:exported="true"
+ android:label="@string/fragment_state_pager_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.FragmentViewModelSupport"
+ <activity
+ android:name=".app.FragmentViewModelSupport"
+ android:exported="true"
android:label="@string/fragment_view_model_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -176,33 +201,39 @@
</intent-filter>
</activity>
- <activity android:name=".app.LoaderCursorSupport"
- android:label="@string/loader_cursor_support">
+ <activity
+ android:name=".app.LoaderCursorSupport"
+ android:exported="true"
+ android:label="@string/loader_cursor_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.LoaderCustomSupport"
- android:label="@string/loader_custom_support">
+ <activity
+ android:name=".app.LoaderCustomSupport"
+ android:exported="true"
+ android:label="@string/loader_custom_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.LoaderThrottleSupport"
- android:label="@string/loader_throttle_support">
+ <activity
+ android:name=".app.LoaderThrottleSupport"
+ android:exported="true"
+ android:label="@string/loader_throttle_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <provider android:name=".app.LoaderThrottleSupport$SimpleProvider"
- android:authorities="com.example.android.apis.supportv4.app.LoaderThrottle" />
- <activity android:name=".app.SimpleJobIntentController"
+ <activity
+ android:name=".app.SimpleJobIntentController"
+ android:exported="true"
android:label="@string/simple_job_intent_controller">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -210,178 +241,204 @@
</intent-filter>
</activity>
- <service android:name=".app.SimpleJobIntentService"
- android:permission="android.permission.BIND_JOB_SERVICE" />
-
- <activity android:name=".content.LocalServiceBroadcaster"
- android:label="@string/local_service_broadcaster">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
- </intent-filter>
- </activity>
- <service android:name=".content.LocalServiceBroadcaster$LocalService"
- android:stopWithTask="true" />
-
- <activity android:name=".content.SimpleWakefulController"
- android:label="@string/simple_wakeful_controller">
+ <activity
+ android:name=".content.LocalServiceBroadcaster"
+ android:exported="true"
+ android:label="@string/local_service_broadcaster">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <receiver android:name=".content.SimpleWakefulReceiver" />
- <service android:name=".content.SimpleWakefulService" />
-
- <activity android:name=".accessibility.AccessibilityManagerSupportActivity"
- android:label="@string/accessibility_manager_title">
+ <activity
+ android:name=".content.SimpleWakefulController"
+ android:exported="true"
+ android:label="@string/simple_wakeful_controller">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".accessibility.AccessibilityDelegateSupportActivity"
- android:label="@string/accessibility_delegate_title">
+ <activity
+ android:name=".accessibility.AccessibilityManagerSupportActivity"
+ android:exported="true"
+ android:label="@string/accessibility_manager_title">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".accessibility.AccessibilityDelegateSupportActivity"
+ android:exported="true"
+ android:label="@string/accessibility_delegate_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".accessibility.AccessibilityRoleDescriptionSupportActivity"
- android:label="@string/accessibility_roledescription_title">
+ <activity
+ android:name=".accessibility.AccessibilityRoleDescriptionSupportActivity"
+ android:exported="true"
+ android:label="@string/accessibility_roledescription_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.SharingSupport"
- android:label="@string/sharing_support_title">
+ <activity
+ android:name=".app.SharingSupport"
+ android:exported="true"
+ android:label="@string/sharing_support_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
-
- <activity android:name=".app.SharingReceiverSupport"
- android:label="@string/sharing_receiver_title">
+ <activity
+ android:name=".app.SharingReceiverSupport"
+ android:exported="true"
+ android:label="@string/sharing_receiver_title">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
- <data android:mimeType="text/plain" />
+
<category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="text/plain" />
</intent-filter>
</activity>
- <activity android:name=".text.BidiFormatterSupport"
- android:label="@string/bidiformatter_support_title">
+ <activity
+ android:name=".text.BidiFormatterSupport"
+ android:exported="true"
+ android:label="@string/bidiformatter_support_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".view.ViewPagerActivity"
- android:label="@string/view_pager_layout_support">
+ <activity
+ android:name=".view.ViewPagerActivity"
+ android:exported="true"
+ android:label="@string/view_pager_layout_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.SwipeRefreshLayoutActivityList"
- android:label="@string/swipe_list"
- android:theme="@style/ThemeHoloLight">
+ <activity
+ android:name=".widget.SwipeRefreshLayoutActivityList"
+ android:exported="true"
+ android:label="@string/swipe_list"
+ android:theme="@style/ThemeHoloLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.SwipeRefreshLayoutActivityTextView"
- android:label="@string/swipe_text"
- android:theme="@style/ThemeHoloLight">
+ <activity
+ android:name=".widget.SwipeRefreshLayoutActivityTextView"
+ android:exported="true"
+ android:label="@string/swipe_text"
+ android:theme="@style/ThemeHoloLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.SwipeRefreshLayoutActivityNestedScrollView"
- android:label="@string/swipe_nested_sv"
- android:theme="@style/ThemeHoloLight">
+ <activity
+ android:name=".widget.SwipeRefreshLayoutActivityNestedScrollView"
+ android:exported="true"
+ android:label="@string/swipe_nested_sv"
+ android:theme="@style/ThemeHoloLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.SwipeRefreshLayoutChildAndParentActivity"
- android:label="@string/swipe_parent_child"
- android:theme="@style/ThemeHoloLight">
+ <activity
+ android:name=".widget.SwipeRefreshLayoutChildAndParentActivity"
+ android:exported="true"
+ android:label="@string/swipe_parent_child"
+ android:theme="@style/ThemeHoloLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ContentLoadingProgressBarActivity"
- android:label="@string/content_loading_progress_bar">
+ <activity
+ android:name=".widget.ContentLoadingProgressBarActivity"
+ android:exported="true"
+ android:label="@string/content_loading_progress_bar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.SlidingPaneLayoutActivity"
- android:label="@string/sliding_pane_layout_support">
+ <activity
+ android:name=".widget.SlidingPaneLayoutActivity"
+ android:exported="true"
+ android:label="@string/sliding_pane_layout_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ExploreByTouchHelperActivity"
- android:label="@string/explore_by_touch_helper_support">
+ <activity
+ android:name=".widget.ExploreByTouchHelperActivity"
+ android:exported="true"
+ android:label="@string/explore_by_touch_helper_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <provider android:authorities="com.example.supportv4.content.sharingsupportprovider"
- android:name=".content.SharingSupportProvider" />
-
- <!-- FileProvider Example -->
-
- <activity android:name=".content.FileProviderExample"
- android:label="@string/file_provider_example">
+ <activity
+ android:name=".content.FileProviderExample"
+ android:exported="true"
+ android:label="@string/file_provider_example">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.NestedScrollActivity"
- android:label="@string/nested_scroll">
+ <activity
+ android:name=".widget.NestedScrollActivity"
+ android:exported="true"
+ android:label="@string/nested_scroll">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.NestedScrollActivity3Levels"
- android:label="@string/nested_scroll_3_levels">
+ <activity
+ android:name=".widget.NestedScrollActivity3Levels"
+ android:exported="true"
+ android:label="@string/nested_scroll_3_levels">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".graphics.RoundedBitmapDrawableActivity"
+ <activity
+ android:name=".graphics.RoundedBitmapDrawableActivity"
+ android:exported="true"
android:label="Graphics/RoundedBitmapDrawable">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -389,36 +446,31 @@
</intent-filter>
</activity>
- <activity android:name=".graphics.DrawableCompatActivity"
- android:label="Graphics/DrawableCompat">
+ <activity
+ android:name=".graphics.DrawableCompatActivity"
+ android:exported="true"
+ android:label="Graphics/DrawableCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
</intent-filter>
</activity>
-<!-- BEGIN_INCLUDE(file_provider_declaration) -->
- <provider
- android:name="androidx.core.content.FileProvider"
- android:authorities="com.example.android.supportv4.my_files"
- android:grantUriPermissions="true"
- android:exported="false">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/my_paths" />
- </provider>
-<!-- END_INCLUDE(file_provider_declaration) -->
-
- <activity android:name=".view.inputmethod.CommitContentSupport"
- android:label="@string/commit_content_support">
+ <activity
+ android:name=".view.inputmethod.CommitContentSupport"
+ android:exported="true"
+ android:label="@string/commit_content_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv13.SUPPORT13_SAMPLE_CODE" />
</intent-filter>
</activity>
- <!-- MediaBrowserCompat Sample -->
- <activity android:name=".media.MediaBrowserSupport"
+ <!-- FileProvider Example -->
+
+ <activity
+ android:name=".media.MediaBrowserSupport"
+ android:exported="true"
android:label="@string/media_browser_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -428,6 +480,7 @@
<activity
android:name=".view.WindowInsetsPlayground"
+ android:exported="true"
android:label="@string/insets_playground"
android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar"
android:windowSoftInputMode="adjustResize">
@@ -439,6 +492,7 @@
<activity
android:name=".view.WindowInsetsControllerPlayground"
+ android:exported="true"
android:label="@string/insets_controller_playground"
android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar"
android:windowSoftInputMode="adjustResize">
@@ -448,32 +502,89 @@
</intent-filter>
</activity>
+ <meta-data
+ android:name="com.google.android.gms.car.notification.SmallIcon"
+ android:resource="@drawable/ic_notification" />
+
+ <meta-data
+ android:name="com.google.android.gms.car.application.theme"
+ android:resource="@style/CarTheme" />
+
+ <!-- BEGIN_INCLUDE(file_provider_declaration) -->
+ <provider
+ android:name=".app.LoaderThrottleSupport$SimpleProvider"
+ android:authorities="com.example.android.apis.supportv4.app.LoaderThrottle" />
+ <!-- END_INCLUDE(file_provider_declaration) -->
+
+ <provider
+ android:name=".content.SharingSupportProvider"
+ android:authorities="com.example.supportv4.content.sharingsupportprovider" />
+
+ <!-- MediaBrowserCompat Sample -->
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="com.example.android.supportv4.my_files"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/my_paths" />
+ </provider>
+
+ <receiver
+ android:name=".content.SimpleWakefulReceiver"
+ android:exported="true" />
+
+ <receiver
+ android:name="androidx.media.session.MediaButtonReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MEDIA_BUTTON" />
+ </intent-filter>
+ </receiver>
+
<!-- (OPTIONAL) use this meta data to indicate which icon should be used in media
notifications (for example, when the music changes and the user is
looking at another app) -->
- <meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
- android:resource="@drawable/ic_notification" />
+ <service
+ android:name=".app.SimpleJobIntentService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
<!--
(OPTIONAL) use this meta data to override the theme from which Android Auto will
look for colors. If you don't set this, Android Auto will look
for color attributes in your application theme.
-->
- <meta-data android:name="com.google.android.gms.car.application.theme"
- android:resource="@style/CarTheme" />
+ <service
+ android:name=".content.LocalServiceBroadcaster$LocalService"
+ android:exported="true"
+ android:stopWithTask="true" />
- <service android:name=".media.MediaBrowserServiceSupport"
- android:exported="true" android:process=":service">
+ <service android:name=".content.SimpleWakefulService" />
+
+ <service
+ android:name=".media.MediaBrowserServiceSupport"
+ android:exported="true"
+ android:process=":service">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
- <receiver android:name="androidx.media.session.MediaButtonReceiver" >
- <intent-filter>
- <action android:name="android.intent.action.MEDIA_BUTTON" />
- </intent-filter>
- </receiver>
-
</application>
+ <supports-screens
+ android:compatibleWidthLimitDp="480"
+ android:requiresSmallestWidthDp="320" />
+
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+
+ <!-- The smallest screen this app works on is a phone. The app will
+ scale its UI to larger screens but doesn't make good use of them
+ so allow the compatibility mode button to be shown (mostly because
+ this is just convenient for testing). -->
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
</manifest>
diff --git a/samples/Support7Demos/src/main/AndroidManifest.xml b/samples/Support7Demos/src/main/AndroidManifest.xml
index 1381479..f4b63c6 100644
--- a/samples/Support7Demos/src/main/AndroidManifest.xml
+++ b/samples/Support7Demos/src/main/AndroidManifest.xml
@@ -23,76 +23,63 @@
package="com.example.android.supportv7">
<!-- Permission for INTERNET is required for streaming video content
from the web, it's not required otherwise. -->
- <uses-permission android:name="android.permission.INTERNET" />
- <!-- Permission for SYSTEM_ALERT_WINDOW is only required for emulating
- remote display using system alert window. -->
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- <!-- Permission for READ_EXTERNAL_STORAGE is explicitly required for
- reading images from the media store from API v19+. -->
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-
- <!-- Permission for ACCESS_COARSE_LOCATION is required for DayNight themes. -->
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-
- <!-- The smallest screen this app works on is a phone. The app will
- scale its UI to larger screens but doesn't make good use of them
- so allow the compatibility mode button to be shown (mostly because
- this is just convenient for testing). -->
- <supports-screens android:requiresSmallestWidthDp="320"
- android:compatibleWidthLimitDp="480" />
-
<application
- android:label="@string/activity_sample_code"
- android:supportsRtl="true"
- android:icon="@drawable/app_sample_code"
- android:hardwareAccelerated="true">
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/app_sample_code"
+ android:label="@string/activity_sample_code"
+ android:supportsRtl="true">
- <activity android:name="Support7Demos">
+ <activity
+ android:name="Support7Demos"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <receiver android:name="com.example.android.supportv7.media.SampleMediaButtonReceiver">
+ <activity
+ android:name=".media.SampleMediaRouterActivity"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_dark"
+ android:theme="@style/Theme.SampleMediaRouter">
<intent-filter>
- <action android:name="android.intent.action.MEDIA_BUTTON" />
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
- </receiver>
+ </activity>
<!-- MediaRouter Support Samples -->
- <activity android:name=".media.SampleMediaRouterActivity"
- android:configChanges="orientation|screenSize"
- android:label="@string/sample_media_router_activity_dark"
- android:theme="@style/Theme.SampleMediaRouter">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity android:name=".media.SampleMediaRouterActivity$Light"
- android:configChanges="orientation|screenSize"
- android:label="@string/sample_media_router_activity_light"
- android:theme="@style/Theme.SampleMediaRouter.Light">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity android:name=".media.SampleMediaRouterActivity$LightWithDarkActionBar"
- android:configChanges="orientation|screenSize"
- android:label="@string/sample_media_router_activity_light_with_dark_action_bar"
- android:theme="@style/Theme.SampleMediaRouter.Light.DarkActionBar">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity android:name=".media.SampleMediaRouterActivity$DynamicGroupActivity"
+ <activity
+ android:name=".media.SampleMediaRouterActivity$Light"
android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_light"
+ android:theme="@style/Theme.SampleMediaRouter.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".media.SampleMediaRouterActivity$LightWithDarkActionBar"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_light_with_dark_action_bar"
+ android:theme="@style/Theme.SampleMediaRouter.Light.DarkActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".media.SampleMediaRouterActivity$DynamicGroupActivity"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
android:label="@string/sample_media_router_activity_dynamic_group"
android:theme="@style/Theme.SampleMediaRouter">
<intent-filter>
@@ -101,8 +88,10 @@
</intent-filter>
</activity>
- <activity android:name=".media.SampleMediaRouterActivity$OutputSwitcherActivity"
+ <activity
+ android:name=".media.SampleMediaRouterActivity$OutputSwitcherActivity"
android:configChanges="orientation|screenSize"
+ android:exported="true"
android:label="@string/sample_media_router_activity_output_switcher"
android:theme="@style/Theme.SampleMediaRouter">
<intent-filter>
@@ -111,63 +100,51 @@
</intent-filter>
</activity>
- <activity android:name=".media.SampleMediaRouteSettingsActivity"
- android:label="@string/sample_media_route_settings_activity"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name=".media.SampleMediaRouteSettingsActivity"
+ android:exported="true"
+ android:label="@string/sample_media_route_settings_activity"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
- <service android:name=".media.SampleMediaRouteProviderService"
- android:label="@string/sample_media_route_provider_service"
- android:process=":mrp">
- <intent-filter>
- <action android:name="android.media.MediaRouteProviderService" />
- <action android:name="android.media.MediaRoute2ProviderService" />
- </intent-filter>
- </service>
-
- <service android:name=".media.SampleDynamicGroupMrpService"
- android:label="@string/sample_media_route_provider_service"
- android:process=":dynamic_mrp">
- <intent-filter>
- <action android:name="android.media.MediaRouteProviderService" />
- <action android:name="android.media.MediaRoute2ProviderService" />
- </intent-filter>
- </service>
-
- <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
-
- <!-- GridLayout Support Samples -->
-
- <activity android:name=".view.GridLayout1"
- android:label="@string/grid_layout_1">
+ <activity
+ android:name=".view.GridLayout1"
+ android:exported="true"
+ android:label="@string/grid_layout_1">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".view.GridLayout2"
- android:label="@string/grid_layout_2">
+ <activity
+ android:name=".view.GridLayout2"
+ android:exported="true"
+ android:label="@string/grid_layout_2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".view.GridLayout3"
- android:label="@string/grid_layout_3">
+ <activity
+ android:name=".view.GridLayout3"
+ android:exported="true"
+ android:label="@string/grid_layout_3">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".view.SystemUIModes"
- android:label="Views/System UI Visibility/System UI Modes"
+ <activity
+ android:name=".view.SystemUIModes"
android:enabled="@bool/atLeastJellyBeanMR2"
+ android:exported="true"
+ android:label="Views/System UI Visibility/System UI Modes"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -175,27 +152,35 @@
</intent-filter>
</activity>
- <!-- Action Bar Samples -->
- <activity android:name=".app.ActionBarMechanics"
- android:label="@string/action_bar_mechanics"
- android:theme="@style/Theme.AppCompat">
+ <!-- GridLayout Support Samples -->
+
+ <activity
+ android:name=".app.ActionBarMechanics"
+ android:exported="true"
+ android:label="@string/action_bar_mechanics"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.SearchActivity">
+ <activity
+ android:name=".app.SearchActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
- <meta-data android:name="android.app.searchable"
- android:resource="@xml/searchable" />
+ <meta-data
+ android:name="android.app.searchable"
+ android:resource="@xml/searchable" />
</activity>
- <activity android:name=".app.ActionBarUsage"
+ <activity
+ android:name=".app.ActionBarUsage"
+ android:exported="true"
android:label="@string/action_bar_usage"
android:theme="@style/Theme.AppCompat">
<intent-filter>
@@ -204,7 +189,9 @@
</intent-filter>
</activity>
- <activity android:name=".app.ActionBarBackgroundChange"
+ <activity
+ android:name=".app.ActionBarBackgroundChange"
+ android:exported="true"
android:label="@string/action_bar_background_change"
android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
@@ -213,62 +200,77 @@
</intent-filter>
</activity>
- <activity android:name=".app.ActionBarDisplayOptions"
- android:label="@string/action_bar_display_options"
- android:logo="@drawable/apidemo_androidlogo"
- android:theme="@style/Theme.AppCompat">
+ <!-- Action Bar Samples -->
+ <activity
+ android:name=".app.ActionBarDisplayOptions"
+ android:exported="true"
+ android:label="@string/action_bar_display_options"
+ android:logo="@drawable/apidemo_androidlogo"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ActionBarSettingsActionProviderActivity"
- android:label="@string/action_bar_settings_action_provider"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+ <activity
+ android:name=".app.ActionBarSettingsActionProviderActivity"
+ android:exported="true"
+ android:label="@string/action_bar_settings_action_provider"
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ActionBarShareActionProvider"
- android:label="@string/action_bar_share_action_provider"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+ <activity
+ android:name=".app.ActionBarShareActionProvider"
+ android:exported="true"
+ android:label="@string/action_bar_share_action_provider"
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ActionBarFragmentMenu"
- android:label="@string/action_bar_fragment_menu"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".app.ActionBarFragmentMenu"
+ android:exported="true"
+ android:label="@string/action_bar_fragment_menu"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ActionBarActionMode"
- android:label="@string/action_bar_action_mode"
- android:theme="@style/Theme.Custom.WithActionMode">
+ <activity
+ android:name=".app.ActionBarActionMode"
+ android:exported="true"
+ android:label="@string/action_bar_action_mode"
+ android:theme="@style/Theme.Custom.WithActionMode">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ActionBarHideOnScroll"
- android:label="@string/action_bar_hide_scroll"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+ <activity
+ android:name=".app.ActionBarHideOnScroll"
+ android:exported="true"
+ android:label="@string/action_bar_hide_scroll"
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsButtons"
+ <activity
+ android:name=".app.AppCompatWidgetsButtons"
+ android:exported="true"
android:label="@string/appcompat_widgets_buttons"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
@@ -277,7 +279,9 @@
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsIcons"
+ <activity
+ android:name=".app.AppCompatWidgetsIcons"
+ android:exported="true"
android:label="@string/appcompat_widgets_icons"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
@@ -286,7 +290,9 @@
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsRatingBars"
+ <activity
+ android:name=".app.AppCompatWidgetsRatingBars"
+ android:exported="true"
android:label="@string/appcompat_widgets_ratingbars"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
@@ -295,16 +301,20 @@
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsSpinners"
- android:label="@string/appcompat_widgets_spinners"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+ <activity
+ android:name=".app.AppCompatWidgetsSpinners"
+ android:exported="true"
+ android:label="@string/appcompat_widgets_spinners"
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsSwitches"
+ <activity
+ android:name=".app.AppCompatWidgetsSwitches"
+ android:exported="true"
android:label="@string/appcompat_widgets_switches"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
@@ -313,25 +323,31 @@
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsTextInput"
- android:label="@string/appcompat_widgets_text_input"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+ <activity
+ android:name=".app.AppCompatWidgetsTextInput"
+ android:exported="true"
+ android:label="@string/appcompat_widgets_text_input"
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsTextViews"
- android:label="@string/appcompat_widgets_text_views"
- android:theme="@style/Theme.Custom.TextLink">
+ <activity
+ android:name=".app.AppCompatWidgetsTextViews"
+ android:exported="true"
+ android:label="@string/appcompat_widgets_text_views"
+ android:theme="@style/Theme.Custom.TextLink">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatWidgetsToggleButtons"
+ <activity
+ android:name=".app.AppCompatWidgetsToggleButtons"
+ android:exported="true"
android:label="@string/appcompat_widgets_toggle_buttons"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
@@ -340,56 +356,68 @@
</intent-filter>
</activity>
- <activity android:name=".app.MenuItemIconTinting"
- android:label="@string/menu_item_icon_tinting"
- android:theme="@style/Theme.Custom.NoActionBar">
+ <activity
+ android:name=".app.MenuItemIconTinting"
+ android:exported="true"
+ android:label="@string/menu_item_icon_tinting"
+ android:theme="@style/Theme.Custom.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ToolbarUsage"
- android:label="@string/toolbar_usage"
- android:theme="@style/Theme.Custom.NoActionBar">
+ <activity
+ android:name=".app.ToolbarUsage"
+ android:exported="true"
+ android:label="@string/toolbar_usage"
+ android:theme="@style/Theme.Custom.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
<meta-data
- android:name="android.app.default_searchable"
- android:value=".app.SearchActivity" />
+ android:name="android.app.default_searchable"
+ android:value=".app.SearchActivity" />
</activity>
- <activity android:name=".app.ToolbarDisplayOptions"
- android:label="@string/toolbar_display_options"
- android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+ <activity
+ android:name=".app.ToolbarDisplayOptions"
+ android:exported="true"
+ android:label="@string/toolbar_display_options"
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ToolbarFragmentPagerMenu"
- android:label="@string/toolbar_fragment_pager"
- android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+ <activity
+ android:name=".app.ToolbarFragmentPagerMenu"
+ android:exported="true"
+ android:label="@string/toolbar_fragment_pager"
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ToolbarActionMode"
- android:label="@string/toolbar_action_mode"
- android:theme="@style/Theme.Custom.NoActionBar.WithActionMode">
+ <activity
+ android:name=".app.ToolbarActionMode"
+ android:exported="true"
+ android:label="@string/toolbar_action_mode"
+ android:theme="@style/Theme.Custom.NoActionBar.WithActionMode">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.ToolbarBackgroundChange"
+ <activity
+ android:name=".app.ToolbarBackgroundChange"
+ android:exported="true"
android:label="@string/toolbar_background_change"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
@@ -402,7 +430,9 @@
android:value=".app.SearchActivity" />
</activity>
- <activity android:name=".app.ToolbarTall"
+ <activity
+ android:name=".app.ToolbarTall"
+ android:exported="true"
android:label="@string/toolbar_tall"
android:theme="@style/Theme.Custom.NoActionBar">
<intent-filter>
@@ -411,43 +441,53 @@
</intent-filter>
</activity>
- <activity android:name=".app.DialogUsage"
- android:label="@string/dialog_usage"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name=".app.DialogUsage"
+ android:exported="true"
+ android:label="@string/dialog_usage"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AlertDialogUsage"
- android:label="@string/alert_dialog_usage"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name=".app.AlertDialogUsage"
+ android:exported="true"
+ android:label="@string/alert_dialog_usage"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.DialogFragmentUsage"
- android:label="@string/dialogfragment_usage"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name=".app.DialogFragmentUsage"
+ android:exported="true"
+ android:label="@string/dialogfragment_usage"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatDefaultNightModeActivity"
- android:label="@string/mode_night_activity_title_default"
- android:theme="@style/Theme.AppCompat.DayNight">
+ <activity
+ android:name=".app.AppCompatDefaultNightModeActivity"
+ android:exported="true"
+ android:label="@string/mode_night_activity_title_default"
+ android:theme="@style/Theme.AppCompat.DayNight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatNightModeBounceActivity"
+ <activity
+ android:name=".app.AppCompatNightModeBounceActivity"
+ android:exported="true"
android:label="@string/mode_night_activity_title_bounce"
android:theme="@style/Theme.AppCompat.DayNight">
<intent-filter>
@@ -456,7 +496,9 @@
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatLocalNightModeActivity"
+ <activity
+ android:name=".app.AppCompatLocalNightModeActivity"
+ android:exported="true"
android:label="@string/mode_night_activity_title_local"
android:theme="@style/Theme.AppCompat.DayNight">
<intent-filter>
@@ -465,10 +507,11 @@
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatDefaultNightModeBootAwareActivity"
- android:label="@string/mode_night_activity_title_bootaware"
+ <activity
+ android:name=".app.AppCompatDefaultNightModeBootAwareActivity"
android:directBootAware="true"
android:exported="true"
+ android:label="@string/mode_night_activity_title_bootaware"
android:theme="@style/Theme.AppCompat.DayNight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -481,48 +524,53 @@
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatNightModeDialog"
- android:label="@string/mode_night_dialog_title"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".app.AppCompatNightModeDialog"
+ android:exported="true"
+ android:label="@string/mode_night_dialog_title"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatNightModeAlertDialog"
- android:label="@string/mode_night_alertdialog_title"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".app.AppCompatNightModeAlertDialog"
+ android:exported="true"
+ android:label="@string/mode_night_alertdialog_title"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".app.AppCompatAnimatedVector"
- android:label="@string/appcompat_vector_title"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name=".app.AppCompatAnimatedVector"
+ android:exported="true"
+ android:label="@string/appcompat_vector_title"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <!-- AnimatedStateListDrawable activity -->
- <activity android:name=".app.AppCompatAnimatedSelector"
- android:label="@string/appcompat_animated_selector_title"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".app.AppCompatAnimatedSelector"
+ android:exported="true"
+ android:label="@string/appcompat_animated_selector_title"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <provider android:name=".app.RecentSuggestionsProvider"
- android:authorities="com.example.android.supportv7.RecentSuggestionsProvider" />
-
- <!-- Nested Scrolling Samples -->
- <activity android:name=".widget.RecyclerViewCoordinatorLayoutAppBarActivity"
+ <activity
+ android:name=".widget.RecyclerViewCoordinatorLayoutAppBarActivity"
+ android:exported="true"
android:label="@string/nested_scrolling_rv_cl_appbar_activity"
android:theme="@style/Theme.AppCompat">
<intent-filter>
@@ -530,7 +578,10 @@
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.NestedScrollViewCoordinatorLayoutAppBarActivity"
+
+ <activity
+ android:name=".widget.NestedScrollViewCoordinatorLayoutAppBarActivity"
+ android:exported="true"
android:label="@string/nested_scrolling_nsv_cl_appbar_activity"
android:theme="@style/Theme.AppCompat">
<intent-filter>
@@ -539,17 +590,21 @@
</intent-filter>
</activity>
- <!-- RecyclerView samples -->
- <activity android:name=".widget.RecyclerViewActivity"
- android:label="@string/recycler_view"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.RecyclerViewActivity"
+ android:exported="true"
+ android:label="@string/recycler_view"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.RecyclerViewSmoothScrollByActivity"
+ <!-- AnimatedStateListDrawable activity -->
+ <activity
+ android:name=".widget.RecyclerViewSmoothScrollByActivity"
+ android:exported="true"
android:label="@string/recycler_view_smooth_scroll_by"
android:theme="@style/Theme.AppCompat">
<intent-filter>
@@ -558,43 +613,54 @@
</intent-filter>
</activity>
- <activity android:name=".widget.RvInNestedScrollViewActivity"
- android:label="@string/rv_in_nestedScrollView"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.RvInNestedScrollViewActivity"
+ android:exported="true"
+ android:label="@string/rv_in_nestedScrollView"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.RvIn2NestedScrollViewsActivity"
- android:label="@string/rv_in_2_nestedScrollViews"
- android:theme="@style/Theme.AppCompat">
+ <!-- Nested Scrolling Samples -->
+ <activity
+ android:name=".widget.RvIn2NestedScrollViewsActivity"
+ android:exported="true"
+ android:label="@string/rv_in_2_nestedScrollViews"
+ android:theme="@style/Theme.AppCompat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".widget.PagerRecyclerViewActivity"
+ android:exported="true"
+ android:label="@string/pager_recycler_view"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.PagerRecyclerViewActivity"
- android:label="@string/pager_recycler_view"
- android:theme="@style/Theme.AppCompat">
+ <!-- RecyclerView samples -->
+ <activity
+ android:name=".widget.AnimatedRecyclerView"
+ android:exported="true"
+ android:label="@string/animated_recycler_view"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.AnimatedRecyclerView"
- android:label="@string/animated_recycler_view"
- android:theme="@style/Theme.AppCompat">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity android:name=".widget.RemoveLargeItemsDemo"
+ <activity
+ android:name=".widget.RemoveLargeItemsDemo"
+ android:exported="true"
android:label="RecyclerView/Remove Large Items Demo"
android:theme="@style/Theme.AppCompat">
<intent-filter>
@@ -603,206 +669,305 @@
</intent-filter>
</activity>
- <activity android:name=".widget.NestedRecyclerViewActivity"
- android:label="@string/nested_recycler_view"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.NestedRecyclerViewActivity"
+ android:exported="true"
+ android:label="@string/nested_recycler_view"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.LinearLayoutManagerActivity"
- android:label="@string/linear_layout_manager"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.LinearLayoutManagerActivity"
+ android:exported="true"
+ android:label="@string/linear_layout_manager"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.LinearLayoutManagerJankActivity"
- android:label="@string/linear_layout_manager_jank"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.LinearLayoutManagerJankActivity"
+ android:exported="true"
+ android:label="@string/linear_layout_manager_jank"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".util.SortedListActivity"
- android:label="@string/sorted_list_activity"
- android:windowSoftInputMode="adjustResize"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".util.SortedListActivity"
+ android:exported="true"
+ android:label="@string/sorted_list_activity"
+ android:theme="@style/Theme.AppCompat"
+ android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.StableIdActivity"
- android:label="@string/recycler_view_stableid"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.StableIdActivity"
+ android:exported="true"
+ android:label="@string/recycler_view_stableid"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".util.DiffUtilActivity"
- android:label="@string/diff_util_activity"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".util.DiffUtilActivity"
+ android:exported="true"
+ android:label="@string/diff_util_activity"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.GridLayoutManagerActivity"
- android:label="@string/grid_layout_manager"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.GridLayoutManagerActivity"
+ android:exported="true"
+ android:label="@string/grid_layout_manager"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.StaggeredGridLayoutManagerActivity"
- android:label="@string/staggered_grid_layout_manager"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.StaggeredGridLayoutManagerActivity"
+ android:exported="true"
+ android:label="@string/staggered_grid_layout_manager"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.AsyncListUtilActivity"
- android:label="@string/async_list_util"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".widget.AsyncListUtilActivity"
+ android:exported="true"
+ android:label="@string/async_list_util"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".view.CardViewActivity"
- android:label="@string/card_view"
- android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+ <activity
+ android:name=".view.CardViewActivity"
+ android:exported="true"
+ android:label="@string/card_view"
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".graphics.PaletteActivity"
- android:label="@string/palette"
- android:theme="@style/Theme.AppCompat">
+ <activity
+ android:name=".graphics.PaletteActivity"
+ android:exported="true"
+ android:label="@string/palette"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".graphics.PaletteDetailActivity"
- android:label="@string/palette"
- android:theme="@style/Theme.AppCompat" />
+ <activity
+ android:name=".graphics.PaletteDetailActivity"
+ android:exported="true"
+ android:label="@string/palette"
+ android:theme="@style/Theme.AppCompat" />
+
+ <activity
+ android:name=".widget.touch.SwipeToDismissActivity"
+ android:exported="true"
+ android:label="@string/swipe_to_dismiss_activity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".widget.touch.DragAndDropActivity"
+ android:exported="true"
+ android:label="@string/drag_and_drop_activity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".widget.DrawerLayoutActivity"
+ android:exported="true"
+ android:label="@string/drawer_layout_activity"
+ android:theme="@style/Theme.SampleDrawerLayout">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".widget.ListPopupWindowActivity"
+ android:exported="true"
+ android:label="@string/list_popup_window_activity"
+ android:theme="@style/Theme.AppCompat.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".widget.PopupMenuActivity"
+ android:exported="true"
+ android:label="@string/popup_menu_activity"
+ android:theme="@style/Theme.AppCompat.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
<!-- item touch helper demo activities-->
- <activity android:name=".widget.touch.SwipeToDismissActivity"
- android:label="@string/swipe_to_dismiss_activity">
+ <activity
+ android:name=".widget.ListViewActivity"
+ android:exported="true"
+ android:label="@string/list_view_activity"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.touch.DragAndDropActivity"
- android:label="@string/drag_and_drop_activity">
+ <activity
+ android:name=".widget.selection.single.SingleStableIdSelectionDemoActivity"
+ android:exported="true"
+ android:label="@string/single_selection_demo_activity"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
<!-- DrawerLayout demo activity -->
- <activity android:name=".widget.DrawerLayoutActivity"
- android:label="@string/drawer_layout_activity"
- android:theme="@style/Theme.SampleDrawerLayout">
+ <activity
+ android:name=".widget.selection.simple.SimpleSelectionDemoActivity"
+ android:exported="true"
+ android:label="@string/simple_selection_demo_activity"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
<!-- ListPopupWindow demo activity -->
- <activity android:name=".widget.ListPopupWindowActivity"
- android:label="@string/list_popup_window_activity"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name=".widget.selection.fancy.FancySelectionDemoActivity"
+ android:exported="true"
+ android:label="@string/fancy_selection_demo_activity"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
<!-- PopupMenu demo activity -->
- <activity android:name=".widget.PopupMenuActivity"
- android:label="@string/popup_menu_activity"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name=".drawable.CustomDrawableActivity"
+ android:exported="true"
+ android:label="@string/custom_drawable"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
<!-- ListView styling activity -->
- <activity android:name=".widget.ListViewActivity"
- android:label="@string/list_view_activity"
- android:theme="@style/Theme.AppCompat.Light">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
- </intent-filter>
- </activity>
+ <provider
+ android:name=".app.RecentSuggestionsProvider"
+ android:authorities="com.example.android.supportv7.RecentSuggestionsProvider" />
<!-- Selection helper single selection demo activity -->
- <activity android:name=".widget.selection.single.SingleStableIdSelectionDemoActivity"
- android:label="@string/single_selection_demo_activity"
- android:theme="@style/Theme.AppCompat.Light">
+ <receiver android:name="com.example.android.supportv7.media.SampleMediaButtonReceiver"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
- </activity>
+ </receiver>
<!-- Selection helper rudimentary demo activity -->
- <activity android:name=".widget.selection.simple.SimpleSelectionDemoActivity"
- android:label="@string/simple_selection_demo_activity"
- android:theme="@style/Theme.AppCompat.Light">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
- </intent-filter>
- </activity>
+ <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver"
+ android:exported="true" />
<!-- Selection helper "the whole kit and caboodle" demo activity -->
- <activity android:name=".widget.selection.fancy.FancySelectionDemoActivity"
- android:label="@string/fancy_selection_demo_activity"
- android:theme="@style/Theme.AppCompat.Light">
+ <service
+ android:name=".media.SampleMediaRouteProviderService"
+ android:exported="true"
+ android:label="@string/sample_media_route_provider_service"
+ android:process=":mrp">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.media.MediaRouteProviderService" />
+ <action android:name="android.media.MediaRoute2ProviderService" />
</intent-filter>
- </activity>
+ </service>
<!-- Custom drawable activity -->
- <activity android:name=".drawable.CustomDrawableActivity"
- android:label="@string/custom_drawable"
- android:theme="@style/Theme.AppCompat.Light">
+ <service
+ android:name=".media.SampleDynamicGroupMrpService"
+ android:label="@string/sample_media_route_provider_service"
+ android:exported="true"
+ android:process=":dynamic_mrp">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ <action android:name="android.media.MediaRouteProviderService" />
+ <action android:name="android.media.MediaRoute2ProviderService" />
</intent-filter>
- </activity>
+ </service>
</application>
+ <!-- Permission for SYSTEM_ALERT_WINDOW is only required for emulating
+ remote display using system alert window. -->
+ <supports-screens
+ android:compatibleWidthLimitDp="480"
+ android:requiresSmallestWidthDp="320" />
+ <!-- Permission for READ_EXTERNAL_STORAGE is explicitly required for
+ reading images from the media store from API v19+. -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <!-- Permission for ACCESS_COARSE_LOCATION is required for DayNight themes. -->
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <!-- The smallest screen this app works on is a phone. The app will
+ scale its UI to larger screens but doesn't make good use of them
+ so allow the compatibility mode button to be shown (mostly because
+ this is just convenient for testing). -->
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
</manifest>
diff --git a/samples/SupportAnimationDemos/src/main/AndroidManifest.xml b/samples/SupportAnimationDemos/src/main/AndroidManifest.xml
index 243e6e4..cf6fc23 100644
--- a/samples/SupportAnimationDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportAnimationDemos/src/main/AndroidManifest.xml
@@ -16,25 +16,33 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.support.animation">
- <application android:label="@string/activity_sample_code"
- android:supportsRtl="true"
- android:icon="@drawable/app_sample_code"
- android:theme="@style/android:Theme.Holo.Light">
- <activity android:name=".MainActivity"
- android:label="ChainedSpringDemo">
+
+ <application
+ android:icon="@drawable/app_sample_code"
+ android:label="@string/activity_sample_code"
+ android:supportsRtl="true"
+ android:theme="@style/android:Theme.Holo.Light">
+ <activity
+ android:name=".MainActivity"
+ android:exported="true"
+ android:label="ChainedSpringDemo">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".BrowseActivity">
+ <activity
+ android:name=".BrowseActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".SpringActivity"
- android:label="SpringDemo">
+ <activity
+ android:name=".SpringActivity"
+ android:exported="true"
+ android:label="SpringDemo">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
diff --git a/samples/SupportContentDemos/src/main/AndroidManifest.xml b/samples/SupportContentDemos/src/main/AndroidManifest.xml
index 4f48ff5..4507e63 100644
--- a/samples/SupportContentDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportContentDemos/src/main/AndroidManifest.xml
@@ -27,7 +27,8 @@
<activity
android:name=".ContentPagerDemoActivity"
android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar">
+ android:theme="@style/AppTheme.NoActionBar"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/samples/SupportEmojiDemos/src/main/AndroidManifest.xml b/samples/SupportEmojiDemos/src/main/AndroidManifest.xml
index bf5e65c..22000bf 100755
--- a/samples/SupportEmojiDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportEmojiDemos/src/main/AndroidManifest.xml
@@ -30,7 +30,8 @@
<activity
android:name=".MainActivity"
- android:windowSoftInputMode="stateUnchanged">
+ android:windowSoftInputMode="stateUnchanged"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/samples/SupportLeanbackDemos/src/main/AndroidManifest.xml b/samples/SupportLeanbackDemos/src/main/AndroidManifest.xml
index fd39ac4..ecd3b3e 100644
--- a/samples/SupportLeanbackDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportLeanbackDemos/src/main/AndroidManifest.xml
@@ -24,7 +24,8 @@
android:theme="@style/Theme.Example.Leanback">
<activity android:name="MainActivity"
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
diff --git a/samples/SupportPreferenceDemos/src/main/AndroidManifest.xml b/samples/SupportPreferenceDemos/src/main/AndroidManifest.xml
index f2fbf0b..f25a041 100644
--- a/samples/SupportPreferenceDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportPreferenceDemos/src/main/AndroidManifest.xml
@@ -32,7 +32,8 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
- <activity android:name="MainActivity">
+ <activity android:name="MainActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="android.intent.action.VIEW"/>
@@ -45,7 +46,8 @@
<activity
android:name="Preferences"
android:label="@string/preferences"
- android:theme="@style/PreferenceTheme">
+ android:theme="@style/PreferenceTheme"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="com.example.androidx.preference.SAMPLE_CODE"/>
@@ -57,7 +59,8 @@
android:name="LeanbackPreferences"
android:label="@string/leanback_preferences"
android:theme="@style/LeanbackTheme"
- android:enabled="@bool/atLeastLollipop">
+ android:enabled="@bool/atLeastLollipop"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="com.example.androidx.preference.SAMPLE_CODE"/>
diff --git a/samples/SupportRemoteCallbackDemos/src/main/AndroidManifest.xml b/samples/SupportRemoteCallbackDemos/src/main/AndroidManifest.xml
index efa29cb..57a7ff3 100644
--- a/samples/SupportRemoteCallbackDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportRemoteCallbackDemos/src/main/AndroidManifest.xml
@@ -26,7 +26,8 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
- <receiver android:name=".RemoteCallbackProvider" >
+ <receiver android:name=".RemoteCallbackProvider"
+ android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
diff --git a/samples/SupportSliceDemos/src/main/AndroidManifest.xml b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
index 5767c33..9757694 100644
--- a/samples/SupportSliceDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
@@ -34,7 +34,8 @@
<activity
android:name=".SliceBrowser"
android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar">
+ android:theme="@style/AppTheme.NoActionBar"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/samples/SupportTransitionDemos/src/main/AndroidManifest.xml b/samples/SupportTransitionDemos/src/main/AndroidManifest.xml
index 7745a50..4008165 100644
--- a/samples/SupportTransitionDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportTransitionDemos/src/main/AndroidManifest.xml
@@ -21,121 +21,150 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.support.transition">
- <application android:label="@string/activity_sample_code"
- android:supportsRtl="true"
- android:icon="@drawable/app_sample_code"
- android:theme="@style/Theme.Transition">
- <activity android:name=".SupportTransitionDemos">
+ <application
+ android:icon="@drawable/app_sample_code"
+ android:label="@string/activity_sample_code"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.Transition">
+
+ <activity
+ android:name=".SupportTransitionDemos"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".widget.SceneUsage"
- android:label="@string/scene"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.SceneUsage"
+ android:exported="true"
+ android:label="@string/scene"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.CustomUsage"
- android:label="@string/custom"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.CustomUsage"
+ android:exported="true"
+ android:label="@string/custom"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.BeginDelayedUsage"
- android:label="@string/beginDelayed"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.BeginDelayedUsage"
+ android:exported="true"
+ android:label="@string/beginDelayed"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ArcMotionUsage"
- android:label="@string/arcMotion"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.ArcMotionUsage"
+ android:exported="true"
+ android:label="@string/arcMotion"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ExplodeUsage"
- android:label="@string/explode"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.ExplodeUsage"
+ android:exported="true"
+ android:label="@string/explode"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ChangeClipBoundsUsage"
- android:label="@string/clipBounds"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.ChangeClipBoundsUsage"
+ android:exported="true"
+ android:label="@string/clipBounds"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ChangeTransformUsage"
- android:label="@string/changeTransform"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.ChangeTransformUsage"
+ android:exported="true"
+ android:label="@string/changeTransform"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ChangeImageTransformUsage"
- android:label="@string/changeImageTransform"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.ChangeImageTransformUsage"
+ android:exported="true"
+ android:label="@string/changeImageTransform"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.ReparentImageUsage"
- android:label="@string/reparentImage"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.ReparentImageUsage"
+ android:exported="true"
+ android:label="@string/reparentImage"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.FragmentTransitionUsage"
- android:label="@string/fragmentTransition"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.FragmentTransitionUsage"
+ android:exported="true"
+ android:label="@string/fragmentTransition"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.SidePropagationUsage"
- android:label="@string/side_propagation"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.SidePropagationUsage"
+ android:exported="true"
+ android:label="@string/side_propagation"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name=".widget.RecyclerViewUsage"
- android:label="@string/recycler_view"
- android:theme="@style/Theme.Transition">
+ <activity
+ android:name=".widget.RecyclerViewUsage"
+ android:exported="true"
+ android:label="@string/recycler_view"
+ android:theme="@style/Theme.Transition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.androidx.transition.SAMPLE_CODE" />
diff --git a/samples/SupportWearDemos/src/main/AndroidManifest.xml b/samples/SupportWearDemos/src/main/AndroidManifest.xml
index 88e7bcd..5f280d8 100644
--- a/samples/SupportWearDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportWearDemos/src/main/AndroidManifest.xml
@@ -15,31 +15,54 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.support.wear" >
- <uses-feature android:name="android.hardware.type.watch" />
+ package="com.example.android.support.wear">
- <!-- Required for ambient mode support. -->
- <uses-permission android:name="android.permission.WAKE_LOCK" />
-
- <application android:icon="@drawable/app_sample_code" android:label="SupportWearDemos"
- android:theme="@android:style/Theme.DeviceDefault">
- <activity android:name=".app.SimpleWearableRecyclerViewDemo" />
- <activity android:name=".app.WearableSwitchDemo" />
- <activity android:name=".app.ConfirmationOverlayDemo" />
- <activity android:name=".app.CircularProgressLayoutDemo" />
- <activity android:name=".app.RoundedDrawableDemo" />
- <activity android:name=".app.drawers.WearableDrawersDemo" android:exported="true" />
- <activity android:name=".app.AmbientModeDemo" />
- <activity android:name=".app.AlertDialogDemo"
+ <application
+ android:icon="@drawable/app_sample_code"
+ android:label="SupportWearDemos"
+ android:theme="@android:style/Theme.DeviceDefault">
+ <activity
+ android:name=".app.SimpleWearableRecyclerViewDemo"
+ android:exported="true" />
+ <activity
+ android:name=".app.WearableSwitchDemo"
+ android:exported="true" />
+ <activity
+ android:name=".app.ConfirmationOverlayDemo"
+ android:exported="true" />
+ <activity
+ android:name=".app.CircularProgressLayoutDemo"
+ android:exported="true" />
+ <activity
+ android:name=".app.RoundedDrawableDemo"
+ android:exported="true" />
+ <activity
+ android:name=".app.drawers.WearableDrawersDemo"
+ android:exported="true" />
+ <activity
+ android:name=".app.AmbientModeDemo"
+ android:exported="true" />
+ <activity
+ android:name=".app.AlertDialogDemo"
+ android:exported="true"
android:theme="@style/Theme.AppCompat.Light" />
- <activity android:name=".app.MainDemoActivity">
+ <activity
+ android:name=".app.MainDemoActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <uses-library android:name="com.google.android.wearable" android:required="true" />
+ <uses-library
+ android:name="com.google.android.wearable"
+ android:required="true" />
</application>
+ <!-- Required for ambient mode support. -->
+ <uses-feature android:name="android.hardware.type.watch" />
+
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
</manifest>
diff --git a/security/security-crypto/api/current.ignore b/security/security-crypto/api/current.ignore
new file mode 100644
index 0000000..5cadc4b
--- /dev/null
+++ b/security/security-crypto/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+ChangedThrows: androidx.security.crypto.EncryptedFile#openFileInput():
+ Method androidx.security.crypto.EncryptedFile.openFileInput added thrown exception java.io.FileNotFoundException
diff --git a/security/security-crypto/api/current.txt b/security/security-crypto/api/current.txt
index 5ce7749..5ac2ea1 100644
--- a/security/security-crypto/api/current.txt
+++ b/security/security-crypto/api/current.txt
@@ -2,7 +2,7 @@
package androidx.security.crypto {
public final class EncryptedFile {
- method public java.io.FileInputStream openFileInput() throws java.security.GeneralSecurityException, java.io.IOException;
+ method public java.io.FileInputStream openFileInput() throws java.io.FileNotFoundException, java.security.GeneralSecurityException, java.io.IOException;
method public java.io.FileOutputStream openFileOutput() throws java.security.GeneralSecurityException, java.io.IOException;
}
diff --git a/security/security-crypto/api/public_plus_experimental_current.txt b/security/security-crypto/api/public_plus_experimental_current.txt
index 5ce7749..5ac2ea1 100644
--- a/security/security-crypto/api/public_plus_experimental_current.txt
+++ b/security/security-crypto/api/public_plus_experimental_current.txt
@@ -2,7 +2,7 @@
package androidx.security.crypto {
public final class EncryptedFile {
- method public java.io.FileInputStream openFileInput() throws java.security.GeneralSecurityException, java.io.IOException;
+ method public java.io.FileInputStream openFileInput() throws java.io.FileNotFoundException, java.security.GeneralSecurityException, java.io.IOException;
method public java.io.FileOutputStream openFileOutput() throws java.security.GeneralSecurityException, java.io.IOException;
}
diff --git a/security/security-crypto/api/restricted_current.ignore b/security/security-crypto/api/restricted_current.ignore
new file mode 100644
index 0000000..5cadc4b
--- /dev/null
+++ b/security/security-crypto/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+ChangedThrows: androidx.security.crypto.EncryptedFile#openFileInput():
+ Method androidx.security.crypto.EncryptedFile.openFileInput added thrown exception java.io.FileNotFoundException
diff --git a/security/security-crypto/api/restricted_current.txt b/security/security-crypto/api/restricted_current.txt
index 5ce7749..5ac2ea1 100644
--- a/security/security-crypto/api/restricted_current.txt
+++ b/security/security-crypto/api/restricted_current.txt
@@ -2,7 +2,7 @@
package androidx.security.crypto {
public final class EncryptedFile {
- method public java.io.FileInputStream openFileInput() throws java.security.GeneralSecurityException, java.io.IOException;
+ method public java.io.FileInputStream openFileInput() throws java.io.FileNotFoundException, java.security.GeneralSecurityException, java.io.IOException;
method public java.io.FileOutputStream openFileOutput() throws java.security.GeneralSecurityException, java.io.IOException;
}
diff --git a/security/security-crypto/src/androidTest/java/androidx/security/crypto/EncryptedFileTest.java b/security/security-crypto/src/androidTest/java/androidx/security/crypto/EncryptedFileTest.java
index b08a7bf..e2ed7a5 100644
--- a/security/security-crypto/src/androidTest/java/androidx/security/crypto/EncryptedFileTest.java
+++ b/security/security-crypto/src/androidTest/java/androidx/security/crypto/EncryptedFileTest.java
@@ -18,6 +18,9 @@
import static androidx.security.crypto.MasterKey.KEYSTORE_PATH_URI;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import static java.nio.charset.StandardCharsets.UTF_8;
import android.content.Context;
@@ -41,6 +44,7 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -102,7 +106,7 @@
EncryptedFile encryptedFile = new EncryptedFile.Builder(mContext,
new File(mContext.getFilesDir(),
- fileName), mMasterKey,
+ fileName), mMasterKey,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB)
.build();
@@ -152,7 +156,7 @@
} catch (IOException ex) {
inputFailed = true;
}
- Assert.assertTrue("File should have failed opening.", inputFailed);
+ assertTrue("File should have failed opening.", inputFailed);
EncryptedFile existingFileOutputCheck = new EncryptedFile.Builder(mContext,
new File(mContext.getFilesDir(), fileName), mMasterKey,
@@ -164,7 +168,7 @@
} catch (IOException ex) {
outputFailed = true;
}
- Assert.assertTrue("File should have failed writing.", outputFailed);
+ assertTrue("File should have failed writing.", outputFailed);
}
@@ -177,7 +181,7 @@
// Write
EncryptedFile encryptedFile = new EncryptedFile.Builder(new File(mContext.getFilesDir(),
- fileName), mContext, mMasterKey.getKeyAlias(),
+ fileName), mContext, mMasterKey.getKeyAlias(),
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB)
.build();
@@ -227,7 +231,7 @@
} catch (IOException ex) {
inputFailed = true;
}
- Assert.assertTrue("File should have failed opening.", inputFailed);
+ assertTrue("File should have failed opening.", inputFailed);
EncryptedFile existingFileOutputCheck = new EncryptedFile.Builder(
new File(mContext.getFilesDir(), fileName), mContext, mMasterKey.getKeyAlias(),
@@ -239,8 +243,28 @@
} catch (IOException ex) {
outputFailed = true;
}
- Assert.assertTrue("File should have failed writing.", outputFailed);
+ assertTrue("File should have failed writing.", outputFailed);
+ }
+ @Test
+ public void testReadNonExistingFileThrows() throws Exception {
+ final File nonExisting = new File(mContext.getFilesDir(), "non-existing.data");
+ if (nonExisting.exists()) {
+ assertTrue(nonExisting.delete());
+ }
+ EncryptedFile encryptedFile = new EncryptedFile.Builder(
+ mContext,
+ nonExisting,
+ mMasterKey,
+ EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB)
+ .build();
+
+ try {
+ FileInputStream stream = encryptedFile.openFileInput();
+ fail("Successfully opened file that should not exist");
+ } catch (FileNotFoundException fnf) {
+ // Pass
+ }
}
@Test
@@ -251,7 +275,7 @@
// Write
EncryptedFile encryptedFile = new EncryptedFile.Builder(mContext,
new File(mContext.getFilesDir(),
- fileName), mMasterKey,
+ fileName), mMasterKey,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB)
.setKeysetAlias("CustomKEYALIAS")
.setKeysetPrefName("CUSTOMPREFNAME")
@@ -295,7 +319,7 @@
SharedPreferences sharedPreferences = mContext.getSharedPreferences("CUSTOMPREFNAME",
Context.MODE_PRIVATE);
boolean containsKeyset = sharedPreferences.contains("CustomKEYALIAS");
- Assert.assertTrue("Keyset should have existed.", containsKeyset);
+ assertTrue("Keyset should have existed.", containsKeyset);
}
@SuppressWarnings("deprecation")
diff --git a/security/security-crypto/src/main/java/androidx/security/crypto/EncryptedFile.java b/security/security-crypto/src/main/java/androidx/security/crypto/EncryptedFile.java
index fce4770..6b0bd91 100644
--- a/security/security-crypto/src/main/java/androidx/security/crypto/EncryptedFile.java
+++ b/security/security-crypto/src/main/java/androidx/security/crypto/EncryptedFile.java
@@ -35,6 +35,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -238,13 +239,14 @@
*
* @return The input stream to read previously encrypted data.
* @throws GeneralSecurityException when a bad master key or keyset has been used
- * @throws IOException when the file was not found
+ * @throws FileNotFoundException when the file was not found
+ * @throws IOException when other I/O errors occur
*/
@NonNull
public FileInputStream openFileInput()
- throws GeneralSecurityException, IOException {
+ throws GeneralSecurityException, IOException, FileNotFoundException {
if (!mFile.exists()) {
- throw new IOException("file doesn't exist: " + mFile.getName());
+ throw new FileNotFoundException("file doesn't exist: " + mFile.getName());
}
FileInputStream fileInputStream = new FileInputStream(mFile);
InputStream decryptingStream = mStreamingAead.newDecryptingStream(fileInputStream,
diff --git a/security/security-identity-credential/build.gradle b/security/security-identity-credential/build.gradle
index 4c3cd86..fcae685b 100644
--- a/security/security-identity-credential/build.gradle
+++ b/security/security-identity-credential/build.gradle
@@ -31,6 +31,7 @@
implementation(project(":biometric:biometric"))
implementation("org.bouncycastle:bcprov-jdk15on:1.65")
implementation("org.bouncycastle:bcpkix-jdk15on:1.56")
+ implementation project(path: ':annotation:annotation')
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
diff --git a/security/security-identity-credential/src/androidTest/java/androidx/security/identity/DynamicAuthTest.java b/security/security-identity-credential/src/androidTest/java/androidx/security/identity/DynamicAuthTest.java
index 85a738c..60c8f80d 100644
--- a/security/security-identity-credential/src/androidTest/java/androidx/security/identity/DynamicAuthTest.java
+++ b/security/security-identity-credential/src/androidTest/java/androidx/security/identity/DynamicAuthTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -137,15 +136,13 @@
cert.getNotBefore().getTime() + kMilliSecsInOneYear - cert.getNotAfter().getTime();
assertTrue(-allowDriftMilliSecs <= diffMilliSecs && diffMilliSecs <= allowDriftMilliSecs);
- // The extension is expected only if - and only if - the underlying hardware
+ // The extension must be there if the underlying hardware says it
// supports updating the credential.
//
- byte[] icExtension = cert.getExtensionValue("1.3.6.1.4.1.11129.2.1.26");
if (store.getCapabilities().isUpdateSupported()) {
+ byte[] icExtension = cert.getExtensionValue("1.3.6.1.4.1.11129.2.1.26");
assertNotNull(icExtension);
assertArrayEquals(proofOfProvisioningSha256, Util.getPopSha256FromAuthKeyCert(cert));
- } else {
- assertNull(icExtension);
}
// ... and we're done. Clean up after ourselves.
diff --git a/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredential.java b/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredential.java
index 3255079..bb1aa08 100644
--- a/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredential.java
+++ b/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredential.java
@@ -16,8 +16,10 @@
package androidx.security.identity;
+import android.icu.util.Calendar;
import android.os.Build;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
@@ -31,6 +33,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
+import java.time.Instant;
import java.util.Collection;
import javax.crypto.BadPaddingException;
@@ -269,4 +272,106 @@
int[] getAuthenticationDataUsageCount() {
return mCredential.getAuthenticationDataUsageCount();
}
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ private static class ApiImplS {
+ @DoNotInline
+ static void callSetAllowUsingExpiredKeys(
+ @NonNull android.security.identity.IdentityCredential credential,
+ boolean allowUsingExpiredKeys) {
+ credential.setAllowUsingExpiredKeys(allowUsingExpiredKeys);
+ }
+
+ @DoNotInline
+ static void callStoreStaticAuthenticationData(
+ @NonNull android.security.identity.IdentityCredential credential,
+ @NonNull X509Certificate authenticationKey,
+ @NonNull Instant expirationDate,
+ @NonNull byte[] staticAuthData)
+ throws android.security.identity.UnknownAuthenticationKeyException {
+ credential.storeStaticAuthenticationData(authenticationKey,
+ expirationDate,
+ staticAuthData);
+ }
+
+ @DoNotInline
+ static @NonNull byte[] callProveOwnership(
+ @NonNull android.security.identity.IdentityCredential credential,
+ @NonNull byte[] challenge) {
+ return credential.proveOwnership(challenge);
+ }
+
+ @DoNotInline
+ static @NonNull byte[] callDelete(
+ @NonNull android.security.identity.IdentityCredential credential,
+ @NonNull byte[] challenge) {
+ return credential.delete(challenge);
+ }
+
+ @DoNotInline
+ static @NonNull byte[] callUpdate(
+ @NonNull android.security.identity.IdentityCredential credential,
+ @NonNull android.security.identity.PersonalizationData personalizationData) {
+ return credential.update(personalizationData);
+ }
+ }
+
+ @Override
+ public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ ApiImplS.callSetAllowUsingExpiredKeys(mCredential, allowUsingExpiredKeys);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public void storeStaticAuthenticationData(
+ @NonNull X509Certificate authenticationKey,
+ @NonNull Calendar expirationDate,
+ @NonNull byte[] staticAuthData)
+ throws UnknownAuthenticationKeyException {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ try {
+ Instant expirationDateAsInstant =
+ Instant.ofEpochMilli(expirationDate.getTimeInMillis());
+ ApiImplS.callStoreStaticAuthenticationData(mCredential,
+ authenticationKey,
+ expirationDateAsInstant,
+ staticAuthData);
+ } catch (android.security.identity.UnknownAuthenticationKeyException e) {
+ throw new UnknownAuthenticationKeyException(e.getMessage(), e);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ return ApiImplS.callProveOwnership(mCredential, challenge);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public @NonNull byte[] delete(@NonNull byte[] challenge) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ return ApiImplS.callDelete(mCredential, challenge);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ return ApiImplS.callUpdate(mCredential,
+ HardwareWritableIdentityCredential.convertPDFromJetpack(personalizationData));
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredentialStore.java b/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredentialStore.java
index 14337da..4446489 100644
--- a/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredentialStore.java
+++ b/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareIdentityCredentialStore.java
@@ -17,6 +17,7 @@
package androidx.security.identity;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.NonNull;
@@ -31,14 +32,17 @@
class HardwareIdentityCredentialStore extends IdentityCredentialStore {
private static final String TAG = "HardwareIdentityCredentialStore";
+ private final Context mContext;
private android.security.identity.IdentityCredentialStore mStore = null;
private boolean mIsDirectAccess = false;
private HardwareIdentityCredentialStore(
@NonNull android.security.identity.IdentityCredentialStore store,
+ @NonNull Context context,
boolean isDirectAccess) {
mStore = store;
+ mContext = context;
mIsDirectAccess = isDirectAccess;
}
@@ -46,7 +50,7 @@
android.security.identity.IdentityCredentialStore store =
android.security.identity.IdentityCredentialStore.getInstance(context);
if (store != null) {
- return new HardwareIdentityCredentialStore(store, false);
+ return new HardwareIdentityCredentialStore(store, context, false);
}
return null;
}
@@ -65,7 +69,7 @@
android.security.identity.IdentityCredentialStore store =
android.security.identity.IdentityCredentialStore.getDirectAccessInstance(context);
if (store != null) {
- return new HardwareIdentityCredentialStore(store, true);
+ return new HardwareIdentityCredentialStore(store, context, true);
}
return null;
}
@@ -144,19 +148,27 @@
public @NonNull
IdentityCredentialStoreCapabilities getCapabilities() {
LinkedHashSet<String> supportedDocTypesSet =
- new LinkedHashSet<String>(Arrays.asList(mStore.getSupportedDocTypes()));
+ new LinkedHashSet<>(Arrays.asList(mStore.getSupportedDocTypes()));
if (mCapabilities == null) {
- // TODO: update for Android 12 platform APIs when available.
- mCapabilities = new SimpleIdentityCredentialStoreCapabilities(
- mIsDirectAccess,
- IdentityCredentialStoreCapabilities.FEATURE_VERSION_202009,
- true,
- supportedDocTypesSet,
- false,
- false,
- false,
- false);
+ PackageManager pm = mContext.getPackageManager();
+ String featureName = PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE;
+ if (mIsDirectAccess) {
+ featureName = PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS;
+ }
+
+ if (pm.hasSystemFeature(featureName,
+ IdentityCredentialStoreCapabilities.FEATURE_VERSION_202101)) {
+ mCapabilities = SimpleIdentityCredentialStoreCapabilities.getFeatureVersion202101(
+ mIsDirectAccess,
+ true,
+ supportedDocTypesSet);
+ } else {
+ mCapabilities = SimpleIdentityCredentialStoreCapabilities.getFeatureVersion202009(
+ mIsDirectAccess,
+ true,
+ supportedDocTypesSet);
+ }
}
return mCapabilities;
}
diff --git a/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareWritableIdentityCredential.java b/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareWritableIdentityCredential.java
index ab359458..686c500 100644
--- a/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareWritableIdentityCredential.java
+++ b/security/security-identity-credential/src/main/java/androidx/security/identity/HardwareWritableIdentityCredential.java
@@ -43,9 +43,8 @@
return mWritableCredential.getCredentialKeyCertificateChain(challenge);
}
- @Override
- @NonNull
- public byte[] personalize(@NonNull PersonalizationData personalizationData) {
+ static @NonNull android.security.identity.PersonalizationData convertPDFromJetpack(
+ @NonNull PersonalizationData personalizationData) {
android.security.identity.PersonalizationData.Builder builder =
new android.security.identity.PersonalizationData.Builder();
@@ -75,6 +74,12 @@
builder.addAccessControlProfile(profileBuilder.build());
}
- return mWritableCredential.personalize(builder.build());
+ return builder.build();
+ }
+
+ @Override
+ @NonNull
+ public byte[] personalize(@NonNull PersonalizationData personalizationData) {
+ return mWritableCredential.personalize(convertPDFromJetpack(personalizationData));
}
}
diff --git a/security/security-identity-credential/src/main/java/androidx/security/identity/SimpleIdentityCredentialStoreCapabilities.java b/security/security-identity-credential/src/main/java/androidx/security/identity/SimpleIdentityCredentialStoreCapabilities.java
index 5393bf8..3c35587 100644
--- a/security/security-identity-credential/src/main/java/androidx/security/identity/SimpleIdentityCredentialStoreCapabilities.java
+++ b/security/security-identity-credential/src/main/java/androidx/security/identity/SimpleIdentityCredentialStoreCapabilities.java
@@ -50,6 +50,36 @@
isStaticAuthenticationDataExpirationDateSupported;
}
+ static SimpleIdentityCredentialStoreCapabilities getFeatureVersion202009(
+ boolean isDirectAccess,
+ boolean isHardwareBacked,
+ Set<String> supportedDocTypesSet) {
+ return new SimpleIdentityCredentialStoreCapabilities(
+ isDirectAccess,
+ IdentityCredentialStoreCapabilities.FEATURE_VERSION_202009,
+ isHardwareBacked,
+ supportedDocTypesSet,
+ false,
+ false,
+ false,
+ false);
+ }
+
+ static SimpleIdentityCredentialStoreCapabilities getFeatureVersion202101(
+ boolean isDirectAccess,
+ boolean isHardwareBacked,
+ Set<String> supportedDocTypesSet) {
+ return new SimpleIdentityCredentialStoreCapabilities(
+ isDirectAccess,
+ IdentityCredentialStoreCapabilities.FEATURE_VERSION_202101,
+ isHardwareBacked,
+ supportedDocTypesSet,
+ true,
+ true,
+ true,
+ true);
+ }
+
@Override
public boolean isDirectAccess() {
return mIsDirectAccess;
diff --git a/security/security-identity-credential/src/main/java/androidx/security/identity/SoftwareIdentityCredentialStore.java b/security/security-identity-credential/src/main/java/androidx/security/identity/SoftwareIdentityCredentialStore.java
index 9aff8dc..d5bac8d 100644
--- a/security/security-identity-credential/src/main/java/androidx/security/identity/SoftwareIdentityCredentialStore.java
+++ b/security/security-identity-credential/src/main/java/androidx/security/identity/SoftwareIdentityCredentialStore.java
@@ -69,15 +69,11 @@
public @NonNull
IdentityCredentialStoreCapabilities getCapabilities() {
if (mCapabilities == null) {
- mCapabilities = new SimpleIdentityCredentialStoreCapabilities(
+ LinkedHashSet<String> supportedDocTypesSet = new LinkedHashSet<>();
+ mCapabilities = SimpleIdentityCredentialStoreCapabilities.getFeatureVersion202101(
false,
- IdentityCredentialStoreCapabilities.FEATURE_VERSION_202101,
false,
- new LinkedHashSet<String>(),
- true,
- true,
- true,
- true);
+ supportedDocTypesSet);
}
return mCapabilities;
}
diff --git a/settings.gradle b/settings.gradle
index d37e963..343f645 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -204,7 +204,12 @@
includeProject(":appcompat:integration-tests:receive-content-testapp", "appcompat/integration-tests/receive-content-testapp", [BuildType.MAIN])
includeProject(":appsearch:appsearch", "appsearch/appsearch", [BuildType.MAIN])
includeProject(":appsearch:appsearch-compiler", "appsearch/compiler", [BuildType.MAIN])
+includeProject(":appsearch:appsearch-debug-view", "appsearch/debug-view", [BuildType.MAIN])
+includeProject(":appsearch:appsearch-debug-view:samples", "appsearch/debug-view/samples",
+ [BuildType.MAIN])
+includeProject(":appsearch:appsearch-ktx", "appsearch/appsearch-ktx", [BuildType.MAIN])
includeProject(":appsearch:appsearch-local-storage", "appsearch/local-storage", [BuildType.MAIN])
+includeProject(":appsearch:appsearch-platform-storage", "appsearch/platform-storage", [BuildType.MAIN])
includeProject(":arch:core:core-common", "arch/core/core-common", [BuildType.MAIN])
includeProject(":arch:core:core-runtime", "arch/core/core-runtime", [BuildType.MAIN])
includeProject(":arch:core:core-testing", "arch/core/core-testing", [BuildType.MAIN])
@@ -390,6 +395,9 @@
includeProject(":core:core-appdigest", "core/core-appdigest", [BuildType.MAIN])
includeProject(":core:core-google-shortcuts", "core/core-google-shortcuts", [BuildType.MAIN])
includeProject(":core:core-ktx", "core/core-ktx", [BuildType.MAIN])
+includeProject(":core:core-remoteviews", "core/core-remoteviews", [BuildType.MAIN])
+includeProject(":core:core-splashscreen", "core/core-splashscreen", [BuildType.MAIN])
+includeProject(":core:core-splashscreen:core-splashscreen-samples", "core/core-splashscreen/samples", [BuildType.MAIN])
includeProject(":core:core-role", "core/core-role", [BuildType.MAIN])
includeProject(":cursoradapter:cursoradapter", "cursoradapter/cursoradapter", [BuildType.MAIN])
includeProject(":customview:customview", "customview/customview", [BuildType.MAIN])
@@ -585,7 +593,7 @@
includeProject(":sharetarget:sharetarget", "sharetarget/sharetarget", [BuildType.MAIN])
includeProject(":slice:slice-benchmark", "slice/slice-benchmark", [BuildType.MAIN])
includeProject(":slice:slice-builders", "slice/slice-builders", [BuildType.MAIN])
-includeProject(":slice:slice-builders-ktx", "slice/slice-builders/ktx", [BuildType.MAIN])
+includeProject(":slice:slice-builders-ktx", "slice/slice-builders-ktx", [BuildType.MAIN])
includeProject(":slice:slice-core", "slice/slice-core", [BuildType.MAIN])
includeProject(":slice:slice-remotecallback", "slice/slice-remotecallback", [BuildType.MAIN])
includeProject(":slice:slice-test", "slice/slice-test", [BuildType.MAIN])
@@ -725,7 +733,7 @@
includeProject(":internal-testutils-appcompat", "testutils/testutils-appcompat", [BuildType.MAIN])
includeProject(":internal-testutils-espresso", "testutils/testutils-espresso", [BuildType.MAIN])
includeProject(":internal-testutils-truth", "testutils/testutils-truth", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":internal-testutils-ktx", "testutils/testutils-ktx", [BuildType.MAIN, BuildType.COMPOSE])
+includeProject(":internal-testutils-ktx", "testutils/testutils-ktx")
includeProject(":internal-testutils-macrobenchmark", "testutils/testutils-macrobenchmark", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":internal-testutils-navigation", "testutils/testutils-navigation", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN])
includeProject(":internal-testutils-paging", "testutils/testutils-paging", [BuildType.MAIN, BuildType.COMPOSE])
diff --git a/sharetarget/integration-tests/testapp/src/main/AndroidManifest.xml b/sharetarget/integration-tests/testapp/src/main/AndroidManifest.xml
index c2d35a1..46fbee3 100644
--- a/sharetarget/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/sharetarget/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -16,43 +16,50 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" package="androidx.sharetarget.testapp">
+ xmlns:tools="http://schemas.android.com/tools"
+ package="androidx.sharetarget.testapp">
<application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning">
- <activity android:name=".MainActivity">
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme"
+ tools:ignore="GoogleAppIndexingWarning">
+ <activity
+ android:name=".MainActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
- <meta-data android:name="android.app.shortcuts"
- android:resource="@xml/shortcuts" />
+ <meta-data
+ android:name="android.app.shortcuts"
+ android:resource="@xml/shortcuts" />
</activity>
<activity
- android:name=".TextConsumerActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme">
+ android:name=".TextConsumerActivity"
+ android:exported="true"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data
- android:name="android.service.chooser.chooser_target_service"
- android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
+ android:name="android.service.chooser.chooser_target_service"
+ android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
</activity>
<activity
- android:name=".OtherTextConsumerActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme">
+ android:name=".OtherTextConsumerActivity"
+ android:exported="true"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/sharetarget/sharetarget/src/androidTest/AndroidManifest.xml b/sharetarget/sharetarget/src/androidTest/AndroidManifest.xml
index 6aa139e..01e95ab 100644
--- a/sharetarget/sharetarget/src/androidTest/AndroidManifest.xml
+++ b/sharetarget/sharetarget/src/androidTest/AndroidManifest.xml
@@ -19,7 +19,7 @@
<application>
<!-- Dummy main activity to provide a "android.app.shortcuts" meta-data entry -->
- <activity android:name="android.app.Activity">
+ <activity android:name="android.app.Activity" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/slice/slice-builders/ktx/OWNERS b/slice/slice-builders-ktx/OWNERS
similarity index 100%
rename from slice/slice-builders/ktx/OWNERS
rename to slice/slice-builders-ktx/OWNERS
diff --git a/slice/slice-builders/ktx/api/current.txt b/slice/slice-builders-ktx/api/current.txt
similarity index 100%
rename from slice/slice-builders/ktx/api/current.txt
rename to slice/slice-builders-ktx/api/current.txt
diff --git a/slice/slice-builders/ktx/api/public_plus_experimental_current.txt b/slice/slice-builders-ktx/api/public_plus_experimental_current.txt
similarity index 100%
rename from slice/slice-builders/ktx/api/public_plus_experimental_current.txt
rename to slice/slice-builders-ktx/api/public_plus_experimental_current.txt
diff --git a/slice/slice-builders/ktx/api/res-current.txt b/slice/slice-builders-ktx/api/res-current.txt
similarity index 100%
rename from slice/slice-builders/ktx/api/res-current.txt
rename to slice/slice-builders-ktx/api/res-current.txt
diff --git a/slice/slice-builders/ktx/api/restricted_current.txt b/slice/slice-builders-ktx/api/restricted_current.txt
similarity index 100%
rename from slice/slice-builders/ktx/api/restricted_current.txt
rename to slice/slice-builders-ktx/api/restricted_current.txt
diff --git a/slice/slice-builders/ktx/build.gradle b/slice/slice-builders-ktx/build.gradle
similarity index 100%
rename from slice/slice-builders/ktx/build.gradle
rename to slice/slice-builders-ktx/build.gradle
diff --git a/slice/slice-builders/ktx/src/androidTest/AndroidManifest.xml b/slice/slice-builders-ktx/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from slice/slice-builders/ktx/src/androidTest/AndroidManifest.xml
rename to slice/slice-builders-ktx/src/androidTest/AndroidManifest.xml
diff --git a/slice/slice-builders/ktx/src/androidTest/java/androidx/slice/builders/SliceBuildersKtxTest.kt b/slice/slice-builders-ktx/src/androidTest/java/androidx/slice/builders/SliceBuildersKtxTest.kt
similarity index 100%
rename from slice/slice-builders/ktx/src/androidTest/java/androidx/slice/builders/SliceBuildersKtxTest.kt
rename to slice/slice-builders-ktx/src/androidTest/java/androidx/slice/builders/SliceBuildersKtxTest.kt
diff --git a/slice/slice-builders/ktx/src/androidTest/java/androidx/slice/builders/TestActivity.java b/slice/slice-builders-ktx/src/androidTest/java/androidx/slice/builders/TestActivity.java
similarity index 100%
rename from slice/slice-builders/ktx/src/androidTest/java/androidx/slice/builders/TestActivity.java
rename to slice/slice-builders-ktx/src/androidTest/java/androidx/slice/builders/TestActivity.java
diff --git a/slice/slice-builders/ktx/src/androidTest/res/drawable/ic_all_out_black_24dp.xml b/slice/slice-builders-ktx/src/androidTest/res/drawable/ic_all_out_black_24dp.xml
similarity index 100%
rename from slice/slice-builders/ktx/src/androidTest/res/drawable/ic_all_out_black_24dp.xml
rename to slice/slice-builders-ktx/src/androidTest/res/drawable/ic_all_out_black_24dp.xml
diff --git a/slice/slice-builders/ktx/src/androidTest/res/drawable/ic_android_black_24dp.xml b/slice/slice-builders-ktx/src/androidTest/res/drawable/ic_android_black_24dp.xml
similarity index 100%
rename from slice/slice-builders/ktx/src/androidTest/res/drawable/ic_android_black_24dp.xml
rename to slice/slice-builders-ktx/src/androidTest/res/drawable/ic_android_black_24dp.xml
diff --git a/slice/slice-builders/ktx/src/androidTest/res/drawable/ic_attach_money_black_24dp.xml b/slice/slice-builders-ktx/src/androidTest/res/drawable/ic_attach_money_black_24dp.xml
similarity index 100%
rename from slice/slice-builders/ktx/src/androidTest/res/drawable/ic_attach_money_black_24dp.xml
rename to slice/slice-builders-ktx/src/androidTest/res/drawable/ic_attach_money_black_24dp.xml
diff --git a/slice/slice-builders/ktx/src/androidTest/res/layout/activity_test.xml b/slice/slice-builders-ktx/src/androidTest/res/layout/activity_test.xml
similarity index 100%
rename from slice/slice-builders/ktx/src/androidTest/res/layout/activity_test.xml
rename to slice/slice-builders-ktx/src/androidTest/res/layout/activity_test.xml
diff --git a/slice/slice-builders/ktx/src/main/AndroidManifest.xml b/slice/slice-builders-ktx/src/main/AndroidManifest.xml
similarity index 100%
rename from slice/slice-builders/ktx/src/main/AndroidManifest.xml
rename to slice/slice-builders-ktx/src/main/AndroidManifest.xml
diff --git a/slice/slice-builders/ktx/src/main/java/androidx/slice/builders/GridRowBuilder.kt b/slice/slice-builders-ktx/src/main/java/androidx/slice/builders/GridRowBuilder.kt
similarity index 100%
rename from slice/slice-builders/ktx/src/main/java/androidx/slice/builders/GridRowBuilder.kt
rename to slice/slice-builders-ktx/src/main/java/androidx/slice/builders/GridRowBuilder.kt
diff --git a/slice/slice-builders/ktx/src/main/java/androidx/slice/builders/ListBuilder.kt b/slice/slice-builders-ktx/src/main/java/androidx/slice/builders/ListBuilder.kt
similarity index 100%
rename from slice/slice-builders/ktx/src/main/java/androidx/slice/builders/ListBuilder.kt
rename to slice/slice-builders-ktx/src/main/java/androidx/slice/builders/ListBuilder.kt
diff --git a/slice/slice-view/src/androidTest/AndroidManifest.xml b/slice/slice-view/src/androidTest/AndroidManifest.xml
index 27a0d6b..213c0fe 100644
--- a/slice/slice-view/src/androidTest/AndroidManifest.xml
+++ b/slice/slice-view/src/androidTest/AndroidManifest.xml
@@ -14,30 +14,33 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.slice.view.test">
+ package="androidx.slice.view.test">
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
- <application
- android:label="Slice Render Test">
- <provider android:name="androidx.slice.SliceViewManagerTest$TestSliceProvider"
- android:authorities="androidx.slice.view.test"
- android:exported="true">
- <intent-filter>
- <action android:name="androidx.slice.action.TEST" />
- <category android:name="android.app.slice.category.SLICE" />
- </intent-filter>
- </provider>
-
- <activity android:name="androidx.slice.render.SliceRenderActivity"
+ <application android:label="Slice Render Test">
+ <activity
+ android:name="androidx.slice.render.SliceRenderActivity"
+ android:exported="false"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
- <meta-data android:name="android.metadata.SLICE_URI"
- android:value="content://androidx.slice.view.test/render" />
+ <meta-data
+ android:name="android.metadata.SLICE_URI"
+ android:value="content://androidx.slice.view.test/render" />
</activity>
+
+ <provider
+ android:name="androidx.slice.SliceViewManagerTest$TestSliceProvider"
+ android:authorities="androidx.slice.view.test"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="androidx.slice.action.TEST" />
+ <category android:name="android.app.slice.category.SLICE" />
+ </intent-filter>
+ </provider>
</application>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>
diff --git a/slidingpanelayout/slidingpanelayout/build.gradle b/slidingpanelayout/slidingpanelayout/build.gradle
index 716eaf0..9071872 100644
--- a/slidingpanelayout/slidingpanelayout/build.gradle
+++ b/slidingpanelayout/slidingpanelayout/build.gradle
@@ -11,7 +11,7 @@
api("androidx.annotation:annotation:1.1.0")
implementation("androidx.core:core:1.1.0")
api("androidx.customview:customview:1.1.0")
- implementation(project(":window:window"))
+ implementation("androidx.window:window:1.0.0-alpha10")
implementation ("androidx.transition:transition:1.4.1")
androidTestImplementation(libs.testExtJunit)
@@ -20,7 +20,7 @@
androidTestImplementation(libs.kotlinStdlib)
androidTestImplementation(libs.truth)
androidTestImplementation(project(':internal-testutils-runtime'))
- androidTestImplementation(project(":window:window-testing"))
+ androidTestImplementation("androidx.window:window-testing:1.0.0-alpha10")
}
androidx {
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/AndroidManifest.xml b/slidingpanelayout/slidingpanelayout/src/androidTest/AndroidManifest.xml
index 83e141c..ab6ef73 100644
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/AndroidManifest.xml
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/AndroidManifest.xml
@@ -16,11 +16,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.slidingpanelayout">
+
<application android:supportsRtl="true">
- <activity android:name="androidx.slidingpanelayout.widget.helpers.TestActivity">
+ <activity
+ android:name="androidx.slidingpanelayout.widget.helpers.TestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
diff --git a/startup/integration-tests/test-app/src/main/AndroidManifest.xml b/startup/integration-tests/test-app/src/main/AndroidManifest.xml
index 9836d05..09bd2ba 100644
--- a/startup/integration-tests/test-app/src/main/AndroidManifest.xml
+++ b/startup/integration-tests/test-app/src/main/AndroidManifest.xml
@@ -22,7 +22,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat">
- <activity android:name=".MainActivity">
+ <activity
+ android:name=".MainActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt b/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
index 423701f..f484f58 100644
--- a/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
+++ b/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
@@ -45,6 +45,7 @@
startActivityAndWait(intent)
}
+@RequiresApi(21)
fun createStartupCompilationParams(
startupModes: List<StartupMode> = listOf(
StartupMode.HOT,
@@ -68,6 +69,7 @@
}
}
+@RequiresApi(21)
fun createCompilationParams(
compilationModes: List<CompilationMode> = listOf(
CompilationMode.None,
diff --git a/textclassifier/integration-tests/testapp/src/main/AndroidManifest.xml b/textclassifier/integration-tests/testapp/src/main/AndroidManifest.xml
index 1fb6f36..3391e59 100644
--- a/textclassifier/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/textclassifier/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:supportsRtl="true"
android:label="@string/app_name"
android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
+ <activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/textclassifier/textclassifier/build.gradle b/textclassifier/textclassifier/build.gradle
index 312925a..6518c20 100644
--- a/textclassifier/textclassifier/build.gradle
+++ b/textclassifier/textclassifier/build.gradle
@@ -20,6 +20,13 @@
androidTestImplementation(libs.espressoCore, excludes.espresso)
androidTestImplementation(libs.mockitoCore, excludes.bytebuddy)
androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy)
+ androidTestImplementation(libs.multidex)
+}
+
+android {
+ defaultConfig {
+ multiDexEnabled = true
+ }
}
androidx {
diff --git a/textclassifier/textclassifier/src/androidTest/AndroidManifest.xml b/textclassifier/textclassifier/src/androidTest/AndroidManifest.xml
index 9981b00..30371d7 100644
--- a/textclassifier/textclassifier/src/androidTest/AndroidManifest.xml
+++ b/textclassifier/textclassifier/src/androidTest/AndroidManifest.xml
@@ -19,7 +19,8 @@
<application
android:supportsRtl="true"
- android:theme="@style/Theme.AppCompat">
+ android:theme="@style/Theme.AppCompat"
+ android:name="androidx.multidex.MultiDexApplication">
<activity
android:name="androidx.textclassifier.widget.FloatingToolbarActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
diff --git a/textclassifier/textclassifier/src/main/res/values-te/strings.xml b/textclassifier/textclassifier/src/main/res/values-te/strings.xml
index 9e55cfd..a96f703 100644
--- a/textclassifier/textclassifier/src/main/res/values-te/strings.xml
+++ b/textclassifier/textclassifier/src/main/res/values-te/strings.xml
@@ -22,8 +22,8 @@
<string name="dial_desc" msgid="1195407206406821463">"ఎంచుకున్న ఫోన్ నంబర్కు కాల్ చేస్తుంది"</string>
<string name="browse" msgid="4753676368851695348">"తెరువు"</string>
<string name="browse_desc" msgid="728882176434276995">"ఎంచుకున్న URLని తెరుస్తుంది"</string>
- <string name="sms" msgid="2214738262605167054">"సందేశం పంపు"</string>
- <string name="sms_desc" msgid="7733202356868441148">"ఎంచుకున్న ఫోన్ నంబర్కి సందేశం పంపుతుంది"</string>
+ <string name="sms" msgid="2214738262605167054">"మెసేజ్ పంపు"</string>
+ <string name="sms_desc" msgid="7733202356868441148">"ఎంచుకున్న ఫోన్ నంబర్కి మెసేజ్ పంపుతుంది"</string>
<string name="add_contact" msgid="386263007484061034">"జోడించు"</string>
<string name="add_contact_desc" msgid="1739272501140197425">"పరిచయాలకు జోడిస్తుంది"</string>
<string name="floating_toolbar_open_overflow_description" msgid="6778458701858708647">"మరిన్ని ఆప్షన్లు"</string>
diff --git a/transition/transition/src/main/java/androidx/transition/ImageViewUtils.java b/transition/transition/src/main/java/androidx/transition/ImageViewUtils.java
index 0fd145f..eddc36b 100644
--- a/transition/transition/src/main/java/androidx/transition/ImageViewUtils.java
+++ b/transition/transition/src/main/java/androidx/transition/ImageViewUtils.java
@@ -96,6 +96,7 @@
}
}
+ @SuppressLint("SoonBlockedPrivateApi") // only called for API <21
private static void fetchDrawMatrixField() {
if (!sDrawMatrixFieldFetched) {
try {
diff --git a/transition/transition/src/main/java/androidx/transition/ViewUtilsBase.java b/transition/transition/src/main/java/androidx/transition/ViewUtilsBase.java
index 4ff8f40..b4722b4 100644
--- a/transition/transition/src/main/java/androidx/transition/ViewUtilsBase.java
+++ b/transition/transition/src/main/java/androidx/transition/ViewUtilsBase.java
@@ -151,6 +151,7 @@
}
}
+ @SuppressLint("SoonBlockedPrivateApi") // Only called on API <23
public void setTransitionVisibility(@NonNull View view, int visibility) {
if (!sViewFlagsFieldFetched) {
try {
diff --git a/vectordrawable/integration-tests/testapp/src/main/AndroidManifest.xml b/vectordrawable/integration-tests/testapp/src/main/AndroidManifest.xml
index 6938e83..5b5a275 100644
--- a/vectordrawable/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/vectordrawable/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -15,45 +15,57 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.support.vectordrawable" >
+ package="com.example.android.support.vectordrawable">
+
<application
android:icon="@drawable/app_sample_code"
android:label="SupportVectorDrawableDemos"
android:theme="@style/Theme.AppCompat">
- <activity android:name="com.example.android.support.vectordrawable.app.SupportVectorDrawableDemos">
+ <activity
+ android:name="com.example.android.support.vectordrawable.app.SupportVectorDrawableDemos"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="com.example.android.support.vectordrawable.app.SimpleAnimatedVectorDrawable"
- android:label="SimpleAnimatedVectorDrawable">
+ <activity
+ android:name="com.example.android.support.vectordrawable.app.SimpleAnimatedVectorDrawable"
+ android:exported="true"
+ android:label="SimpleAnimatedVectorDrawable">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name="com.example.android.support.vectordrawable.app.SimpleStaticVectorDrawable"
- android:label="SimpleVectorDrawable">
+ <activity
+ android:name="com.example.android.support.vectordrawable.app.SimpleStaticVectorDrawable"
+ android:label="SimpleVectorDrawable"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name="com.example.android.support.vectordrawable.app.AVDCListenerDemo"
- android:label="AnimatedVectorDrawableCompatListener"
- android:theme="@style/Theme.AppCompat.Light">
+ <activity
+ android:name="com.example.android.support.vectordrawable.app.AVDCListenerDemo"
+ android:exported="true"
+ android:label="AnimatedVectorDrawableCompatListener"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
- <activity android:name="com.example.android.support.vectordrawable.app.SeekableDemo"
+ <activity
+ android:name="com.example.android.support.vectordrawable.app.SeekableDemo"
+ android:exported="true"
android:label="SeekableAnimatedVectorDrawable"
android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
diff --git a/viewpager/viewpager/build.gradle b/viewpager/viewpager/build.gradle
index 0d2e668..40c8c5a 100644
--- a/viewpager/viewpager/build.gradle
+++ b/viewpager/viewpager/build.gradle
@@ -8,7 +8,7 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
- implementation("androidx.core:core:1.3.0-beta01")
+ implementation project(":core:core")
api("androidx.customview:customview:1.0.0")
androidTestImplementation(libs.testExtJunit)
@@ -18,6 +18,7 @@
androidTestImplementation(libs.espressoCore, excludes.espresso)
androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation project(':internal-testutils-espresso')
}
androidx {
diff --git a/viewpager/viewpager/lint-baseline.xml b/viewpager/viewpager/lint-baseline.xml
index 25cc6cd..907f9d0 100644
--- a/viewpager/viewpager/lint-baseline.xml
+++ b/viewpager/viewpager/lint-baseline.xml
@@ -8,7 +8,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="789"
+ line="822"
column="52"/>
</issue>
@@ -52,7 +52,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="711"
+ line="744"
column="41"/>
</issue>
@@ -63,7 +63,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="912"
+ line="945"
column="38"/>
</issue>
@@ -74,7 +74,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="1390"
+ line="1423"
column="35"/>
</issue>
@@ -85,7 +85,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="1431"
+ line="1464"
column="12"/>
</issue>
@@ -96,7 +96,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="1442"
+ line="1475"
column="40"/>
</issue>
@@ -107,7 +107,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="1462"
+ line="1495"
column="25"/>
</issue>
@@ -118,7 +118,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="1462"
+ line="1495"
column="48"/>
</issue>
@@ -129,7 +129,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="1486"
+ line="1519"
column="28"/>
</issue>
@@ -140,7 +140,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2028"
+ line="2061"
column="42"/>
</issue>
@@ -151,7 +151,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2169"
+ line="2214"
column="33"/>
</issue>
@@ -162,7 +162,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2429"
+ line="2507"
column="22"/>
</issue>
@@ -173,7 +173,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2471"
+ line="2549"
column="27"/>
</issue>
@@ -184,7 +184,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2713"
+ line="2791"
column="33"/>
</issue>
@@ -195,7 +195,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2737"
+ line="2815"
column="37"/>
</issue>
@@ -206,7 +206,7 @@
errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2899"
+ line="2977"
column="31"/>
</issue>
@@ -217,7 +217,7 @@
errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2941"
+ line="3019"
column="31"/>
</issue>
@@ -228,7 +228,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2961"
+ line="3039"
column="13"/>
</issue>
@@ -239,7 +239,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="2990"
+ line="3068"
column="55"/>
</issue>
@@ -250,7 +250,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3013"
+ line="3091"
column="15"/>
</issue>
@@ -261,7 +261,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3018"
+ line="3096"
column="15"/>
</issue>
@@ -272,7 +272,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3018"
+ line="3096"
column="59"/>
</issue>
@@ -283,7 +283,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3023"
+ line="3101"
column="41"/>
</issue>
@@ -294,7 +294,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3028"
+ line="3106"
column="12"/>
</issue>
@@ -305,7 +305,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3028"
+ line="3106"
column="56"/>
</issue>
@@ -316,7 +316,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3143"
+ line="3221"
column="29"/>
</issue>
@@ -327,7 +327,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/viewpager/widget/ViewPager.java"
- line="3143"
+ line="3221"
column="46"/>
</issue>
diff --git a/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java b/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java
index 6423be2..52100a6 100644
--- a/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java
+++ b/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java
@@ -53,6 +53,7 @@
import static org.mockito.Mockito.verify;
import android.app.Activity;
+import android.content.Context;
import android.graphics.Color;
import android.support.v4.testutils.TestUtilsMatchers;
import android.text.TextUtils;
@@ -61,9 +62,11 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.EdgeEffect;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.core.os.BuildCompat;
import androidx.test.espresso.ViewAction;
import androidx.test.espresso.action.EspressoKey;
import androidx.test.filters.FlakyTest;
@@ -94,6 +97,13 @@
@Rule
public final ActivityTestRule<T> mActivityTestRule;
+ /**
+ * The distance of a swipe's start position from the view's edge, in terms of the view's length.
+ * We do not start the swipe exactly on the view's edge, but somewhat more inward, since swiping
+ * from the exact edge may behave in an unexpected way (e.g. may open a navigation drawer).
+ */
+ private static final float EDGE_FUZZ_FACTOR = 0.083f;
+
private static final int DIRECTION_LEFT = -1;
private static final int DIRECTION_RIGHT = 1;
protected ViewPager mViewPager;
@@ -336,7 +346,8 @@
verifyPageSelections(true);
}
- private void verifyPageChangeViewActions(ViewAction next, ViewAction previous) {
+ private void verifyPageChangeViewActions(ViewAction next, ViewAction previous)
+ throws Throwable {
assertEquals("Initial state", 0, mViewPager.getCurrentItem());
assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
@@ -361,6 +372,8 @@
onView(withId(R.id.pager)).perform(next);
assertEquals("Attempt to move to next page beyond last page", 2,
mViewPager.getCurrentItem());
+
+ waitForEdgeAnimations();
// We're still on this page, so we shouldn't have been called again with index 2
verify(mockPageChangeListener, times(1)).onPageSelected(2);
assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
@@ -388,6 +401,7 @@
verify(mockPageChangeListener, times(1)).onPageSelected(0);
assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+ waitForEdgeAnimations();
mViewPager.removeOnPageChangeListener(mockPageChangeListener);
@@ -397,38 +411,84 @@
assertThat(pageSelectedCaptor.getAllValues(), TestUtilsMatchers.matches(1, 2, 1, 0));
}
+ private void waitForEdgeAnimations() throws Throwable {
+ while (!mViewPager.mLeftEdge.isFinished() || !mViewPager.mRightEdge.isFinished()) {
+ mActivityTestRule.runOnUiThread(() -> {});
+ }
+ }
+
@Test
@LargeTest
- public void testPageSwipes() {
+ public void testPageSwipes() throws Throwable {
verifyPageChangeViewActions(ViewPagerActions.wrap(swipeLeft()), ViewPagerActions.wrap(swipeRight()));
}
@Test
@LargeTest
- public void testArrowPageChanges() {
+ public void testArrowPageChanges() throws Throwable {
verifyPageChangeViewActions(
ViewPagerActions.arrowScroll(View.FOCUS_RIGHT), ViewPagerActions.arrowScroll(View.FOCUS_LEFT));
}
@Test
@LargeTest
- public void testPageSwipesComposite() {
+ public void testPageSwipesComposite() throws Throwable {
assertEquals("Initial state", 0, mViewPager.getCurrentItem());
onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeLeft()), ViewPagerActions.wrap(swipeLeft()));
assertEquals("Swipe twice left", 2, mViewPager.getCurrentItem());
- onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeLeft()), ViewPagerActions.wrap(swipeRight()));
- assertEquals("Swipe left beyond last page and then right", 1, mViewPager.getCurrentItem());
+ onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeLeft()));
+
+ waitForEdgeAnimations();
+
+ onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeRight()));
+ assertEquals("Swipe left beyond last page and then right", 1,
+ mViewPager.getCurrentItem());
onView(withId(R.id.pager)).perform(
ViewPagerActions.wrap(swipeRight()), ViewPagerActions.wrap(swipeRight()));
assertEquals("Swipe right and then right beyond first page", 0,
mViewPager.getCurrentItem());
- onView(withId(R.id.pager)).perform(
- ViewPagerActions.wrap(swipeRight()), ViewPagerActions.wrap(swipeLeft()));
- assertEquals("Swipe right beyond first page and then left", 1, mViewPager.getCurrentItem());
+ waitForEdgeAnimations();
+
+ onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeRight()));
+
+ waitForEdgeAnimations();
+
+ onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeLeft()));
+
+ assertEquals("Swipe right beyond first page and then left", 1,
+ mViewPager.getCurrentItem());
+ }
+
+ @Test
+ @MediumTest
+ public void testFlingAfterStretchAtLeft() {
+ if (BuildCompat.isAtLeastS()) {
+ CaptureOnAbsorb edgeEffect = new CaptureOnAbsorb(mViewPager.getContext());
+ mViewPager.mLeftEdge = edgeEffect;
+ onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeRight()));
+ assertTrue(edgeEffect.pullDistance > 0f);
+ assertTrue(edgeEffect.absorbedVelocity > 0);
+ }
+ }
+
+ @Test
+ @MediumTest
+ public void testFlingAfterStretchAtRight() throws Throwable {
+ if (BuildCompat.isAtLeastS()) {
+ CaptureOnAbsorb edgeEffect = new CaptureOnAbsorb(mViewPager.getContext());
+ mViewPager.mRightEdge = edgeEffect;
+ mActivityTestRule.runOnUiThread(() -> {
+ mViewPager.setCurrentItem(2);
+ });
+
+ onView(withId(R.id.pager)).perform(ViewPagerActions.wrap(swipeLeft()));
+ assertTrue(edgeEffect.pullDistance > 0f);
+ assertTrue(edgeEffect.absorbedVelocity > 0);
+ }
}
private void verifyPageContent(boolean smoothScroll) {
@@ -1110,4 +1170,25 @@
onView(is(adapter.getButton(1, 0))).perform(pressKey(KeyEvent.KEYCODE_DPAD_LEFT));
assertEquals(0, mViewPager.getCurrentItem());
}
+
+ private static class CaptureOnAbsorb extends EdgeEffect {
+ public int absorbedVelocity;
+ public float pullDistance;
+
+ CaptureOnAbsorb(Context context) {
+ super(context);
+ }
+
+ @Override
+ public float onPullDistance(float deltaDistance, float displacement) {
+ pullDistance += deltaDistance;
+ return super.onPullDistance(deltaDistance, displacement);
+ }
+
+ @Override
+ public void onAbsorb(int velocity) {
+ absorbedVelocity = velocity;
+ super.onAbsorb(velocity);
+ }
+ }
}
diff --git a/viewpager/viewpager/src/androidTest/res/layout/view_pager_with_stretch.xml b/viewpager/viewpager/src/androidTest/res/layout/view_pager_with_stretch.xml
new file mode 100644
index 0000000..15f3e79
--- /dev/null
+++ b/viewpager/viewpager/src/androidTest/res/layout/view_pager_with_stretch.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<androidx.viewpager.widget.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
diff --git a/viewpager/viewpager/src/main/java/androidx/viewpager/widget/ViewPager.java b/viewpager/viewpager/src/main/java/androidx/viewpager/widget/ViewPager.java
index 1e1e827..81ee482 100644
--- a/viewpager/viewpager/src/main/java/androidx/viewpager/widget/ViewPager.java
+++ b/viewpager/viewpager/src/main/java/androidx/viewpager/widget/ViewPager.java
@@ -49,12 +49,15 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.widget.EdgeEffectCompat;
import androidx.customview.view.AbsSavedState;
import java.lang.annotation.ElementType;
@@ -231,8 +234,16 @@
private boolean mFakeDragging;
private long mFakeDragBeginTime;
- private EdgeEffect mLeftEdge;
- private EdgeEffect mRightEdge;
+ /** @hide */
+ @VisibleForTesting
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @NonNull
+ public EdgeEffect mLeftEdge;
+ /** @hide */
+ @VisibleForTesting
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @NonNull
+ public EdgeEffect mRightEdge;
private boolean mFirstLayout = true;
private boolean mCalledSuper;
@@ -391,19 +402,18 @@
public ViewPager(@NonNull Context context) {
super(context);
- initViewPager();
+ initViewPager(context, null);
}
public ViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
- initViewPager();
+ initViewPager(context, attrs);
}
- void initViewPager() {
+ void initViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
setWillNotDraw(false);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setFocusable(true);
- final Context context = getContext();
mScroller = new Scroller(context, sInterpolator);
final ViewConfiguration configuration = ViewConfiguration.get(context);
final float density = context.getResources().getDisplayMetrics().density;
@@ -2107,7 +2117,7 @@
}
if (mIsBeingDragged) {
// Scroll to follow the motion event
- if (performDrag(x)) {
+ if (performDrag(x, y)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
@@ -2135,6 +2145,18 @@
mIsBeingDragged = true;
requestParentDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
+ } else if (EdgeEffectCompat.getDistance(mLeftEdge) != 0
+ || EdgeEffectCompat.getDistance(mRightEdge) != 0) {
+ // Caught the edge glow animation
+ mIsBeingDragged = true;
+ setScrollState(SCROLL_STATE_DRAGGING);
+ if (EdgeEffectCompat.getDistance(mLeftEdge) != 0) {
+ EdgeEffectCompat.onPullDistance(mLeftEdge, 0f,
+ 1 - mLastMotionY / getHeight());
+ }
+ if (EdgeEffectCompat.getDistance(mRightEdge) != 0) {
+ EdgeEffectCompat.onPullDistance(mRightEdge, 0f, mLastMotionY / getHeight());
+ }
} else {
completeScroll(false);
mIsBeingDragged = false;
@@ -2243,7 +2265,7 @@
// Scroll to follow the motion event
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(activePointerIndex);
- needsInvalidate |= performDrag(x);
+ needsInvalidate |= performDrag(x, ev.getY(activePointerIndex));
}
break;
case MotionEvent.ACTION_UP:
@@ -2267,6 +2289,13 @@
setCurrentItemInternal(nextPage, true, true, initialVelocity);
needsInvalidate = resetTouch();
+ if (nextPage == currentPage && needsInvalidate) {
+ if (!mRightEdge.isFinished()) {
+ mRightEdge.onAbsorb(-initialVelocity);
+ } else if (!mLeftEdge.isFinished()) {
+ mLeftEdge.onAbsorb(initialVelocity);
+ }
+ }
}
break;
case MotionEvent.ACTION_CANCEL:
@@ -2299,7 +2328,7 @@
endDrag();
mLeftEdge.onRelease();
mRightEdge.onRelease();
- needsInvalidate = mLeftEdge.isFinished() || mRightEdge.isFinished();
+ needsInvalidate = !mLeftEdge.isFinished() || !mRightEdge.isFinished();
return needsInvalidate;
}
@@ -2310,11 +2339,42 @@
}
}
- private boolean performDrag(float x) {
+ /**
+ * If either of the horizontal edge glows are currently active, this consumes part or all of
+ * deltaX on the edge glow.
+ *
+ * @param deltaX The pointer motion, in pixels, in the horizontal direction, positive
+ * for moving down and negative for moving up.
+ * @param y The vertical position of the pointer.
+ * @return The amount of <code>deltaX</code> that has been consumed by the
+ * edge glow.
+ */
+ private float releaseHorizontalGlow(float deltaX, float y) {
+ // First allow releasing existing overscroll effect:
+ float consumed = 0;
+ float displacement = y / getHeight();
+ float pullDistance = (float) deltaX / getWidth();
+ if (EdgeEffectCompat.getDistance(mLeftEdge) != 0) {
+ consumed = -EdgeEffectCompat.onPullDistance(mLeftEdge, -pullDistance, 1 - displacement);
+ } else if (EdgeEffectCompat.getDistance(mRightEdge) != 0) {
+ consumed = EdgeEffectCompat.onPullDistance(mRightEdge, pullDistance, displacement);
+ }
+ return consumed * getWidth();
+ }
+
+ private boolean performDrag(float x, float y) {
boolean needsInvalidate = false;
- final float deltaX = mLastMotionX - x;
+ final float dX = mLastMotionX - x;
mLastMotionX = x;
+ final float releaseConsumed = releaseHorizontalGlow(dX, y);
+ final float deltaX = dX - releaseConsumed;
+ if (releaseConsumed != 0) {
+ needsInvalidate = true;
+ }
+ if (Math.abs(deltaX) < 0.0001f) { // ignore rounding errors from releaseHorizontalGlow()
+ return needsInvalidate;
+ }
float oldScrollX = getScrollX();
float scrollX = oldScrollX + deltaX;
@@ -2339,14 +2399,14 @@
if (scrollX < leftBound) {
if (leftAbsolute) {
float over = leftBound - scrollX;
- mLeftEdge.onPull(Math.abs(over) / width);
+ EdgeEffectCompat.onPullDistance(mLeftEdge, over / width, 1 - y / getHeight());
needsInvalidate = true;
}
scrollX = leftBound;
} else if (scrollX > rightBound) {
if (rightAbsolute) {
float over = scrollX - rightBound;
- mRightEdge.onPull(Math.abs(over) / width);
+ EdgeEffectCompat.onPullDistance(mRightEdge, over / width, y / getHeight());
needsInvalidate = true;
}
scrollX = rightBound;
@@ -2407,7 +2467,9 @@
private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
int targetPage;
- if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
+ if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity
+ && EdgeEffectCompat.getDistance(mLeftEdge) == 0 // don't fling while stretched
+ && EdgeEffectCompat.getDistance(mRightEdge) == 0) {
targetPage = velocity > 0 ? currentPage : currentPage + 1;
} else {
final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
diff --git a/viewpager2/integration-tests/testapp/src/main/AndroidManifest.xml b/viewpager2/integration-tests/testapp/src/main/AndroidManifest.xml
index 2ba748b..3ec4e78 100644
--- a/viewpager2/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/viewpager2/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -24,70 +24,70 @@
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".CardViewActivity">
+ <activity android:name=".CardViewActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".CardFragmentActivity">
+ <activity android:name=".CardFragmentActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".MutableCollectionFragmentActivity">
+ <activity android:name=".MutableCollectionFragmentActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".MutableCollectionViewActivity">
+ <activity android:name=".MutableCollectionViewActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".CardViewTabLayoutActivity">
+ <activity android:name=".CardViewTabLayoutActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".FakeDragActivity">
+ <activity android:name=".FakeDragActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".PageTransformerActivity">
+ <activity android:name=".PageTransformerActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".PreviewPagesActivity">
+ <activity android:name=".PreviewPagesActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".ParallelNestedScrollingActivity">
+ <activity android:name=".ParallelNestedScrollingActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
- <activity android:name=".BrowseActivity">
+ <activity android:name=".BrowseActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/wear/compose/compose-foundation/samples/build.gradle b/wear/compose/compose-foundation/samples/build.gradle
index fc01a79..56f7231 100644
--- a/wear/compose/compose-foundation/samples/build.gradle
+++ b/wear/compose/compose-foundation/samples/build.gradle
@@ -39,6 +39,12 @@
implementation(project(":wear:compose:compose-foundation"))
}
+android {
+ defaultConfig {
+ minSdkVersion 25
+ }
+}
+
androidx {
name = "Android Wear Compose Foundation Samples"
type = LibraryType.SAMPLES
diff --git a/wear/compose/compose-foundation/samples/src/main/AndroidManifest.xml b/wear/compose/compose-foundation/samples/src/main/AndroidManifest.xml
index 12512aa..bf52724 100644
--- a/wear/compose/compose-foundation/samples/src/main/AndroidManifest.xml
+++ b/wear/compose/compose-foundation/samples/src/main/AndroidManifest.xml
@@ -18,6 +18,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="androidx.wear.compose.foundation.samples">
- <uses-sdk android:minSdkVersion="25"
- tools:overrideLibrary="androidx.wear.compose.foundation"/>
+ <uses-sdk tools:overrideLibrary="androidx.wear.compose.foundation"/>
</manifest>
diff --git a/wear/compose/compose-material/api/current.txt b/wear/compose/compose-material/api/current.txt
index f84796e..3edf5d9 100644
--- a/wear/compose/compose-material/api/current.txt
+++ b/wear/compose/compose-material/api/current.txt
@@ -164,10 +164,36 @@
field public static final androidx.wear.compose.material.ScalingLazyColumnDefaults INSTANCE;
}
+ public interface ScalingLazyColumnItemInfo {
+ method public float getAlpha();
+ method public int getIndex();
+ method public int getOffset();
+ method public float getScale();
+ method public int getSize();
+ method public int getUnadjustedOffset();
+ property public abstract float alpha;
+ property public abstract int index;
+ property public abstract int offset;
+ property public abstract float scale;
+ property public abstract int size;
+ property public abstract int unadjustedOffset;
+ }
+
public final class ScalingLazyColumnKt {
method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingParams scalingParams, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.wear.compose.material.ScalingLazyColumnState state, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyColumnScope,kotlin.Unit> content);
}
+ public interface ScalingLazyColumnLayoutInfo {
+ method public int getTotalItemsCount();
+ method public int getViewportEndOffset();
+ method public int getViewportStartOffset();
+ method public java.util.List<androidx.wear.compose.material.ScalingLazyColumnItemInfo> getVisibleItemsInfo();
+ property public abstract int totalItemsCount;
+ property public abstract int viewportEndOffset;
+ property public abstract int viewportStartOffset;
+ property public abstract java.util.List<androidx.wear.compose.material.ScalingLazyColumnItemInfo> visibleItemsInfo;
+ }
+
public final class ScalingLazyColumnMeasureKt {
}
@@ -178,6 +204,8 @@
@androidx.compose.runtime.Stable public final class ScalingLazyColumnState {
ctor public ScalingLazyColumnState();
+ method public androidx.wear.compose.material.ScalingLazyColumnLayoutInfo getLayoutInfo();
+ property public final androidx.wear.compose.material.ScalingLazyColumnLayoutInfo layoutInfo;
field public static final androidx.wear.compose.material.ScalingLazyColumnState.Companion Companion;
}
diff --git a/wear/compose/compose-material/api/public_plus_experimental_current.txt b/wear/compose/compose-material/api/public_plus_experimental_current.txt
index cead0f8..93fd282 100644
--- a/wear/compose/compose-material/api/public_plus_experimental_current.txt
+++ b/wear/compose/compose-material/api/public_plus_experimental_current.txt
@@ -190,10 +190,36 @@
field public static final androidx.wear.compose.material.ScalingLazyColumnDefaults INSTANCE;
}
+ public interface ScalingLazyColumnItemInfo {
+ method public float getAlpha();
+ method public int getIndex();
+ method public int getOffset();
+ method public float getScale();
+ method public int getSize();
+ method public int getUnadjustedOffset();
+ property public abstract float alpha;
+ property public abstract int index;
+ property public abstract int offset;
+ property public abstract float scale;
+ property public abstract int size;
+ property public abstract int unadjustedOffset;
+ }
+
public final class ScalingLazyColumnKt {
method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingParams scalingParams, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.wear.compose.material.ScalingLazyColumnState state, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyColumnScope,kotlin.Unit> content);
}
+ public interface ScalingLazyColumnLayoutInfo {
+ method public int getTotalItemsCount();
+ method public int getViewportEndOffset();
+ method public int getViewportStartOffset();
+ method public java.util.List<androidx.wear.compose.material.ScalingLazyColumnItemInfo> getVisibleItemsInfo();
+ property public abstract int totalItemsCount;
+ property public abstract int viewportEndOffset;
+ property public abstract int viewportStartOffset;
+ property public abstract java.util.List<androidx.wear.compose.material.ScalingLazyColumnItemInfo> visibleItemsInfo;
+ }
+
public final class ScalingLazyColumnMeasureKt {
}
@@ -204,6 +230,8 @@
@androidx.compose.runtime.Stable public final class ScalingLazyColumnState {
ctor public ScalingLazyColumnState();
+ method public androidx.wear.compose.material.ScalingLazyColumnLayoutInfo getLayoutInfo();
+ property public final androidx.wear.compose.material.ScalingLazyColumnLayoutInfo layoutInfo;
field public static final androidx.wear.compose.material.ScalingLazyColumnState.Companion Companion;
}
diff --git a/wear/compose/compose-material/api/restricted_current.txt b/wear/compose/compose-material/api/restricted_current.txt
index f84796e..3edf5d9 100644
--- a/wear/compose/compose-material/api/restricted_current.txt
+++ b/wear/compose/compose-material/api/restricted_current.txt
@@ -164,10 +164,36 @@
field public static final androidx.wear.compose.material.ScalingLazyColumnDefaults INSTANCE;
}
+ public interface ScalingLazyColumnItemInfo {
+ method public float getAlpha();
+ method public int getIndex();
+ method public int getOffset();
+ method public float getScale();
+ method public int getSize();
+ method public int getUnadjustedOffset();
+ property public abstract float alpha;
+ property public abstract int index;
+ property public abstract int offset;
+ property public abstract float scale;
+ property public abstract int size;
+ property public abstract int unadjustedOffset;
+ }
+
public final class ScalingLazyColumnKt {
method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingParams scalingParams, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.wear.compose.material.ScalingLazyColumnState state, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyColumnScope,kotlin.Unit> content);
}
+ public interface ScalingLazyColumnLayoutInfo {
+ method public int getTotalItemsCount();
+ method public int getViewportEndOffset();
+ method public int getViewportStartOffset();
+ method public java.util.List<androidx.wear.compose.material.ScalingLazyColumnItemInfo> getVisibleItemsInfo();
+ property public abstract int totalItemsCount;
+ property public abstract int viewportEndOffset;
+ property public abstract int viewportStartOffset;
+ property public abstract java.util.List<androidx.wear.compose.material.ScalingLazyColumnItemInfo> visibleItemsInfo;
+ }
+
public final class ScalingLazyColumnMeasureKt {
}
@@ -178,6 +204,8 @@
@androidx.compose.runtime.Stable public final class ScalingLazyColumnState {
ctor public ScalingLazyColumnState();
+ method public androidx.wear.compose.material.ScalingLazyColumnLayoutInfo getLayoutInfo();
+ property public final androidx.wear.compose.material.ScalingLazyColumnLayoutInfo layoutInfo;
field public static final androidx.wear.compose.material.ScalingLazyColumnState.Companion Companion;
}
diff --git a/wear/compose/compose-material/build.gradle b/wear/compose/compose-material/build.gradle
index d464b4f..48477c7 100644
--- a/wear/compose/compose-material/build.gradle
+++ b/wear/compose/compose-material/build.gradle
@@ -46,6 +46,7 @@
androidTestImplementation project(path: ':compose:test-utils')
androidTestImplementation project(":test:screenshot:test-screenshot")
androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.truth)
}
}
diff --git a/wear/compose/compose-material/samples/build.gradle b/wear/compose/compose-material/samples/build.gradle
index 748fd30..8f3828d 100644
--- a/wear/compose/compose-material/samples/build.gradle
+++ b/wear/compose/compose-material/samples/build.gradle
@@ -39,6 +39,12 @@
implementation(project(":wear:compose:compose-material"))
}
+android {
+ defaultConfig {
+ minSdkVersion 25
+ }
+}
+
androidx {
name = "Android Wear Compose Material Samples"
type = LibraryType.SAMPLES
diff --git a/wear/compose/compose-material/samples/src/main/AndroidManifest.xml b/wear/compose/compose-material/samples/src/main/AndroidManifest.xml
index 67639fa..9607116 100644
--- a/wear/compose/compose-material/samples/src/main/AndroidManifest.xml
+++ b/wear/compose/compose-material/samples/src/main/AndroidManifest.xml
@@ -18,6 +18,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="androidx.wear.compose.material.samples">
- <uses-sdk android:minSdkVersion="25"
- tools:overrideLibrary="androidx.wear.compose.material"/>
+ <uses-sdk tools:overrideLibrary="androidx.wear.compose.material"/>
</manifest>
diff --git a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
index 53aea17..9a6a05d 100644
--- a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
+++ b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
@@ -17,6 +17,7 @@
package androidx.wear.compose.material.samples
import androidx.annotation.Sampled
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
@@ -31,7 +32,20 @@
@Sampled
@Composable
fun SimpleScalingLazyColumn() {
- ScalingLazyColumn() {
+ ScalingLazyColumn {
+ items(20) {
+ Chip(
+ onClick = { },
+ label = { Text("List item $it") },
+ colors = ChipDefaults.secondaryChipColors()
+ )
+ }
+ }
+}
+
+@Composable
+fun SimpleScalingLazyColumnWithContentPadding() {
+ ScalingLazyColumn(contentPadding = PaddingValues(top = 100.dp, bottom = 100.dp)) {
items(20) {
Chip(
onClick = { },
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnLayoutInfoTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnLayoutInfoTest.kt
new file mode 100644
index 0000000..d6a00f6
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnLayoutInfoTest.kt
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import com.google.common.truth.Truth.assertThat
+import kotlin.math.roundToInt
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+public class ScalingLazyColumnLayoutInfoTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private var itemSizePx: Int = 50
+ private var itemSizeDp: Dp = Dp.Infinity
+ private var defaultItemSpacingDp: Dp = 4.dp
+ private var defaultItemSpacingPx = Int.MAX_VALUE
+
+ @Before
+ fun before() {
+ with(rule.density) {
+ itemSizeDp = itemSizePx.toDp()
+ defaultItemSpacingPx = defaultItemSpacingDp.roundToPx()
+ }
+ }
+
+ @Test
+ fun visibleItemsAreCorrect() {
+ lateinit var state: ScalingLazyColumnState
+ rule.setContent {
+ ScalingLazyColumn(
+ state = rememberScalingLazyColumnState().also { state = it },
+ modifier = Modifier.requiredSize(
+ itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
+ ),
+ ) {
+ items(5) {
+ Box(Modifier.requiredSize(itemSizeDp))
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ state.layoutInfo.assertVisibleItems(count = 4)
+ }
+ }
+
+ @Test
+ fun visibleItemsAreCorrectNoScaling() {
+ lateinit var state: ScalingLazyColumnState
+ rule.setContent {
+ ScalingLazyColumn(
+ state = rememberScalingLazyColumnState().also { state = it },
+ modifier = Modifier.requiredSize(
+ itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
+ ),
+ scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f)
+ ) {
+ items(5) {
+ Box(Modifier.requiredSize(itemSizeDp))
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ state.layoutInfo.assertVisibleItems(count = 4)
+ assertThat(state.layoutInfo.visibleItemsInfo.first().offset).isEqualTo(0)
+ }
+ }
+
+ @Test
+ fun visibleItemsAreCorrectWithCustomSpacing() {
+ lateinit var state: ScalingLazyColumnState
+ val spacing: Dp = 10.dp
+ rule.setContent {
+ ScalingLazyColumn(
+ state = rememberScalingLazyColumnState().also { state = it },
+ modifier = Modifier.requiredSize(itemSizeDp * 3.5f + spacing * 2.5f),
+ verticalArrangement = Arrangement.spacedBy(spacing)
+ ) {
+ items(5) {
+ Box(Modifier.requiredSize(itemSizeDp))
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ val spacingPx = with(rule.density) {
+ spacing.roundToPx()
+ }
+ state.layoutInfo.assertVisibleItems(
+ count = 4,
+ spacing = spacingPx
+ )
+ }
+ }
+
+ @Test
+ fun visibleItemsAreObservableWhenResize() {
+ lateinit var state: ScalingLazyColumnState
+ var size by mutableStateOf(itemSizeDp * 2)
+ var currentInfo: ScalingLazyColumnLayoutInfo? = null
+ @Composable
+ fun observingFun() {
+ currentInfo = state.layoutInfo
+ }
+ rule.setContent {
+ ScalingLazyColumn(
+ state = rememberScalingLazyColumnState().also { state = it }
+ ) {
+ item {
+ Box(Modifier.requiredSize(size))
+ }
+ }
+ observingFun()
+ }
+
+ rule.runOnIdle {
+ assertThat(currentInfo).isNotNull()
+ currentInfo!!.assertVisibleItems(count = 1, unscaledSize = itemSizePx * 2)
+ currentInfo = null
+ size = itemSizeDp
+ }
+
+ rule.runOnIdle {
+ assertThat(currentInfo).isNotNull()
+ currentInfo!!.assertVisibleItems(count = 1, unscaledSize = itemSizePx)
+ }
+ }
+
+ @Test
+ fun viewportOffsetsAreCorrect() {
+ val sizePx = 45
+ val sizeDp = with(rule.density) { sizePx.toDp() }
+ lateinit var state: ScalingLazyColumnState
+ rule.setContent {
+ ScalingLazyColumn(
+ Modifier.requiredSize(sizeDp),
+ state = rememberScalingLazyColumnState().also { state = it }
+ ) {
+ items(4) {
+ Box(Modifier.requiredSize(sizeDp))
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(state.layoutInfo.viewportStartOffset).isEqualTo(0)
+ assertThat(state.layoutInfo.viewportEndOffset).isEqualTo(sizePx)
+ }
+ }
+
+ @Test
+ fun viewportOffsetsAreCorrectWithContentPadding() {
+ val sizePx = 45
+ val startPaddingPx = 10
+ val endPaddingPx = 15
+ val sizeDp = with(rule.density) { sizePx.toDp() }
+ val topPaddingDp = with(rule.density) { startPaddingPx.toDp() }
+ val bottomPaddingDp = with(rule.density) { endPaddingPx.toDp() }
+ lateinit var state: ScalingLazyColumnState
+ rule.setContent {
+ ScalingLazyColumn(
+ Modifier.requiredSize(sizeDp),
+ contentPadding = PaddingValues(top = topPaddingDp, bottom = bottomPaddingDp),
+ state = rememberScalingLazyColumnState().also { state = it }
+ ) {
+ items(4) {
+ Box(Modifier.requiredSize(sizeDp))
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(state.layoutInfo.viewportStartOffset).isEqualTo(-startPaddingPx)
+ assertThat(state.layoutInfo.viewportEndOffset).isEqualTo(sizePx - startPaddingPx)
+ }
+ }
+
+ @Test
+ fun totalCountIsCorrect() {
+ var count by mutableStateOf(10)
+ lateinit var state: ScalingLazyColumnState
+ rule.setContent {
+ ScalingLazyColumn(
+ state = rememberScalingLazyColumnState().also { state = it }
+ ) {
+ items(count) {
+ Box(Modifier.requiredSize(10.dp))
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(state.layoutInfo.totalItemsCount).isEqualTo(10)
+ count = 20
+ }
+
+ rule.runOnIdle {
+ assertThat(state.layoutInfo.totalItemsCount).isEqualTo(20)
+ }
+ }
+
+ fun ScalingLazyColumnLayoutInfo.assertVisibleItems(
+ count: Int,
+ startIndex: Int = 0,
+ unscaledSize: Int = itemSizePx,
+ spacing: Int = defaultItemSpacingPx
+ ) {
+ assertThat(visibleItemsInfo.size).isEqualTo(count)
+ var currentIndex = startIndex
+ var previousEndOffset = -1
+ visibleItemsInfo.forEach {
+ assertThat(it.index).isEqualTo(currentIndex)
+ assertThat(it.size).isEqualTo((unscaledSize * it.scale).roundToInt())
+ currentIndex++
+ if (previousEndOffset != -1) {
+ assertThat(spacing).isEqualTo(it.offset - previousEndOffset)
+ }
+ previousEndOffset = it.offset + it.size
+ }
+ }
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/SwipeToDismissBoxTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/SwipeToDismissBoxTest.kt
new file mode 100644
index 0000000..b2b1548
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/SwipeToDismissBoxTest.kt
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.GestureScope
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performGesture
+import androidx.compose.ui.test.swipeLeft
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.test.width
+import androidx.wear.compose.material.ExperimentalWearMaterialApi
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.SwipeDismissTarget
+import androidx.wear.compose.material.SwipeToDismissBox
+import androidx.wear.compose.material.TEST_TAG
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.rememberSwipeToDismissBoxState
+import androidx.wear.compose.material.setContentWithTheme
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+@ExperimentalWearMaterialApi
+class SwipeToDismissBoxTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun supports_testtag() {
+ rule.setContentWithTheme {
+ val state = rememberSwipeToDismissBoxState()
+ SwipeToDismissBox(
+ state = state,
+ modifier = Modifier.testTag(TEST_TAG)
+ ) {
+ Text("Test")
+ }
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun dismisses_when_swiped_right() =
+ verifySwipe(gesture = { swipeRight() }, expectedToDismiss = true)
+
+ @Test
+ fun does_not_dismiss_when_swiped_left() =
+ // Swipe left is met with resistance and is not a swipe-to-dismiss.
+ verifySwipe(gesture = { swipeLeft() }, expectedToDismiss = false)
+
+ @Test
+ @ExperimentalTestApi
+ fun does_not_dismiss_when_swipe_right_incomplete() =
+ // Execute a partial swipe over a longer-than-default duration so that there
+ // is insufficient velocity to perform a 'fling'.
+ verifySwipe(
+ gesture = { swipeRight(startX = 0f, endX = width / 4f, durationMillis = LONG_SWIPE) },
+ expectedToDismiss = false
+ )
+
+ @Test
+ fun does_not_display_background_without_swipe() {
+ rule.setContentWithTheme {
+ val state = rememberSwipeToDismissBoxState()
+ SwipeToDismissBox(
+ state = state,
+ modifier = Modifier.testTag(TEST_TAG),
+ background = {
+ Text(BACKGROUND_MESSAGE)
+ },
+ ) {
+ messageContent()
+ }
+ }
+
+ rule.onNodeWithText(BACKGROUND_MESSAGE).assertDoesNotExist()
+ }
+
+ @Test
+ @ExperimentalTestApi
+ fun displays_background_during_swipe() =
+ verifyPartialSwipe(expectedMessage = BACKGROUND_MESSAGE)
+
+ @Test
+ @ExperimentalTestApi
+ fun displays_content_during_swipe() =
+ verifyPartialSwipe(expectedMessage = CONTENT_MESSAGE)
+
+ fun verifySwipe(gesture: GestureScope.() -> Unit, expectedToDismiss: Boolean) {
+ var dismissed = false
+ rule.setContentWithTheme {
+ val state = rememberSwipeToDismissBoxState()
+ LaunchedEffect(state.currentValue) {
+ dismissed =
+ state.currentValue == SwipeDismissTarget.Dismissal
+ }
+ SwipeToDismissBox(
+ state = state,
+ modifier = Modifier.testTag(TEST_TAG),
+ ) {
+ messageContent()
+ }
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performGesture(gesture)
+
+ rule.runOnIdle {
+ assertEquals(expectedToDismiss, dismissed)
+ }
+ }
+
+ @ExperimentalTestApi
+ fun verifyPartialSwipe(expectedMessage: String) {
+ rule.setContentWithTheme {
+ val state = rememberSwipeToDismissBoxState()
+ SwipeToDismissBox(
+ state = state,
+ modifier = Modifier.testTag(TEST_TAG),
+ background = {
+ Text(BACKGROUND_MESSAGE)
+ },
+ ) {
+ messageContent()
+ }
+ }
+
+ // Advance the clock by half the length of time configured for the swipe gesture,
+ // so that the background ought to be revealed.
+ rule.mainClock.autoAdvance = false
+ rule.onNodeWithTag(TEST_TAG).performGesture { swipeRight(durationMillis = LONG_SWIPE) }
+ rule.waitForIdle()
+ rule.mainClock.advanceTimeBy(milliseconds = LONG_SWIPE / 2)
+
+ rule.onNodeWithText(expectedMessage).assertExists()
+ }
+
+ @Composable
+ fun messageContent() {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center,
+ ) {
+ Text(CONTENT_MESSAGE, color = MaterialTheme.colors.onPrimary)
+ }
+ }
+}
+
+internal const val BACKGROUND_MESSAGE = "The Background"
+internal const val CONTENT_MESSAGE = "The Content"
+internal const val LONG_SWIPE = 1000L
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
index 64bfa92..d1d0f97 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
@@ -25,13 +25,13 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
-import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
@@ -39,7 +39,6 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
-import kotlin.math.roundToInt
/**
* Receiver scope which is used by [ScalingLazyColumn].
@@ -96,9 +95,17 @@
content: ScalingLazyColumnScope.() -> Unit
) {
BoxWithConstraints(modifier = modifier) {
-
val extraPaddingInPixels = scalingParams.resolveViewportVerticalOffset(constraints)
val extraPadding = with(LocalDensity.current) { extraPaddingInPixels.toDp() }
+
+ // Set up transient state
+ state.scalingParams.value = scalingParams
+ state.extraPaddingInPixels.value = extraPaddingInPixels
+ state.viewportHeightPx.value = constraints.maxHeight
+ state.gapBetweenItemsPx.value = with(LocalDensity.current) {
+ verticalArrangement.spacing.roundToPx()
+ }
+
val combinedPaddingValues = CombinedPaddingValues(
contentPadding = contentPadding,
extraPadding = extraPadding
@@ -128,11 +135,8 @@
state = state.lazyListState
) {
val scope = ScalingLazyColumnScopeImpl(
- state.lazyListState,
+ state,
this,
- scalingParams,
- maxHeight,
- verticalArrangement.spacing
)
scope.content()
}
@@ -213,11 +217,8 @@
}
private class ScalingLazyColumnScopeImpl(
- private val state: LazyListState,
+ private val state: ScalingLazyColumnState,
private val scope: LazyListScope,
- private val scalingParams: ScalingParams,
- private val realViewportSize: Dp,
- private val paddingBetweenItems: Dp
) : ScalingLazyColumnScope {
private var currentStartIndex = 0
@@ -228,9 +229,6 @@
ScalingLazyColumnItemWrapper(
startIndex,
state,
- scalingParams,
- realViewportSize,
- paddingBetweenItems,
content = content
)
}
@@ -243,9 +241,6 @@
ScalingLazyColumnItemWrapper(
startIndex + it,
state,
- scalingParams,
- realViewportSize,
- paddingBetweenItems
) {
itemContent(it)
}
@@ -257,85 +252,20 @@
@Composable
private fun ScalingLazyColumnItemWrapper(
index: Int,
- state: LazyListState,
- scalingParams: ScalingParams,
- realViewportSize: Dp,
- paddingBetweenItems: Dp,
+ state: ScalingLazyColumnState,
content: @Composable () -> Unit
) {
Box(
- // TODO (b/194464927): Refactor this method to make it more readable
Modifier.graphicsLayer {
val items = state.layoutInfo.visibleItemsInfo
val currentItem = items.find { it.index == index }
if (currentItem != null) {
- val viewportSize = realViewportSize.roundToPx()
- val centerOffset = viewportSize / 2
- val paddingBetweenItemsPx = paddingBetweenItems.roundToPx()
-
- val rawItemStart = currentItem.offset
- val rawItemEnd = rawItemStart + currentItem.size
- if (rawItemEnd < centerOffset) {
- var currentSumOfScaledSizeDiffs = 0
- items.reversed().forEach {
- if (it.index > currentItem.index && it.offset < centerOffset) {
- val (scale, _) = calculateScaleAndAlpha(
- 0,
- viewportSize,
- it.offset + currentSumOfScaledSizeDiffs,
- it.offset + it.size + currentSumOfScaledSizeDiffs,
- scalingParams
- )
- currentSumOfScaledSizeDiffs += it.size -
- (it.size * scale).roundToInt() +
- (
- paddingBetweenItemsPx -
- (paddingBetweenItemsPx * scale).roundToInt()
- )
- }
- }
- translationY = currentSumOfScaledSizeDiffs.toFloat()
- }
- if (rawItemEnd > centerOffset) {
- var currentSumOfScaledSizeDiffs = 0
- items.forEach {
- if (it.index < currentItem.index && it.offset > centerOffset) {
- val (scale, _) = calculateScaleAndAlpha(
- 0,
- viewportSize,
- it.offset + currentSumOfScaledSizeDiffs,
- it.offset + it.size + currentSumOfScaledSizeDiffs,
- scalingParams
- )
- currentSumOfScaledSizeDiffs -= it.size -
- (it.size * scale).roundToInt() -
- (
- paddingBetweenItemsPx -
- (paddingBetweenItemsPx * scale).roundToInt()
- )
- }
- }
- translationY = currentSumOfScaledSizeDiffs.toFloat()
- }
-
- val (scaleToApply, alphaToApply) = calculateScaleAndAlpha(
- 0,
- viewportSize,
- rawItemStart + translationY.roundToInt(),
- rawItemEnd + translationY.roundToInt(),
- scalingParams
- )
-
- alpha = alphaToApply
- scaleX = scaleToApply
- scaleY = scaleToApply
- val halfScaleSizeDiff = (currentItem.size - (currentItem.size * scaleToApply)) / 2f
- if (rawItemEnd < centerOffset) {
- translationY += halfScaleSizeDiff
- }
- if (rawItemEnd > centerOffset) {
- translationY -= halfScaleSizeDiff
- }
+ alpha = currentItem.alpha
+ scaleX = currentItem.scale
+ scaleY = currentItem.scale
+ translationY =
+ (currentItem.offset - currentItem.unadjustedOffset).toFloat()
+ transformOrigin = TransformOrigin(0.5f, 0.0f)
}
}
) {
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnItemInfo.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnItemInfo.kt
new file mode 100644
index 0000000..26a30fb
--- /dev/null
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnItemInfo.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.wear.compose.material
+
+/**
+ * Contains useful information about an individual item in a [ScalingLazyColumn].
+ *
+ * @see ScalingLazyColumnLayoutInfo
+ */
+interface ScalingLazyColumnItemInfo {
+ /**
+ * The index of the item in the list.
+ */
+ val index: Int
+
+ /**
+ * The main axis offset of the item before adjustment for scaling of the items in the viewport.
+ * It is relative to the start of the lazy list container.
+ */
+ val unadjustedOffset: Int
+
+ /**
+ * The main axis offset of the item after adjustment for scaling of the items in the viewport.
+ * It is relative to the start of the lazy list container.
+ */
+ val offset: Int
+
+ /**
+ * The scaled/adjusted main axis size of the item. Note that if you emit multiple layouts in the
+ * composable slot for the item then this size will be calculated as the sum of their sizes.
+ */
+ val size: Int
+
+ /**
+ * How much scaling has been applied to the item, between 0 and 1
+ */
+ val scale: Float
+
+ /**
+ * How much alpha should be applied to the item, between 0 and 1
+ */
+ val alpha: Float
+}
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnLayoutInfo.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnLayoutInfo.kt
new file mode 100644
index 0000000..eef8982
--- /dev/null
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnLayoutInfo.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.wear.compose.material
+
+/**
+ * Contains useful information about the currently displayed layout state of [ScalingLazyColumn].
+ * For example you can get the list of currently displayed item.
+ *
+ * Use [ScalingLazyColumnState.layoutInfo] to retrieve this
+ */
+interface ScalingLazyColumnLayoutInfo {
+ /**
+ * The list of [ScalingLazyColumnItemInfo] representing all the currently visible items.
+ */
+ val visibleItemsInfo: List<ScalingLazyColumnItemInfo>
+
+ /**
+ * The start offset of the layout's viewport. You can think of it as a minimum offset which
+ * would be visible. Usually it is 0, but it can be negative if a content padding was applied
+ * as the content displayed in the content padding area is still visible.
+ *
+ * You can use it to understand what items from [visibleItemsInfo] are fully visible.
+ */
+ val viewportStartOffset: Int
+
+ /**
+ * The end offset of the layout's viewport. You can think of it as a maximum offset which
+ * would be visible. Usually it is a size of the lazy list container plus a content padding.
+ *
+ * You can use it to understand what items from [visibleItemsInfo] are fully visible.
+ */
+ val viewportEndOffset: Int
+
+ /**
+ * The total count of items passed to [ScalingLazyColumn].
+ */
+ val totalItemsCount: Int
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
index 401b349..9994b74 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
@@ -17,9 +17,12 @@
package androidx.wear.compose.material
import androidx.compose.animation.core.Easing
+import androidx.compose.foundation.lazy.LazyListItemInfo
import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
import androidx.compose.ui.unit.Constraints
import kotlin.math.min
+import kotlin.math.roundToInt
/**
* Parameters to control the scaling of the contents of a [ScalingLazyColumn]. The contents
@@ -158,6 +161,7 @@
public fun resolveViewportVerticalOffset(viewportConstraints: Constraints): Int
}
+@Stable
internal class DefaultScalingParams(
override val edgeScale: Float,
override val edgeAlpha: Float,
@@ -300,11 +304,70 @@
return ScaleAndAlpha(scaleToApply, alphaToApply)
}
+/**
+ * Create a [ScalingLazyColumnItemInfo] given an unscaled start and end position for an item.
+ *
+ * @param itemStart the x-axis position of a list item. The x-axis position takes into account
+ * any adjustment to the original position based on the scaling of other list items.
+ * @param item the original item info used to provide the pre-scaling position and size
+ * information for the item.
+ * @param verticalAdjustment the amount of vertical adjustment to apply to item positions to
+ * allow for content padding in order to determine the adjusted position of the item within the
+ * viewport in order to correctly calculate the scaling to apply.
+ * @param viewportHeightPx the height of the viewport in pixels
+ * @param scalingParams the scaling params to use for determining the scaled size of the item
+ */
+internal fun createItemInfo(
+ itemStart: Int,
+ item: LazyListItemInfo,
+ verticalAdjustment: Int,
+ viewportHeightPx: Int,
+ scalingParams: ScalingParams,
+): ScalingLazyColumnItemInfo {
+ val adjustedItemStart = itemStart - verticalAdjustment
+ val adjustedItemEnd = itemStart + item.size - verticalAdjustment
+
+ val scaleAndAlpha = calculateScaleAndAlpha(
+ viewPortStartPx = 0, viewPortEndPx = viewportHeightPx, itemTopPx = adjustedItemStart,
+ itemBottomPx = adjustedItemEnd, scalingParams = scalingParams
+ )
+
+ val isAboveLine = (adjustedItemEnd + adjustedItemStart) < viewportHeightPx
+ val scaledHeight = (item.size * scaleAndAlpha.scale).roundToInt()
+ val scaledItemTop = if (!isAboveLine) {
+ itemStart
+ } else {
+ itemStart + item.size - scaledHeight
+ }
+
+ return DefaultScalingLazyColumnItemInfo(
+ index = item.index,
+ unadjustedOffset = item.offset,
+ offset = scaledItemTop,
+ size = scaledHeight,
+ scale = scaleAndAlpha.scale,
+ alpha = scaleAndAlpha.alpha
+ )
+}
+
+internal class DefaultScalingLazyColumnLayoutInfo(
+ override val visibleItemsInfo: List<ScalingLazyColumnItemInfo>,
+ override val viewportStartOffset: Int,
+ override val viewportEndOffset: Int,
+ override val totalItemsCount: Int
+) : ScalingLazyColumnLayoutInfo
+
+internal class DefaultScalingLazyColumnItemInfo(
+ override val index: Int,
+ override val unadjustedOffset: Int,
+ override val offset: Int,
+ override val size: Int,
+ override val scale: Float,
+ override val alpha: Float
+) : ScalingLazyColumnItemInfo
+
@Immutable
internal data class ScaleAndAlpha(
val scale: Float,
val alpha: Float
)
-
-@Immutable
-internal data class ScaleAlphaAndStartPosition(val scale: Float, val alpha: Float, val top: Int)
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnState.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnState.kt
index 738ed4d..c5bce6d 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnState.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnState.kt
@@ -1,8 +1,28 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package androidx.wear.compose.material
+import androidx.compose.foundation.lazy.LazyListItemInfo
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
@@ -27,6 +47,122 @@
public class ScalingLazyColumnState {
internal var lazyListState: LazyListState = LazyListState(0, 0)
+ internal val extraPaddingInPixels = mutableStateOf<Int?>(null)
+ internal val scalingParams = mutableStateOf<ScalingParams?>(null)
+ internal val gapBetweenItemsPx = mutableStateOf<Int?>(null)
+ internal val viewportHeightPx = mutableStateOf<Int?>(null)
+
+ /**
+ * The object of [ScalingLazyColumnLayoutInfo] calculated during the last layout pass. For
+ * example, you can use it to calculate what items are currently visible.
+ */
+ public val layoutInfo: ScalingLazyColumnLayoutInfo by derivedStateOf {
+ if (extraPaddingInPixels.value == null || scalingParams.value == null ||
+ gapBetweenItemsPx.value == null || viewportHeightPx.value == null
+ ) {
+ EmptyScalingLazyColumnLayoutInfo
+ } else {
+ val visibleItemsInfo = mutableListOf<ScalingLazyColumnItemInfo>()
+
+ if (lazyListState.layoutInfo.visibleItemsInfo.isNotEmpty()) {
+ val verticalAdjustment =
+ lazyListState.layoutInfo.viewportStartOffset + extraPaddingInPixels.value!!
+
+ // Find the item in the middle of the viewport
+ val centralItem =
+ findItemNearestCenter(viewportHeightPx.value!!, verticalAdjustment)!!
+
+ // Place the center item
+ val centerItemInfo = createItemInfo(
+ centralItem.offset,
+ centralItem,
+ verticalAdjustment,
+ viewportHeightPx.value!!,
+ scalingParams.value!!,
+ )
+ visibleItemsInfo.add(
+ centerItemInfo
+ )
+ // Go Up
+ val centralItemIndex = centralItem.index
+ var nextItemBottomNoPadding = centerItemInfo.offset - gapBetweenItemsPx.value!!
+ (centralItemIndex - 1 downTo 0).forEach { ix ->
+ val currentItem =
+ lazyListState.layoutInfo.visibleItemsInfo.find { it.index == ix }
+ if (currentItem != null) {
+ val itemInfo = createItemInfo(
+ nextItemBottomNoPadding - currentItem.size,
+ currentItem,
+ verticalAdjustment,
+ viewportHeightPx.value!!,
+ scalingParams.value!!,
+ )
+ // If the item is visible in the viewport insert it at the start of the
+ // list
+ if ((itemInfo.offset + itemInfo.size) > verticalAdjustment) {
+ // Insert the item info at the front of the list
+ visibleItemsInfo.add(0, itemInfo)
+ }
+ nextItemBottomNoPadding = itemInfo.offset - gapBetweenItemsPx.value!!
+ }
+ }
+ // Go Down
+ var nextItemTopNoPadding =
+ centerItemInfo.offset + centerItemInfo.size +
+ gapBetweenItemsPx.value!!
+ (
+ centralItemIndex + 1 until
+ (centralItemIndex + lazyListState.layoutInfo.visibleItemsInfo.size)
+ )
+ .forEach { ix ->
+ val currentItem =
+ lazyListState.layoutInfo.visibleItemsInfo.find { it.index == ix }
+ if (currentItem != null) {
+ val itemInfo = createItemInfo(
+ nextItemTopNoPadding,
+ currentItem,
+ verticalAdjustment,
+ viewportHeightPx.value!!,
+ scalingParams.value!!,
+ )
+ // If the item is visible in the viewport insert it at the end of the
+ // list
+ if ((itemInfo.offset - verticalAdjustment) < viewportHeightPx.value!!) {
+ visibleItemsInfo.add(itemInfo)
+ }
+ nextItemTopNoPadding =
+ itemInfo.offset + itemInfo.size + gapBetweenItemsPx.value!!
+ }
+ }
+ }
+ DefaultScalingLazyColumnLayoutInfo(
+ visibleItemsInfo = visibleItemsInfo,
+ totalItemsCount = lazyListState.layoutInfo.totalItemsCount,
+ viewportStartOffset = lazyListState.layoutInfo.viewportStartOffset +
+ extraPaddingInPixels.value!!,
+ viewportEndOffset = lazyListState.layoutInfo.viewportEndOffset -
+ extraPaddingInPixels.value!!
+ )
+ }
+ }
+
+ private fun findItemNearestCenter(
+ viewportHeightPx: Int,
+ verticalAdjustment: Int
+ ): LazyListItemInfo? {
+ val centerLine = viewportHeightPx / 2
+ var result: LazyListItemInfo? = null
+ // Find the item in the middle of the viewport
+ for (item in lazyListState.layoutInfo.visibleItemsInfo) {
+ val rawItemStart = item.offset - verticalAdjustment
+ val rawItemEnd = rawItemStart + item.size
+ result = item
+ if (rawItemEnd > centerLine) {
+ break
+ }
+ }
+ return result
+ }
companion object {
/**
@@ -36,17 +172,24 @@
save = {
listOf(
it.lazyListState.firstVisibleItemIndex,
- it.lazyListState.firstVisibleItemScrollOffset
+ it.lazyListState.firstVisibleItemScrollOffset,
)
},
restore = {
- var scalingLazyColumnState = ScalingLazyColumnState()
+ val scalingLazyColumnState = ScalingLazyColumnState()
scalingLazyColumnState.lazyListState = LazyListState(
firstVisibleItemIndex = it[0],
- firstVisibleItemScrollOffset = it[1]
+ firstVisibleItemScrollOffset = it[1],
)
scalingLazyColumnState
}
)
}
}
+
+private object EmptyScalingLazyColumnLayoutInfo : ScalingLazyColumnLayoutInfo {
+ override val visibleItemsInfo = emptyList<ScalingLazyColumnItemInfo>()
+ override val viewportStartOffset = 0
+ override val viewportEndOffset = 0
+ override val totalItemsCount = 0
+}
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
index 828a084..c52d8fca 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
@@ -68,7 +68,7 @@
)
Box(
- modifier = modifier
+ modifier = Modifier
.fillMaxSize()
.swipeable(
state = state,
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
index 1b6a684..ed7220d 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
@@ -21,6 +21,7 @@
import androidx.wear.compose.material.ExperimentalWearMaterialApi
import androidx.wear.compose.material.samples.ScalingLazyColumnWithHeaders
import androidx.wear.compose.material.samples.SimpleScalingLazyColumn
+import androidx.wear.compose.material.samples.SimpleScalingLazyColumnWithContentPadding
import androidx.wear.compose.material.samples.SimpleSwipeToDismissBox
// Declare the swipe to dismiss demos so that we can use this variable as the background composable
@@ -72,7 +73,15 @@
),
ComposableDemo("Card") { CardDemo() },
SwipeToDismissDemos,
- ComposableDemo("Scaling Lazy Column") { SimpleScalingLazyColumn() },
- ComposableDemo("List Headers") { ScalingLazyColumnWithHeaders() },
+ DemoCategory(
+ "List",
+ listOf(
+ ComposableDemo("Scaling Lazy Column") { SimpleScalingLazyColumn() },
+ ComposableDemo("SLC with Content Padding") {
+ SimpleScalingLazyColumnWithContentPadding()
+ },
+ ComposableDemo("List Headers") { ScalingLazyColumnWithHeaders() },
+ )
+ )
),
)
diff --git a/wear/tiles/tiles-renderer/src/androidTest/java/androidx/wear/tiles/renderer/test/TileRendererGoldenTest.java b/wear/tiles/tiles-renderer/src/androidTest/java/androidx/wear/tiles/renderer/test/TileRendererGoldenTest.java
index 433bec7..e3c0260 100644
--- a/wear/tiles/tiles-renderer/src/androidTest/java/androidx/wear/tiles/renderer/test/TileRendererGoldenTest.java
+++ b/wear/tiles/tiles-renderer/src/androidTest/java/androidx/wear/tiles/renderer/test/TileRendererGoldenTest.java
@@ -93,6 +93,7 @@
{"line_in_arc"},
{"line_multi_height"},
{"long_text"},
+ {"mixed_language_text"},
{"multi_line_text_alignment"},
{"row_column_space_test"},
{"row_with_alignment"},
diff --git a/wear/tiles/tiles-renderer/src/androidTest/res/raw/mixed_language_text.textproto b/wear/tiles/tiles-renderer/src/androidTest/res/raw/mixed_language_text.textproto
new file mode 100644
index 0000000..27891c3
--- /dev/null
+++ b/wear/tiles/tiles-renderer/src/androidTest/res/raw/mixed_language_text.textproto
@@ -0,0 +1,73 @@
+box {
+ modifiers {
+ background {
+ color {
+ argb: 0xFF000000
+ }
+ }
+ }
+ width {
+ expanded_dimension: {}
+ }
+ height {
+ expanded_dimension: {}
+ }
+ vertical_alignment {
+ value: VERTICAL_ALIGN_CENTER
+ }
+ horizontal_alignment {
+ value: HORIZONTAL_ALIGN_CENTER
+ }
+ contents {
+ column {
+ horizontal_alignment {
+ value: HORIZONTAL_ALIGN_LEFT
+ }
+ contents {
+ text {
+ text {
+ value: "Latin Only"
+ }
+ font_style {
+ size { value: 16 }
+ underline { value: true }
+ }
+ }
+ }
+ contents {
+ text {
+ text {
+ value: "Underline 안녕하세요"
+ }
+ font_style {
+ size { value: 16 }
+ underline { value: true }
+ }
+ }
+ }
+ contents {
+ text {
+ text {
+ value: "Italic 안녕하세요"
+ }
+ font_style {
+ size { value: 16 }
+ italic { value: true }
+ }
+ }
+ }
+ contents {
+ text {
+ text {
+ value: "Italic Underline 안녕하세요"
+ }
+ font_style {
+ size { value: 16 }
+ italic { value: true }
+ underline { value: true }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
index de35084..bd556c18 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
@@ -56,19 +56,19 @@
/**
* Default constructor.
*
- * @param appContext The application context.
+ * @param uiContext A {@link Context} suitable for interacting with the UI.
* @param layout The portion of the Tile to render.
* @param resources The resources for the Tile.
* @param loadActionListener Listener for clicks that will cause the contents to be reloaded.
*/
public TileRenderer(
- @NonNull Context appContext,
+ @NonNull Context uiContext,
@NonNull LayoutElementBuilders.Layout layout,
@NonNull ResourceBuilders.Resources resources,
@NonNull Executor loadActionExecutor,
@NonNull LoadActionListener loadActionListener) {
this(
- appContext,
+ uiContext,
layout,
/* tilesTheme= */ 0,
resources,
@@ -79,7 +79,7 @@
/**
* Default constructor.
*
- * @param appContext The application context.
+ * @param uiContext A {@link Context} suitable for interacting with the UI.
* @param layout The portion of the Tile to render.
* @param tilesTheme The theme to use for this Tile instance. This can be used to customise
* things like the default font family. Pass 0 to use the default theme.
@@ -87,7 +87,7 @@
* @param loadActionListener Listener for clicks that will cause the contents to be reloaded.
*/
public TileRenderer(
- @NonNull Context appContext,
+ @NonNull Context uiContext,
@NonNull LayoutElementBuilders.Layout layout,
@StyleRes int tilesTheme,
@NonNull ResourceBuilders.Resources resources,
@@ -95,9 +95,9 @@
@NonNull LoadActionListener loadActionListener) {
this.mRenderer =
new TileRendererInternal(
- appContext,
+ uiContext,
layout.toProto(),
- StandardResourceResolvers.forLocalApp(resources.toProto(), appContext)
+ StandardResourceResolvers.forLocalApp(resources.toProto(), uiContext)
.build(),
tilesTheme,
loadActionExecutor,
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/DefaultInlineImageResourceResolver.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/DefaultInlineImageResourceResolver.java
index 3f28ec0..9f06df3 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/DefaultInlineImageResourceResolver.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/DefaultInlineImageResourceResolver.java
@@ -38,11 +38,11 @@
public class DefaultInlineImageResourceResolver implements InlineImageResourceResolver {
private static final int RGB565_BYTES_PER_PX = 2;
- private final Context mAppContext;
+ private final Context mUiContext;
/** Constructor. */
- public DefaultInlineImageResourceResolver(@NonNull Context appContext) {
- this.mAppContext = appContext;
+ public DefaultInlineImageResourceResolver(@NonNull Context uiContext) {
+ this.mUiContext = uiContext;
}
@NonNull
@@ -61,9 +61,9 @@
throw new ResourceAccessException("Unsupported image format in image resource.");
}
- // The app Context is correct here, as it's just used for display density, so it doesn't
+ // The UI Context is correct here, as it's just used for display density, so it doesn't
// depend on anything from the provider app.
- return new BitmapDrawable(mAppContext.getResources(), bitmap);
+ return new BitmapDrawable(mUiContext.getResources(), bitmap);
}
@Override
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/StandardResourceResolvers.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/StandardResourceResolvers.java
index 95acaf7..cfcc08f 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/StandardResourceResolvers.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/StandardResourceResolvers.java
@@ -32,16 +32,17 @@
* <p>Use {@code setFooResolver} calls to change the pre-populated ones or add others.
*
* @param protoResources ProtoLayout resources for the current layout.
- * @param appContext Context for the app that both owns the resources and displays the layout.
+ * @param uiContext UI-capable Context for the app that both owns the resources and displays
+ * the layout.
*/
@NonNull
public static ResourceResolvers.Builder forLocalApp(
- @NonNull ResourceProto.Resources protoResources, @NonNull Context appContext) {
+ @NonNull ResourceProto.Resources protoResources, @NonNull Context uiContext) {
DefaultAndroidImageResourceByResIdResolver androidResourceResolver =
- new DefaultAndroidImageResourceByResIdResolver(appContext.getResources());
+ new DefaultAndroidImageResourceByResIdResolver(uiContext.getResources());
DefaultInlineImageResourceResolver inlineResourceResolver =
- new DefaultInlineImageResourceResolver(appContext);
+ new DefaultInlineImageResourceResolver(uiContext);
return ResourceResolvers.builder(protoResources)
.setAndroidImageResourceByResIdResolver(androidResourceResolver)
.setInlineImageResourceResolver(inlineResourceResolver);
@@ -56,19 +57,20 @@
* @param protoResources ProtoLayout resources for the current layout.
* @param servicePackageName Package name for the service that owns the resources.
* @param serviceAndroidResources Android resources from the service.
- * @param hostAppContext Context for the app hosting the renderer displaying the layout.
+ * @param hostUiContext UI-capable Context for the app hosting the renderer displaying the
+ * layout.
*/
@NonNull
public static ResourceResolvers.Builder forRemoteService(
@NonNull ResourceProto.Resources protoResources,
@NonNull String servicePackageName,
@NonNull Resources serviceAndroidResources,
- @NonNull Context hostAppContext) {
+ @NonNull Context hostUiContext) {
DefaultAndroidImageResourceByResIdResolver androidResourceResolver =
new DefaultAndroidImageResourceByResIdResolver(serviceAndroidResources);
DefaultInlineImageResourceResolver inlineResourceResolver =
- new DefaultInlineImageResourceResolver(hostAppContext);
+ new DefaultInlineImageResourceResolver(hostUiContext);
return ResourceResolvers.builder(protoResources)
.setAndroidImageResourceByResIdResolver(androidResourceResolver)
.setInlineImageResourceResolver(inlineResourceResolver);
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/TileRendererInternal.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/TileRendererInternal.java
index b8504a9..647c94a 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/TileRendererInternal.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/internal/TileRendererInternal.java
@@ -40,6 +40,7 @@
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils.TruncateAt;
+import android.text.method.LinkMovementMethod;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
@@ -59,6 +60,7 @@
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
+import android.widget.Scroller;
import android.widget.Space;
import android.widget.TextView;
@@ -168,7 +170,7 @@
// White
private static final int LINE_COLOR_DEFAULT = 0xFFFFFFFF;
- final Context mAppContext;
+ final Context mUiContext;
private final Layout mLayoutProto;
private final ResourceResolvers mResourceResolvers;
@@ -195,20 +197,20 @@
/**
* Default constructor.
*
- * @param appContext The application context.
+ * @param uiContext A {@link Context} suitable for interacting with the UI.
* @param layout The portion of the Tile to render.
* @param resourceResolvers Resolvers for the resources used for rendering this Prototile.
* @param loadActionExecutor Executor to dispatch loadActionListener on.
* @param loadActionListener Listener for clicks that will cause the contents to be reloaded.
*/
public TileRendererInternal(
- @NonNull Context appContext,
+ @NonNull Context uiContext,
@NonNull Layout layout,
@NonNull ResourceResolvers resourceResolvers,
@NonNull Executor loadActionExecutor,
@NonNull LoadActionListener loadActionListener) {
this(
- appContext,
+ uiContext,
layout,
resourceResolvers,
/* tilesTheme= */ 0,
@@ -219,7 +221,7 @@
/**
* Default constructor.
*
- * @param appContext The application context.
+ * @param uiContext A {@link Context} suitable for interacting with the UI.
* @param layout The portion of the Tile to render.
* @param resourceResolvers Resolvers for the resources used for rendering this Prototile.
* @param tilesTheme The theme to use for this Tiles instance. This can be used to customise
@@ -228,7 +230,7 @@
* @param loadActionListener Listener for clicks that will cause the contents to be reloaded.
*/
public TileRendererInternal(
- @NonNull Context appContext,
+ @NonNull Context uiContext,
@NonNull Layout layout,
@NonNull ResourceResolvers resourceResolvers,
@StyleRes int tilesTheme,
@@ -238,15 +240,15 @@
tilesTheme = R.style.TilesBaseTheme;
}
- TypedArray a = appContext.obtainStyledAttributes(tilesTheme, R.styleable.TilesTheme);
+ TypedArray a = uiContext.obtainStyledAttributes(tilesTheme, R.styleable.TilesTheme);
this.mTitleFontSet =
- new FontSet(appContext, a.getResourceId(R.styleable.TilesTheme_tilesTitleFont, -1));
+ new FontSet(uiContext, a.getResourceId(R.styleable.TilesTheme_tilesTitleFont, -1));
this.mBodyFontSet =
- new FontSet(appContext, a.getResourceId(R.styleable.TilesTheme_tilesBodyFont, -1));
+ new FontSet(uiContext, a.getResourceId(R.styleable.TilesTheme_tilesBodyFont, -1));
a.recycle();
- this.mAppContext = new ContextThemeWrapper(appContext, tilesTheme);
+ this.mUiContext = new ContextThemeWrapper(uiContext, tilesTheme);
this.mLayoutProto = layout;
this.mResourceResolvers = resourceResolvers;
this.mLoadActionExecutor = loadActionExecutor;
@@ -255,7 +257,7 @@
private int safeDpToPx(DpProp dpProp) {
return round(
- max(0, dpProp.getValue()) * mAppContext.getResources().getDisplayMetrics().density);
+ max(0, dpProp.getValue()) * mUiContext.getResources().getDisplayMetrics().density);
}
@Nullable
@@ -533,26 +535,18 @@
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
spField.getValue(),
- mAppContext.getResources().getDisplayMetrics());
+ mUiContext.getResources().getDisplayMetrics());
}
private void applyFontStyle(FontStyle style, TextView textView) {
+ // Note: Underline must be applied as a Span to work correctly (as opposed to using
+ // TextPaint#setTextUnderline). This is applied in the caller instead.
+
// Need to supply typefaceStyle when creating the typeface (will select specialist
// bold/italic typefaces), *and* when setting the typeface (will set synthetic bold/italic
// flags in Paint if they're not supported by the given typeface).
textView.setTypeface(createTypeface(style), fontStyleToTypefaceStyle(style));
- int currentPaintFlags = textView.getPaintFlags();
-
- // Remove the bits we're setting
- currentPaintFlags &= ~Paint.UNDERLINE_TEXT_FLAG;
-
- if (style.hasUnderline() && style.getUnderline().getValue()) {
- currentPaintFlags |= Paint.UNDERLINE_TEXT_FLAG;
- }
-
- textView.setPaintFlags(currentPaintFlags);
-
if (style.hasSize()) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, style.getSize().getValue());
}
@@ -579,12 +573,11 @@
}
}
- // Package private to avoid synthetic accessor.
void dispatchLaunchActionIntent(Intent i) {
- ActivityInfo ai = i.resolveActivityInfo(mAppContext.getPackageManager(), /* flags= */ 0);
+ ActivityInfo ai = i.resolveActivityInfo(mUiContext.getPackageManager(), /* flags= */ 0);
if (ai != null && ai.exported && (ai.permission == null || ai.permission.isEmpty())) {
- mAppContext.startActivity(i);
+ mUiContext.startActivity(i);
}
}
@@ -626,13 +619,13 @@
if (hasAction) {
// Apply ripple effect
TypedValue outValue = new TypedValue();
- mAppContext
+ mUiContext
.getTheme()
.resolveAttribute(
android.R.attr.selectableItemBackground,
outValue,
/* resolveRefs= */ true);
- view.setForeground(mAppContext.getDrawable(outValue.resourceId));
+ view.setForeground(mUiContext.getDrawable(outValue.resourceId));
}
}
@@ -860,7 +853,7 @@
return null;
}
- LinearLayout linearLayout = new LinearLayout(mAppContext);
+ LinearLayout linearLayout = new LinearLayout(mUiContext);
linearLayout.setOrientation(LinearLayout.VERTICAL);
LayoutParams layoutParams = generateDefaultLayoutParams();
@@ -887,7 +880,7 @@
return null;
}
- LinearLayout linearLayout = new LinearLayout(mAppContext);
+ LinearLayout linearLayout = new LinearLayout(mUiContext);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams layoutParams = generateDefaultLayoutParams();
@@ -914,7 +907,7 @@
return null;
}
- FrameLayout frame = new FrameLayout(mAppContext);
+ FrameLayout frame = new FrameLayout(mUiContext);
LayoutParams layoutParams = generateDefaultLayoutParams();
@@ -955,7 +948,7 @@
}
if (numMatchParentChildren == 1) {
- Space hackSpace = new Space(mAppContext);
+ Space hackSpace = new Space(mUiContext);
LayoutParams hackSpaceLp =
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
frame.addView(hackSpace, hackSpaceLp);
@@ -979,7 +972,7 @@
// modifiers.
View view;
if (spacer.hasModifiers()) {
- view = applyModifiers(new View(mAppContext), spacer.getModifiers());
+ view = applyModifiers(new View(mUiContext), spacer.getModifiers());
layoutParams =
updateLayoutParams(
parent,
@@ -987,7 +980,7 @@
spacerDimensionToContainerDimension(spacer.getWidth()),
spacerDimensionToContainerDimension(spacer.getHeight()));
} else {
- view = new Space(mAppContext);
+ view = new Space(mUiContext);
view.setMinimumWidth(widthPx);
view.setMinimumHeight(heightPx);
}
@@ -1006,7 +999,7 @@
return null;
}
- WearCurvedSpacer space = new WearCurvedSpacer(mAppContext);
+ WearCurvedSpacer space = new WearCurvedSpacer(mUiContext);
LayoutParams layoutParams = generateDefaultLayoutParams();
@@ -1021,11 +1014,22 @@
private View inflateText(ViewGroup parent, Text text) {
TextView textView =
- new TextView(mAppContext, /* attrs= */ null, R.attr.tilesFallbackTextAppearance);
+ new TextView(mUiContext, /* attrs= */ null, R.attr.tilesFallbackTextAppearance);
LayoutParams layoutParams = generateDefaultLayoutParams();
- textView.setText(text.getText().getValue());
+ // Underlines are applied using a Spannable here, rather than setting paint bits (or using
+ // Paint#setTextUnderline). When multiple fonts are mixed on the same line (especially when
+ // mixing anything with NotoSans-CJK), multiple underlines can appear. Using UnderlineSpan
+ // instead though causes the correct behaviour to happen (only a single underline).
+ SpannableStringBuilder ssb = new SpannableStringBuilder();
+ ssb.append(text.getText().getValue());
+
+ if (text.getFontStyle().getUnderline().getValue()) {
+ ssb.setSpan(new UnderlineSpan(), 0, ssb.length(), Spanned.SPAN_MARK_MARK);
+ }
+
+ textView.setText(ssb);
textView.setEllipsize(textTruncationToEllipsize(text.getOverflow()));
textView.setGravity(textAlignToAndroidGravity(text.getMultilineAlignment()));
@@ -1068,7 +1072,7 @@
private View inflateArcText(ViewGroup parent, ArcText text) {
CurvedTextView textView =
new CurvedTextView(
- mAppContext, /* attrs= */ null, R.attr.tilesFallbackTextAppearance);
+ mUiContext, /* attrs= */ null, R.attr.tilesFallbackTextAppearance);
LayoutParams layoutParams = generateDefaultLayoutParams();
layoutParams.width = LayoutParams.MATCH_PARENT;
@@ -1180,7 +1184,7 @@
return null;
}
- ImageViewWithoutIntrinsicSizes imageView = new ImageViewWithoutIntrinsicSizes(mAppContext);
+ ImageViewWithoutIntrinsicSizes imageView = new ImageViewWithoutIntrinsicSizes(mUiContext);
if (image.hasContentScaleMode()) {
imageView.setScaleType(
@@ -1206,7 +1210,7 @@
imageDimensionToContainerDimension(image.getWidth()),
imageDimensionToContainerDimension(image.getHeight()));
- RatioViewWrapper ratioViewWrapper = new RatioViewWrapper(mAppContext);
+ RatioViewWrapper ratioViewWrapper = new RatioViewWrapper(mUiContext);
ratioViewWrapper.setAspectRatio(ratio);
ratioViewWrapper.addView(imageView);
@@ -1236,7 +1240,7 @@
// Otherwise, handle the result on the UI thread.
drawableFuture.addListener(
() -> setImageDrawable(imageView, drawableFuture, protoResId),
- ContextCompat.getMainExecutor(mAppContext));
+ ContextCompat.getMainExecutor(mUiContext));
}
boolean canImageBeTinted = false;
@@ -1284,7 +1288,7 @@
return null;
}
- WearCurvedLineView lineView = new WearCurvedLineView(mAppContext);
+ WearCurvedLineView lineView = new WearCurvedLineView(mUiContext);
// A ArcLineView must always be the same width/height as its parent, so it can draw the line
// properly inside of those bounds.
@@ -1309,7 +1313,7 @@
@Nullable
private View inflateArc(ViewGroup parent, Arc arc) {
- ArcLayout arcLayout = new ArcLayout(mAppContext);
+ ArcLayout arcLayout = new ArcLayout(mUiContext);
LayoutParams layoutParams = generateDefaultLayoutParams();
layoutParams.width = LayoutParams.MATCH_PARENT;
@@ -1455,7 +1459,7 @@
// Update the TextView.
textView.setText(builder);
},
- ContextCompat.getMainExecutor(mAppContext));
+ ContextCompat.getMainExecutor(mUiContext));
}
return builder;
@@ -1512,21 +1516,32 @@
private View inflateSpannable(ViewGroup parent, Spannable spannable) {
TextView tv =
- new TextView(mAppContext, /* attrs= */ null, R.attr.tilesFallbackTextAppearance);
+ new TextView(mUiContext, /* attrs= */ null, R.attr.tilesFallbackTextAppearance);
LayoutParams layoutParams = generateDefaultLayoutParams();
SpannableStringBuilder builder = new SpannableStringBuilder();
+ boolean isAnySpanClickable = false;
for (Span element : spannable.getSpansList()) {
switch (element.getInnerCase()) {
case IMAGE:
SpanImage protoImage = element.getImage();
builder = inflateImageInSpannable(builder, protoImage, tv);
+
+ if (protoImage.getModifiers().hasClickable()) {
+ isAnySpanClickable = true;
+ }
+
break;
case TEXT:
SpanText protoText = element.getText();
builder = inflateTextInSpannable(builder, protoText);
+
+ if (protoText.getModifiers().hasClickable()) {
+ isAnySpanClickable = true;
+ }
+
break;
default:
Log.w(TAG, "Unknown Span child type.");
@@ -1569,8 +1584,23 @@
tv.setText(builder);
+ if (isAnySpanClickable) {
+ // For any ClickableSpans to work, the MovementMethod must be set to LinkMovementMethod.
+ tv.setMovementMethod(LinkMovementMethod.getInstance());
+
+ // Disable the highlight color; if we don't do this, the clicked span will get
+ // highlighted, which will be cleared half a second later if using LoadAction as the
+ // next layout will be delivered, which recreates the elements and clears the highlight.
+ tv.setHighlightColor(Color.TRANSPARENT);
+
+ // Use InhibitingScroller to prevent the text from scrolling when tapped. Setting a
+ // MovementMethod on a TextView (e.g. for clickables in a Spannable) then cause the
+ // TextView to be scrollable, and to jump to the end when tapped.
+ tv.setScroller(new InhibitingScroller(mUiContext));
+ }
+
View wrappedView = applyModifiers(tv, spannable.getModifiers());
- parent.addView(applyModifiers(tv, spannable.getModifiers()), layoutParams);
+ parent.addView(wrappedView, layoutParams);
return wrappedView;
}
@@ -1959,4 +1989,17 @@
}
}
}
+
+ /** Implementation of {@link Scroller} which inhibits all scrolling. */
+ private static class InhibitingScroller extends Scroller {
+ InhibitingScroller(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void startScroll(int startX, int startY, int dx, int dy) {}
+
+ @Override
+ public void startScroll(int startX, int startY, int dx, int dy, int duration) {}
+ }
}
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/renderer/internal/TileRendererInternalTest.java b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/renderer/internal/TileRendererInternalTest.java
index 56d3e02..720732c 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/renderer/internal/TileRendererInternalTest.java
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/renderer/internal/TileRendererInternalTest.java
@@ -29,6 +29,8 @@
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.Looper;
+import android.os.SystemClock;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
@@ -84,6 +86,7 @@
import androidx.wear.tiles.proto.ModifiersProto.Modifiers;
import androidx.wear.tiles.proto.ModifiersProto.Padding;
import androidx.wear.tiles.proto.ModifiersProto.Semantics;
+import androidx.wear.tiles.proto.ModifiersProto.SpanModifiers;
import androidx.wear.tiles.proto.ResourceProto.AndroidImageResourceByResId;
import androidx.wear.tiles.proto.ResourceProto.ImageResource;
import androidx.wear.tiles.proto.ResourceProto.Resources;
@@ -103,6 +106,8 @@
import org.robolectric.shadows.ShadowPackageManager;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
@RunWith(TilesTestRunner.class)
@@ -1137,6 +1142,60 @@
}
@Test
+ public void inflate_spannable_onClickCanFire() {
+ LayoutElement root = LayoutElement.newBuilder()
+ .setSpannable(Spannable.newBuilder()
+ .addSpans(Span.newBuilder()
+ .setText(SpanText.newBuilder()
+ .setText(StringProp.newBuilder()
+ .setValue("Hello World"))
+ .setModifiers(SpanModifiers.newBuilder()
+ .setClickable(Clickable.newBuilder()
+ .setOnClick(Action.newBuilder()
+ .setLoadAction(LoadAction
+ .getDefaultInstance())))))))
+ .build();
+
+ List<Boolean> hasFiredList = new ArrayList<>();
+ FrameLayout rootLayout =
+ inflateProto(
+ root,
+ /* theme= */0,
+ resourceResolvers(),
+ p -> hasFiredList.add(true));
+
+ TextView tv = (TextView) rootLayout.getChildAt(0);
+
+ // Dispatch a click event to the first View; it should trigger the LoadAction...
+ long startTime = SystemClock.uptimeMillis();
+ MotionEvent evt =
+ MotionEvent.obtain(
+ /* downTime= */ startTime,
+ /* eventTime= */ startTime,
+ MotionEvent.ACTION_DOWN,
+ /* x= */ 5f,
+ /* y= */ 5f,
+ /* metaState= */ 0);
+ tv.dispatchTouchEvent(evt);
+ evt.recycle();
+
+ evt =
+ MotionEvent.obtain(
+ /* downTime= */ startTime,
+ /* eventTime= */ startTime + 100,
+ MotionEvent.ACTION_UP,
+ /* x= */ 5f,
+ /* y= */ 5f,
+ /* metaState= */ 0);
+ tv.dispatchTouchEvent(evt);
+ evt.recycle();
+
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(hasFiredList).hasSize(1);
+ }
+
+ @Test
public void inflate_image_intrinsicSizeIsIgnored() {
LayoutElement root = LayoutElement.newBuilder()
.setBox(Box.newBuilder()
diff --git a/wear/tiles/tiles-renderer/src/test/resources/robolectric.properties b/wear/tiles/tiles-renderer/src/test/resources/robolectric.properties
index 2fd61aa..55de435 100644
--- a/wear/tiles/tiles-renderer/src/test/resources/robolectric.properties
+++ b/wear/tiles/tiles-renderer/src/test/resources/robolectric.properties
@@ -14,6 +14,6 @@
# limitations under the License.
#
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/wear/tiles/tiles-testing/build.gradle b/wear/tiles/tiles-testing/build.gradle
index 526dbc2..15fa1d3 100644
--- a/wear/tiles/tiles-testing/build.gradle
+++ b/wear/tiles/tiles-testing/build.gradle
@@ -53,7 +53,6 @@
android {
defaultConfig {
minSdkVersion 26
- targetSdkVersion 29
}
// Use Robolectric 4.+
diff --git a/wear/tiles/tiles-testing/src/test/resources/robolectric.properties b/wear/tiles/tiles-testing/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..df424a9
--- /dev/null
+++ b/wear/tiles/tiles-testing/src/test/resources/robolectric.properties
@@ -0,0 +1,20 @@
+#
+# Copyright 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
+# sdk for now. Remove when no longer necessary.
+sdk=30
+
diff --git a/wear/tiles/tiles/src/test/resources/robolectric.properties b/wear/tiles/tiles/src/test/resources/robolectric.properties
index 2fd61aa..df424a9 100644
--- a/wear/tiles/tiles/src/test/resources/robolectric.properties
+++ b/wear/tiles/tiles/src/test/resources/robolectric.properties
@@ -14,6 +14,7 @@
# limitations under the License.
#
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
+
diff --git a/wear/wear-complications-data-source-ktx/src/test/resources/robolectric.properties b/wear/wear-complications-data-source-ktx/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..aedfc83
--- /dev/null
+++ b/wear/wear-complications-data-source-ktx/src/test/resources/robolectric.properties
@@ -0,0 +1,20 @@
+#
+# Copyright 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Robolectric currently doesn't support API 31, so we have to explicitly specify the target sdk
+# levels for now.
+# TODO(b/177072877): Remove when no longer necessary.
+sdk=30
diff --git a/wear/wear-complications-data-source-samples/src/main/java/androidx/wear/complications/datasource/samples/BackgroundDataSourceService.kt b/wear/wear-complications-data-source-samples/src/main/java/androidx/wear/complications/datasource/samples/BackgroundDataSourceService.kt
index 9125e9f..928a337 100644
--- a/wear/wear-complications-data-source-samples/src/main/java/androidx/wear/complications/datasource/samples/BackgroundDataSourceService.kt
+++ b/wear/wear-complications-data-source-samples/src/main/java/androidx/wear/complications/datasource/samples/BackgroundDataSourceService.kt
@@ -39,7 +39,7 @@
override fun onCreate() {
if (updateRequester == null) {
- updateRequester = ComplicationDataSourceUpdateRequester(
+ updateRequester = ComplicationDataSourceUpdateRequester.create(
this,
ComponentName(this, BackgroundDataSourceService::class.java)
)
diff --git a/wear/wear-complications-data-source/api/current.txt b/wear/wear-complications-data-source/api/current.txt
index 0a2c756..fec91f0 100644
--- a/wear/wear-complications-data-source/api/current.txt
+++ b/wear/wear-complications-data-source/api/current.txt
@@ -27,14 +27,15 @@
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public void onComplicationData(androidx.wear.complications.data.ComplicationData? complicationData) throws android.os.RemoteException;
}
- public final class ComplicationDataSourceUpdateRequester {
- ctor public ComplicationDataSourceUpdateRequester(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
+ public interface ComplicationDataSourceUpdateRequester {
+ method public default static androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester create(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
method public void requestUpdate(int... complicationInstanceIds);
method public void requestUpdateAll();
field public static final androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester.Companion Companion;
}
public static final class ComplicationDataSourceUpdateRequester.Companion {
+ method public androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester create(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
}
public final class ComplicationRequest {
diff --git a/wear/wear-complications-data-source/api/public_plus_experimental_current.txt b/wear/wear-complications-data-source/api/public_plus_experimental_current.txt
index 0a2c756..fec91f0 100644
--- a/wear/wear-complications-data-source/api/public_plus_experimental_current.txt
+++ b/wear/wear-complications-data-source/api/public_plus_experimental_current.txt
@@ -27,14 +27,15 @@
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public void onComplicationData(androidx.wear.complications.data.ComplicationData? complicationData) throws android.os.RemoteException;
}
- public final class ComplicationDataSourceUpdateRequester {
- ctor public ComplicationDataSourceUpdateRequester(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
+ public interface ComplicationDataSourceUpdateRequester {
+ method public default static androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester create(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
method public void requestUpdate(int... complicationInstanceIds);
method public void requestUpdateAll();
field public static final androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester.Companion Companion;
}
public static final class ComplicationDataSourceUpdateRequester.Companion {
+ method public androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester create(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
}
public final class ComplicationRequest {
diff --git a/wear/wear-complications-data-source/api/restricted_current.txt b/wear/wear-complications-data-source/api/restricted_current.txt
index cfb545e..df3765a 100644
--- a/wear/wear-complications-data-source/api/restricted_current.txt
+++ b/wear/wear-complications-data-source/api/restricted_current.txt
@@ -27,8 +27,8 @@
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public void onComplicationData(androidx.wear.complications.data.ComplicationData? complicationData) throws android.os.RemoteException;
}
- public final class ComplicationDataSourceUpdateRequester {
- ctor public ComplicationDataSourceUpdateRequester(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
+ public interface ComplicationDataSourceUpdateRequester {
+ method public default static androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester create(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
method public void requestUpdate(int... complicationInstanceIds);
method public void requestUpdateAll();
field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String ACTION_REQUEST_UPDATE = "android.support.wearable.complications.ACTION_REQUEST_UPDATE";
@@ -36,9 +36,16 @@
field public static final androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester.Companion Companion;
field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String EXTRA_COMPLICATION_IDS = "android.support.wearable.complications.EXTRA_COMPLICATION_IDS";
field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String EXTRA_PROVIDER_COMPONENT = "android.support.wearable.complications.EXTRA_PROVIDER_COMPONENT";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String UPDATE_REQUEST_RECEIVER_PACKAGE = "com.google.android.wearable.app";
}
public static final class ComplicationDataSourceUpdateRequester.Companion {
+ method public androidx.wear.complications.datasource.ComplicationDataSourceUpdateRequester create(android.content.Context context, android.content.ComponentName complicationDataSourceComponent);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String ACTION_REQUEST_UPDATE = "android.support.wearable.complications.ACTION_REQUEST_UPDATE";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String ACTION_REQUEST_UPDATE_ALL = "android.support.wearable.complications.ACTION_REQUEST_UPDATE_ALL";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String EXTRA_COMPLICATION_IDS = "android.support.wearable.complications.EXTRA_COMPLICATION_IDS";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String EXTRA_PROVIDER_COMPONENT = "android.support.wearable.complications.EXTRA_PROVIDER_COMPONENT";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String UPDATE_REQUEST_RECEIVER_PACKAGE = "com.google.android.wearable.app";
}
public final class ComplicationRequest {
diff --git a/wear/wear-complications-data-source/src/main/java/androidx/wear/complications/datasource/ComplicationDataSourceUpdateRequester.kt b/wear/wear-complications-data-source/src/main/java/androidx/wear/complications/datasource/ComplicationDataSourceUpdateRequester.kt
index 0d03066..48d30d9 100644
--- a/wear/wear-complications-data-source/src/main/java/androidx/wear/complications/datasource/ComplicationDataSourceUpdateRequester.kt
+++ b/wear/wear-complications-data-source/src/main/java/androidx/wear/complications/datasource/ComplicationDataSourceUpdateRequester.kt
@@ -27,37 +27,19 @@
* Allows complication complication data source to request update calls from the system. This
* effectively allows complication data source to push updates to the system outside of the update
* request cycle.
- *
- * @param context The [ComplicationDataSourceService]'s [Context]
- * @param complicationDataSourceComponent The [ComponentName] of the ComplicationDataSourceService]
- * to reload.
*/
-public class ComplicationDataSourceUpdateRequester(
- private val context: Context,
- private val complicationDataSourceComponent: ComponentName
-) {
+public interface ComplicationDataSourceUpdateRequester {
/**
* Requests that the system call
* [onComplicationUpdate][ComplicationDataSourceService.onComplicationRequest] on the specified
* complication data source, for all active complications using that complication data source.
*
* This will do nothing if no active complications are configured to use the specified
- * omplication data source.
+ * complication data source.
*
* This will also only work if called from the same package as the omplication data source.
*/
- @SuppressLint("PendingIntentMutability")
- public fun requestUpdateAll() {
- val intent = Intent(ACTION_REQUEST_UPDATE_ALL)
- intent.setPackage(UPDATE_REQUEST_RECEIVER_PACKAGE)
- intent.putExtra(EXTRA_PROVIDER_COMPONENT, complicationDataSourceComponent)
- // Add a placeholder PendingIntent to allow the UID to be checked.
- intent.putExtra(
- ComplicationDataSourceUpdateRequesterConstants.EXTRA_PENDING_INTENT,
- PendingIntent.getActivity(context, 0, Intent(""), 0)
- )
- context.sendBroadcast(intent)
- }
+ public fun requestUpdateAll()
/**
* Requests that the system call
@@ -69,12 +51,71 @@
* provided to [ComplicationDataSourceService.onComplicationActivated] and
* [ComplicationDataSourceService.onComplicationRequest].
*/
+ public fun requestUpdate(vararg complicationInstanceIds: Int)
+
+ public companion object {
+ /**
+ * The package of the service that accepts complication data source requests.
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public const val UPDATE_REQUEST_RECEIVER_PACKAGE = "com.google.android.wearable.app"
+
+ /**
+ * Creates a [ComplicationDataSourceUpdateRequester].
+ *
+ * @param context The [ComplicationDataSourceService]'s [Context]
+ * @param complicationDataSourceComponent The [ComponentName] of the
+ * [ComplicationDataSourceService] to reload.
+ * @return The constructed [ComplicationDataSourceUpdateRequester].
+ */
+ @JvmStatic
+ public fun create(
+ context: Context,
+ complicationDataSourceComponent: ComponentName
+ ): ComplicationDataSourceUpdateRequester =
+ ComplicationDataSourceUpdateRequesterImpl(context, complicationDataSourceComponent)
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public const val ACTION_REQUEST_UPDATE: String =
+ "android.support.wearable.complications.ACTION_REQUEST_UPDATE"
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public const val ACTION_REQUEST_UPDATE_ALL: String =
+ "android.support.wearable.complications.ACTION_REQUEST_UPDATE_ALL"
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public const val EXTRA_PROVIDER_COMPONENT: String =
+ "android.support.wearable.complications.EXTRA_PROVIDER_COMPONENT"
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public const val EXTRA_COMPLICATION_IDS: String =
+ "android.support.wearable.complications.EXTRA_COMPLICATION_IDS"
+ }
+}
+
+/**
+ * @param context The [ComplicationDataSourceService]'s [Context]
+ * @param complicationDataSourceComponent The [ComponentName] of the ComplicationDataSourceService]
+ * to reload.
+ */
+private class ComplicationDataSourceUpdateRequesterImpl(
+ private val context: Context,
+ private val complicationDataSourceComponent: ComponentName
+) : ComplicationDataSourceUpdateRequester {
+
@SuppressLint("PendingIntentMutability")
- public fun requestUpdate(vararg complicationInstanceIds: Int) {
- val intent = Intent(ACTION_REQUEST_UPDATE)
- intent.setPackage(UPDATE_REQUEST_RECEIVER_PACKAGE)
- intent.putExtra(EXTRA_PROVIDER_COMPONENT, complicationDataSourceComponent)
- intent.putExtra(EXTRA_COMPLICATION_IDS, complicationInstanceIds)
+ override fun requestUpdateAll() {
+ val intent = Intent(ComplicationDataSourceUpdateRequester.ACTION_REQUEST_UPDATE_ALL)
+ intent.setPackage(ComplicationDataSourceUpdateRequester.UPDATE_REQUEST_RECEIVER_PACKAGE)
+ intent.putExtra(
+ ComplicationDataSourceUpdateRequester.EXTRA_PROVIDER_COMPONENT,
+ complicationDataSourceComponent
+ )
// Add a placeholder PendingIntent to allow the UID to be checked.
intent.putExtra(
ComplicationDataSourceUpdateRequesterConstants.EXTRA_PENDING_INTENT,
@@ -83,32 +124,23 @@
context.sendBroadcast(intent)
}
- public companion object {
- /** The package of the service that accepts complication data source requests. */
- private const val UPDATE_REQUEST_RECEIVER_PACKAGE = "com.google.android.wearable.app"
-
- /** @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public const val ACTION_REQUEST_UPDATE: String =
- "android.support.wearable.complications.ACTION_REQUEST_UPDATE"
-
- /** @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public const val ACTION_REQUEST_UPDATE_ALL: String =
- "android.support.wearable.complications.ACTION_REQUEST_UPDATE_ALL"
-
- /** @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public const val EXTRA_PROVIDER_COMPONENT: String =
- "android.support.wearable.complications.EXTRA_PROVIDER_COMPONENT"
-
- /** @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public const val EXTRA_COMPLICATION_IDS: String =
- "android.support.wearable.complications.EXTRA_COMPLICATION_IDS"
+ @SuppressLint("PendingIntentMutability")
+ override fun requestUpdate(vararg complicationInstanceIds: Int) {
+ val intent = Intent(ComplicationDataSourceUpdateRequester.ACTION_REQUEST_UPDATE)
+ intent.setPackage(ComplicationDataSourceUpdateRequester.UPDATE_REQUEST_RECEIVER_PACKAGE)
+ intent.putExtra(
+ ComplicationDataSourceUpdateRequester.EXTRA_PROVIDER_COMPONENT,
+ complicationDataSourceComponent
+ )
+ intent.putExtra(
+ ComplicationDataSourceUpdateRequester.EXTRA_COMPLICATION_IDS,
+ complicationInstanceIds
+ )
+ // Add a placeholder PendingIntent to allow the UID to be checked.
+ intent.putExtra(
+ ComplicationDataSourceUpdateRequesterConstants.EXTRA_PENDING_INTENT,
+ PendingIntent.getActivity(context, 0, Intent(""), 0)
+ )
+ context.sendBroadcast(intent)
}
}
diff --git a/wear/wear-complications-data-source/src/test/resources/robolectric.properties b/wear/wear-complications-data-source/src/test/resources/robolectric.properties
index ce87047..ab64ba7 100644
--- a/wear/wear-complications-data-source/src/test/resources/robolectric.properties
+++ b/wear/wear-complications-data-source/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/wear/wear-input/src/test/resources/robolectric.properties b/wear/wear-input/src/test/resources/robolectric.properties
index 8df5ac5..3c2e5f0 100644
--- a/wear/wear-input/src/test/resources/robolectric.properties
+++ b/wear/wear-input/src/test/resources/robolectric.properties
@@ -14,7 +14,7 @@
# limitations under the License.
#
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 28 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 28 as the target
# sdk for now.
# TODO(b/177072877) Remove when no longer necessary.
-sdk=28
+sdk=30
diff --git a/wear/wear-phone-interactions/api/1.0.0-beta01.txt b/wear/wear-phone-interactions/api/1.0.0-beta01.txt
new file mode 100644
index 0000000..bff73eca
--- /dev/null
+++ b/wear/wear-phone-interactions/api/1.0.0-beta01.txt
@@ -0,0 +1,146 @@
+// Signature format: 4.0
+package androidx.wear.phone.interactions {
+
+ public final class PhoneTypeHelper {
+ method public static int getPhoneDeviceType(android.content.Context context);
+ field public static final androidx.wear.phone.interactions.PhoneTypeHelper.Companion Companion;
+ field public static final int DEVICE_TYPE_ANDROID = 1; // 0x1
+ field public static final int DEVICE_TYPE_ERROR = 0; // 0x0
+ field public static final int DEVICE_TYPE_IOS = 2; // 0x2
+ field public static final int DEVICE_TYPE_UNKNOWN = 3; // 0x3
+ }
+
+ public static final class PhoneTypeHelper.Companion {
+ method public int getPhoneDeviceType(android.content.Context context);
+ }
+
+}
+
+package androidx.wear.phone.interactions.authentication {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeChallenge {
+ ctor public CodeChallenge(androidx.wear.phone.interactions.authentication.CodeVerifier codeVerifier);
+ method public String getValue();
+ property public final String value;
+ }
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeVerifier {
+ ctor public CodeVerifier(optional int byteLength);
+ ctor public CodeVerifier(String value);
+ method public String getValue();
+ property public final String value;
+ }
+
+ public final class OAuthRequest {
+ method public String getPackageName();
+ method public android.net.Uri getRequestUrl();
+ property public final String packageName;
+ property public final android.net.Uri requestUrl;
+ field public static final androidx.wear.phone.interactions.authentication.OAuthRequest.Companion Companion;
+ field public static final String WEAR_REDIRECT_URL_PREFIX = "https://wear.googleapis.com/3p_auth/";
+ field public static final String WEAR_REDIRECT_URL_PREFIX_CN = "https://wear.googleapis-cn.com/3p_auth/";
+ }
+
+ public static final class OAuthRequest.Builder {
+ ctor public OAuthRequest.Builder(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.wear.phone.interactions.authentication.OAuthRequest build();
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setAuthProviderUrl(android.net.Uri authProviderUrl);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setClientId(String clientId);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setCodeChallenge(androidx.wear.phone.interactions.authentication.CodeChallenge codeChallenge);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setRedirectUrl(android.net.Uri redirectUrl);
+ }
+
+ public static final class OAuthRequest.Companion {
+ }
+
+ public final class OAuthResponse {
+ method public int getErrorCode();
+ method public android.net.Uri? getResponseUrl();
+ property public final int errorCode;
+ property public final android.net.Uri? responseUrl;
+ }
+
+ public static final class OAuthResponse.Builder {
+ ctor public OAuthResponse.Builder();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse build();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setErrorCode(int errorCode);
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setResponseUrl(android.net.Uri responseUrl);
+ }
+
+ public final class RemoteAuthClient implements java.lang.AutoCloseable {
+ method @UiThread public void close();
+ method public static androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ method protected void finalize();
+ method @UiThread public void sendAuthorizationRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, java.util.concurrent.Executor executor, androidx.wear.phone.interactions.authentication.RemoteAuthClient.Callback clientCallback);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthClient.Companion Companion;
+ field public static final int ERROR_PHONE_UNAVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNSUPPORTED = 0; // 0x0
+ field public static final int NO_ERROR = -1; // 0xffffffff
+ }
+
+ public abstract static class RemoteAuthClient.Callback {
+ ctor public RemoteAuthClient.Callback();
+ method @UiThread public abstract void onAuthorizationError(androidx.wear.phone.interactions.authentication.OAuthRequest request, int errorCode);
+ method @UiThread public abstract void onAuthorizationResponse(androidx.wear.phone.interactions.authentication.OAuthRequest request, androidx.wear.phone.interactions.authentication.OAuthResponse response);
+ }
+
+ public static final class RemoteAuthClient.Companion {
+ method public androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ }
+
+ public interface RemoteAuthRequestHandler {
+ method public boolean isAuthSupported();
+ method public void sendAuthRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+ public abstract class RemoteAuthService extends android.app.Service {
+ ctor public RemoteAuthService();
+ method protected final android.os.IBinder onBind(android.content.Intent intent, androidx.wear.phone.interactions.authentication.RemoteAuthRequestHandler remoteAuthRequestHandler);
+ method public static final void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ method protected boolean verifyPackageName(android.content.Context context, String? requestPackageName);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthService.Companion Companion;
+ }
+
+ public static final class RemoteAuthService.Companion {
+ method public void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+}
+
+package androidx.wear.phone.interactions.notifications {
+
+ public final class BridgingConfig {
+ method public java.util.Set<java.lang.String>? getExcludedTags();
+ method public boolean isBridgingEnabled();
+ property public final java.util.Set<java.lang.String>? excludedTags;
+ property public final boolean isBridgingEnabled;
+ }
+
+ public static final class BridgingConfig.Builder {
+ ctor public BridgingConfig.Builder(android.content.Context context, boolean isBridgingEnabled);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTag(String tag);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTags(java.util.Collection<java.lang.String> tags);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig build();
+ }
+
+ public fun interface BridgingConfigurationHandler {
+ method public void applyBridgingConfiguration(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ }
+
+ public final class BridgingManager {
+ method public static androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ method public void setConfig(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ field public static final androidx.wear.phone.interactions.notifications.BridgingManager.Companion Companion;
+ }
+
+ public static final class BridgingManager.Companion {
+ method public androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ }
+
+ public final class BridgingManagerService extends android.app.Service {
+ ctor public BridgingManagerService(android.content.Context context, androidx.wear.phone.interactions.notifications.BridgingConfigurationHandler bridgingConfigurationHandler);
+ method public android.os.IBinder? onBind(android.content.Intent? intent);
+ }
+
+}
+
diff --git a/wear/wear-phone-interactions/api/1.0.0-beta02.txt b/wear/wear-phone-interactions/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..bff73eca
--- /dev/null
+++ b/wear/wear-phone-interactions/api/1.0.0-beta02.txt
@@ -0,0 +1,146 @@
+// Signature format: 4.0
+package androidx.wear.phone.interactions {
+
+ public final class PhoneTypeHelper {
+ method public static int getPhoneDeviceType(android.content.Context context);
+ field public static final androidx.wear.phone.interactions.PhoneTypeHelper.Companion Companion;
+ field public static final int DEVICE_TYPE_ANDROID = 1; // 0x1
+ field public static final int DEVICE_TYPE_ERROR = 0; // 0x0
+ field public static final int DEVICE_TYPE_IOS = 2; // 0x2
+ field public static final int DEVICE_TYPE_UNKNOWN = 3; // 0x3
+ }
+
+ public static final class PhoneTypeHelper.Companion {
+ method public int getPhoneDeviceType(android.content.Context context);
+ }
+
+}
+
+package androidx.wear.phone.interactions.authentication {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeChallenge {
+ ctor public CodeChallenge(androidx.wear.phone.interactions.authentication.CodeVerifier codeVerifier);
+ method public String getValue();
+ property public final String value;
+ }
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeVerifier {
+ ctor public CodeVerifier(optional int byteLength);
+ ctor public CodeVerifier(String value);
+ method public String getValue();
+ property public final String value;
+ }
+
+ public final class OAuthRequest {
+ method public String getPackageName();
+ method public android.net.Uri getRequestUrl();
+ property public final String packageName;
+ property public final android.net.Uri requestUrl;
+ field public static final androidx.wear.phone.interactions.authentication.OAuthRequest.Companion Companion;
+ field public static final String WEAR_REDIRECT_URL_PREFIX = "https://wear.googleapis.com/3p_auth/";
+ field public static final String WEAR_REDIRECT_URL_PREFIX_CN = "https://wear.googleapis-cn.com/3p_auth/";
+ }
+
+ public static final class OAuthRequest.Builder {
+ ctor public OAuthRequest.Builder(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.wear.phone.interactions.authentication.OAuthRequest build();
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setAuthProviderUrl(android.net.Uri authProviderUrl);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setClientId(String clientId);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setCodeChallenge(androidx.wear.phone.interactions.authentication.CodeChallenge codeChallenge);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setRedirectUrl(android.net.Uri redirectUrl);
+ }
+
+ public static final class OAuthRequest.Companion {
+ }
+
+ public final class OAuthResponse {
+ method public int getErrorCode();
+ method public android.net.Uri? getResponseUrl();
+ property public final int errorCode;
+ property public final android.net.Uri? responseUrl;
+ }
+
+ public static final class OAuthResponse.Builder {
+ ctor public OAuthResponse.Builder();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse build();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setErrorCode(int errorCode);
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setResponseUrl(android.net.Uri responseUrl);
+ }
+
+ public final class RemoteAuthClient implements java.lang.AutoCloseable {
+ method @UiThread public void close();
+ method public static androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ method protected void finalize();
+ method @UiThread public void sendAuthorizationRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, java.util.concurrent.Executor executor, androidx.wear.phone.interactions.authentication.RemoteAuthClient.Callback clientCallback);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthClient.Companion Companion;
+ field public static final int ERROR_PHONE_UNAVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNSUPPORTED = 0; // 0x0
+ field public static final int NO_ERROR = -1; // 0xffffffff
+ }
+
+ public abstract static class RemoteAuthClient.Callback {
+ ctor public RemoteAuthClient.Callback();
+ method @UiThread public abstract void onAuthorizationError(androidx.wear.phone.interactions.authentication.OAuthRequest request, int errorCode);
+ method @UiThread public abstract void onAuthorizationResponse(androidx.wear.phone.interactions.authentication.OAuthRequest request, androidx.wear.phone.interactions.authentication.OAuthResponse response);
+ }
+
+ public static final class RemoteAuthClient.Companion {
+ method public androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ }
+
+ public interface RemoteAuthRequestHandler {
+ method public boolean isAuthSupported();
+ method public void sendAuthRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+ public abstract class RemoteAuthService extends android.app.Service {
+ ctor public RemoteAuthService();
+ method protected final android.os.IBinder onBind(android.content.Intent intent, androidx.wear.phone.interactions.authentication.RemoteAuthRequestHandler remoteAuthRequestHandler);
+ method public static final void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ method protected boolean verifyPackageName(android.content.Context context, String? requestPackageName);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthService.Companion Companion;
+ }
+
+ public static final class RemoteAuthService.Companion {
+ method public void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+}
+
+package androidx.wear.phone.interactions.notifications {
+
+ public final class BridgingConfig {
+ method public java.util.Set<java.lang.String>? getExcludedTags();
+ method public boolean isBridgingEnabled();
+ property public final java.util.Set<java.lang.String>? excludedTags;
+ property public final boolean isBridgingEnabled;
+ }
+
+ public static final class BridgingConfig.Builder {
+ ctor public BridgingConfig.Builder(android.content.Context context, boolean isBridgingEnabled);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTag(String tag);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTags(java.util.Collection<java.lang.String> tags);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig build();
+ }
+
+ public fun interface BridgingConfigurationHandler {
+ method public void applyBridgingConfiguration(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ }
+
+ public final class BridgingManager {
+ method public static androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ method public void setConfig(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ field public static final androidx.wear.phone.interactions.notifications.BridgingManager.Companion Companion;
+ }
+
+ public static final class BridgingManager.Companion {
+ method public androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ }
+
+ public final class BridgingManagerService extends android.app.Service {
+ ctor public BridgingManagerService(android.content.Context context, androidx.wear.phone.interactions.notifications.BridgingConfigurationHandler bridgingConfigurationHandler);
+ method public android.os.IBinder? onBind(android.content.Intent? intent);
+ }
+
+}
+
diff --git a/wear/wear-phone-interactions/api/public_plus_experimental_1.0.0-beta01.txt b/wear/wear-phone-interactions/api/public_plus_experimental_1.0.0-beta01.txt
new file mode 100644
index 0000000..bff73eca
--- /dev/null
+++ b/wear/wear-phone-interactions/api/public_plus_experimental_1.0.0-beta01.txt
@@ -0,0 +1,146 @@
+// Signature format: 4.0
+package androidx.wear.phone.interactions {
+
+ public final class PhoneTypeHelper {
+ method public static int getPhoneDeviceType(android.content.Context context);
+ field public static final androidx.wear.phone.interactions.PhoneTypeHelper.Companion Companion;
+ field public static final int DEVICE_TYPE_ANDROID = 1; // 0x1
+ field public static final int DEVICE_TYPE_ERROR = 0; // 0x0
+ field public static final int DEVICE_TYPE_IOS = 2; // 0x2
+ field public static final int DEVICE_TYPE_UNKNOWN = 3; // 0x3
+ }
+
+ public static final class PhoneTypeHelper.Companion {
+ method public int getPhoneDeviceType(android.content.Context context);
+ }
+
+}
+
+package androidx.wear.phone.interactions.authentication {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeChallenge {
+ ctor public CodeChallenge(androidx.wear.phone.interactions.authentication.CodeVerifier codeVerifier);
+ method public String getValue();
+ property public final String value;
+ }
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeVerifier {
+ ctor public CodeVerifier(optional int byteLength);
+ ctor public CodeVerifier(String value);
+ method public String getValue();
+ property public final String value;
+ }
+
+ public final class OAuthRequest {
+ method public String getPackageName();
+ method public android.net.Uri getRequestUrl();
+ property public final String packageName;
+ property public final android.net.Uri requestUrl;
+ field public static final androidx.wear.phone.interactions.authentication.OAuthRequest.Companion Companion;
+ field public static final String WEAR_REDIRECT_URL_PREFIX = "https://wear.googleapis.com/3p_auth/";
+ field public static final String WEAR_REDIRECT_URL_PREFIX_CN = "https://wear.googleapis-cn.com/3p_auth/";
+ }
+
+ public static final class OAuthRequest.Builder {
+ ctor public OAuthRequest.Builder(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.wear.phone.interactions.authentication.OAuthRequest build();
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setAuthProviderUrl(android.net.Uri authProviderUrl);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setClientId(String clientId);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setCodeChallenge(androidx.wear.phone.interactions.authentication.CodeChallenge codeChallenge);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setRedirectUrl(android.net.Uri redirectUrl);
+ }
+
+ public static final class OAuthRequest.Companion {
+ }
+
+ public final class OAuthResponse {
+ method public int getErrorCode();
+ method public android.net.Uri? getResponseUrl();
+ property public final int errorCode;
+ property public final android.net.Uri? responseUrl;
+ }
+
+ public static final class OAuthResponse.Builder {
+ ctor public OAuthResponse.Builder();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse build();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setErrorCode(int errorCode);
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setResponseUrl(android.net.Uri responseUrl);
+ }
+
+ public final class RemoteAuthClient implements java.lang.AutoCloseable {
+ method @UiThread public void close();
+ method public static androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ method protected void finalize();
+ method @UiThread public void sendAuthorizationRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, java.util.concurrent.Executor executor, androidx.wear.phone.interactions.authentication.RemoteAuthClient.Callback clientCallback);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthClient.Companion Companion;
+ field public static final int ERROR_PHONE_UNAVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNSUPPORTED = 0; // 0x0
+ field public static final int NO_ERROR = -1; // 0xffffffff
+ }
+
+ public abstract static class RemoteAuthClient.Callback {
+ ctor public RemoteAuthClient.Callback();
+ method @UiThread public abstract void onAuthorizationError(androidx.wear.phone.interactions.authentication.OAuthRequest request, int errorCode);
+ method @UiThread public abstract void onAuthorizationResponse(androidx.wear.phone.interactions.authentication.OAuthRequest request, androidx.wear.phone.interactions.authentication.OAuthResponse response);
+ }
+
+ public static final class RemoteAuthClient.Companion {
+ method public androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ }
+
+ public interface RemoteAuthRequestHandler {
+ method public boolean isAuthSupported();
+ method public void sendAuthRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+ public abstract class RemoteAuthService extends android.app.Service {
+ ctor public RemoteAuthService();
+ method protected final android.os.IBinder onBind(android.content.Intent intent, androidx.wear.phone.interactions.authentication.RemoteAuthRequestHandler remoteAuthRequestHandler);
+ method public static final void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ method protected boolean verifyPackageName(android.content.Context context, String? requestPackageName);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthService.Companion Companion;
+ }
+
+ public static final class RemoteAuthService.Companion {
+ method public void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+}
+
+package androidx.wear.phone.interactions.notifications {
+
+ public final class BridgingConfig {
+ method public java.util.Set<java.lang.String>? getExcludedTags();
+ method public boolean isBridgingEnabled();
+ property public final java.util.Set<java.lang.String>? excludedTags;
+ property public final boolean isBridgingEnabled;
+ }
+
+ public static final class BridgingConfig.Builder {
+ ctor public BridgingConfig.Builder(android.content.Context context, boolean isBridgingEnabled);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTag(String tag);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTags(java.util.Collection<java.lang.String> tags);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig build();
+ }
+
+ public fun interface BridgingConfigurationHandler {
+ method public void applyBridgingConfiguration(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ }
+
+ public final class BridgingManager {
+ method public static androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ method public void setConfig(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ field public static final androidx.wear.phone.interactions.notifications.BridgingManager.Companion Companion;
+ }
+
+ public static final class BridgingManager.Companion {
+ method public androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ }
+
+ public final class BridgingManagerService extends android.app.Service {
+ ctor public BridgingManagerService(android.content.Context context, androidx.wear.phone.interactions.notifications.BridgingConfigurationHandler bridgingConfigurationHandler);
+ method public android.os.IBinder? onBind(android.content.Intent? intent);
+ }
+
+}
+
diff --git a/wear/wear-phone-interactions/api/public_plus_experimental_1.0.0-beta02.txt b/wear/wear-phone-interactions/api/public_plus_experimental_1.0.0-beta02.txt
new file mode 100644
index 0000000..bff73eca
--- /dev/null
+++ b/wear/wear-phone-interactions/api/public_plus_experimental_1.0.0-beta02.txt
@@ -0,0 +1,146 @@
+// Signature format: 4.0
+package androidx.wear.phone.interactions {
+
+ public final class PhoneTypeHelper {
+ method public static int getPhoneDeviceType(android.content.Context context);
+ field public static final androidx.wear.phone.interactions.PhoneTypeHelper.Companion Companion;
+ field public static final int DEVICE_TYPE_ANDROID = 1; // 0x1
+ field public static final int DEVICE_TYPE_ERROR = 0; // 0x0
+ field public static final int DEVICE_TYPE_IOS = 2; // 0x2
+ field public static final int DEVICE_TYPE_UNKNOWN = 3; // 0x3
+ }
+
+ public static final class PhoneTypeHelper.Companion {
+ method public int getPhoneDeviceType(android.content.Context context);
+ }
+
+}
+
+package androidx.wear.phone.interactions.authentication {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeChallenge {
+ ctor public CodeChallenge(androidx.wear.phone.interactions.authentication.CodeVerifier codeVerifier);
+ method public String getValue();
+ property public final String value;
+ }
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeVerifier {
+ ctor public CodeVerifier(optional int byteLength);
+ ctor public CodeVerifier(String value);
+ method public String getValue();
+ property public final String value;
+ }
+
+ public final class OAuthRequest {
+ method public String getPackageName();
+ method public android.net.Uri getRequestUrl();
+ property public final String packageName;
+ property public final android.net.Uri requestUrl;
+ field public static final androidx.wear.phone.interactions.authentication.OAuthRequest.Companion Companion;
+ field public static final String WEAR_REDIRECT_URL_PREFIX = "https://wear.googleapis.com/3p_auth/";
+ field public static final String WEAR_REDIRECT_URL_PREFIX_CN = "https://wear.googleapis-cn.com/3p_auth/";
+ }
+
+ public static final class OAuthRequest.Builder {
+ ctor public OAuthRequest.Builder(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.wear.phone.interactions.authentication.OAuthRequest build();
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setAuthProviderUrl(android.net.Uri authProviderUrl);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setClientId(String clientId);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setCodeChallenge(androidx.wear.phone.interactions.authentication.CodeChallenge codeChallenge);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setRedirectUrl(android.net.Uri redirectUrl);
+ }
+
+ public static final class OAuthRequest.Companion {
+ }
+
+ public final class OAuthResponse {
+ method public int getErrorCode();
+ method public android.net.Uri? getResponseUrl();
+ property public final int errorCode;
+ property public final android.net.Uri? responseUrl;
+ }
+
+ public static final class OAuthResponse.Builder {
+ ctor public OAuthResponse.Builder();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse build();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setErrorCode(int errorCode);
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setResponseUrl(android.net.Uri responseUrl);
+ }
+
+ public final class RemoteAuthClient implements java.lang.AutoCloseable {
+ method @UiThread public void close();
+ method public static androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ method protected void finalize();
+ method @UiThread public void sendAuthorizationRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, java.util.concurrent.Executor executor, androidx.wear.phone.interactions.authentication.RemoteAuthClient.Callback clientCallback);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthClient.Companion Companion;
+ field public static final int ERROR_PHONE_UNAVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNSUPPORTED = 0; // 0x0
+ field public static final int NO_ERROR = -1; // 0xffffffff
+ }
+
+ public abstract static class RemoteAuthClient.Callback {
+ ctor public RemoteAuthClient.Callback();
+ method @UiThread public abstract void onAuthorizationError(androidx.wear.phone.interactions.authentication.OAuthRequest request, int errorCode);
+ method @UiThread public abstract void onAuthorizationResponse(androidx.wear.phone.interactions.authentication.OAuthRequest request, androidx.wear.phone.interactions.authentication.OAuthResponse response);
+ }
+
+ public static final class RemoteAuthClient.Companion {
+ method public androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ }
+
+ public interface RemoteAuthRequestHandler {
+ method public boolean isAuthSupported();
+ method public void sendAuthRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+ public abstract class RemoteAuthService extends android.app.Service {
+ ctor public RemoteAuthService();
+ method protected final android.os.IBinder onBind(android.content.Intent intent, androidx.wear.phone.interactions.authentication.RemoteAuthRequestHandler remoteAuthRequestHandler);
+ method public static final void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ method protected boolean verifyPackageName(android.content.Context context, String? requestPackageName);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthService.Companion Companion;
+ }
+
+ public static final class RemoteAuthService.Companion {
+ method public void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+}
+
+package androidx.wear.phone.interactions.notifications {
+
+ public final class BridgingConfig {
+ method public java.util.Set<java.lang.String>? getExcludedTags();
+ method public boolean isBridgingEnabled();
+ property public final java.util.Set<java.lang.String>? excludedTags;
+ property public final boolean isBridgingEnabled;
+ }
+
+ public static final class BridgingConfig.Builder {
+ ctor public BridgingConfig.Builder(android.content.Context context, boolean isBridgingEnabled);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTag(String tag);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTags(java.util.Collection<java.lang.String> tags);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig build();
+ }
+
+ public fun interface BridgingConfigurationHandler {
+ method public void applyBridgingConfiguration(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ }
+
+ public final class BridgingManager {
+ method public static androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ method public void setConfig(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ field public static final androidx.wear.phone.interactions.notifications.BridgingManager.Companion Companion;
+ }
+
+ public static final class BridgingManager.Companion {
+ method public androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ }
+
+ public final class BridgingManagerService extends android.app.Service {
+ ctor public BridgingManagerService(android.content.Context context, androidx.wear.phone.interactions.notifications.BridgingConfigurationHandler bridgingConfigurationHandler);
+ method public android.os.IBinder? onBind(android.content.Intent? intent);
+ }
+
+}
+
diff --git a/work/workmanager-gcm/api/res-2.6.0-beta01.txt b/wear/wear-phone-interactions/api/res-1.0.0-beta01.txt
similarity index 100%
copy from work/workmanager-gcm/api/res-2.6.0-beta01.txt
copy to wear/wear-phone-interactions/api/res-1.0.0-beta01.txt
diff --git a/work/workmanager-gcm/api/res-2.6.0-beta02.txt b/wear/wear-phone-interactions/api/res-1.0.0-beta02.txt
similarity index 100%
rename from work/workmanager-gcm/api/res-2.6.0-beta02.txt
rename to wear/wear-phone-interactions/api/res-1.0.0-beta02.txt
diff --git a/wear/wear-phone-interactions/api/restricted_1.0.0-beta01.txt b/wear/wear-phone-interactions/api/restricted_1.0.0-beta01.txt
new file mode 100644
index 0000000..bff73eca
--- /dev/null
+++ b/wear/wear-phone-interactions/api/restricted_1.0.0-beta01.txt
@@ -0,0 +1,146 @@
+// Signature format: 4.0
+package androidx.wear.phone.interactions {
+
+ public final class PhoneTypeHelper {
+ method public static int getPhoneDeviceType(android.content.Context context);
+ field public static final androidx.wear.phone.interactions.PhoneTypeHelper.Companion Companion;
+ field public static final int DEVICE_TYPE_ANDROID = 1; // 0x1
+ field public static final int DEVICE_TYPE_ERROR = 0; // 0x0
+ field public static final int DEVICE_TYPE_IOS = 2; // 0x2
+ field public static final int DEVICE_TYPE_UNKNOWN = 3; // 0x3
+ }
+
+ public static final class PhoneTypeHelper.Companion {
+ method public int getPhoneDeviceType(android.content.Context context);
+ }
+
+}
+
+package androidx.wear.phone.interactions.authentication {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeChallenge {
+ ctor public CodeChallenge(androidx.wear.phone.interactions.authentication.CodeVerifier codeVerifier);
+ method public String getValue();
+ property public final String value;
+ }
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeVerifier {
+ ctor public CodeVerifier(optional int byteLength);
+ ctor public CodeVerifier(String value);
+ method public String getValue();
+ property public final String value;
+ }
+
+ public final class OAuthRequest {
+ method public String getPackageName();
+ method public android.net.Uri getRequestUrl();
+ property public final String packageName;
+ property public final android.net.Uri requestUrl;
+ field public static final androidx.wear.phone.interactions.authentication.OAuthRequest.Companion Companion;
+ field public static final String WEAR_REDIRECT_URL_PREFIX = "https://wear.googleapis.com/3p_auth/";
+ field public static final String WEAR_REDIRECT_URL_PREFIX_CN = "https://wear.googleapis-cn.com/3p_auth/";
+ }
+
+ public static final class OAuthRequest.Builder {
+ ctor public OAuthRequest.Builder(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.wear.phone.interactions.authentication.OAuthRequest build();
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setAuthProviderUrl(android.net.Uri authProviderUrl);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setClientId(String clientId);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setCodeChallenge(androidx.wear.phone.interactions.authentication.CodeChallenge codeChallenge);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setRedirectUrl(android.net.Uri redirectUrl);
+ }
+
+ public static final class OAuthRequest.Companion {
+ }
+
+ public final class OAuthResponse {
+ method public int getErrorCode();
+ method public android.net.Uri? getResponseUrl();
+ property public final int errorCode;
+ property public final android.net.Uri? responseUrl;
+ }
+
+ public static final class OAuthResponse.Builder {
+ ctor public OAuthResponse.Builder();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse build();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setErrorCode(int errorCode);
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setResponseUrl(android.net.Uri responseUrl);
+ }
+
+ public final class RemoteAuthClient implements java.lang.AutoCloseable {
+ method @UiThread public void close();
+ method public static androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ method protected void finalize();
+ method @UiThread public void sendAuthorizationRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, java.util.concurrent.Executor executor, androidx.wear.phone.interactions.authentication.RemoteAuthClient.Callback clientCallback);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthClient.Companion Companion;
+ field public static final int ERROR_PHONE_UNAVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNSUPPORTED = 0; // 0x0
+ field public static final int NO_ERROR = -1; // 0xffffffff
+ }
+
+ public abstract static class RemoteAuthClient.Callback {
+ ctor public RemoteAuthClient.Callback();
+ method @UiThread public abstract void onAuthorizationError(androidx.wear.phone.interactions.authentication.OAuthRequest request, int errorCode);
+ method @UiThread public abstract void onAuthorizationResponse(androidx.wear.phone.interactions.authentication.OAuthRequest request, androidx.wear.phone.interactions.authentication.OAuthResponse response);
+ }
+
+ public static final class RemoteAuthClient.Companion {
+ method public androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ }
+
+ public interface RemoteAuthRequestHandler {
+ method public boolean isAuthSupported();
+ method public void sendAuthRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+ public abstract class RemoteAuthService extends android.app.Service {
+ ctor public RemoteAuthService();
+ method protected final android.os.IBinder onBind(android.content.Intent intent, androidx.wear.phone.interactions.authentication.RemoteAuthRequestHandler remoteAuthRequestHandler);
+ method public static final void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ method protected boolean verifyPackageName(android.content.Context context, String? requestPackageName);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthService.Companion Companion;
+ }
+
+ public static final class RemoteAuthService.Companion {
+ method public void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+}
+
+package androidx.wear.phone.interactions.notifications {
+
+ public final class BridgingConfig {
+ method public java.util.Set<java.lang.String>? getExcludedTags();
+ method public boolean isBridgingEnabled();
+ property public final java.util.Set<java.lang.String>? excludedTags;
+ property public final boolean isBridgingEnabled;
+ }
+
+ public static final class BridgingConfig.Builder {
+ ctor public BridgingConfig.Builder(android.content.Context context, boolean isBridgingEnabled);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTag(String tag);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTags(java.util.Collection<java.lang.String> tags);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig build();
+ }
+
+ public fun interface BridgingConfigurationHandler {
+ method public void applyBridgingConfiguration(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ }
+
+ public final class BridgingManager {
+ method public static androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ method public void setConfig(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ field public static final androidx.wear.phone.interactions.notifications.BridgingManager.Companion Companion;
+ }
+
+ public static final class BridgingManager.Companion {
+ method public androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ }
+
+ public final class BridgingManagerService extends android.app.Service {
+ ctor public BridgingManagerService(android.content.Context context, androidx.wear.phone.interactions.notifications.BridgingConfigurationHandler bridgingConfigurationHandler);
+ method public android.os.IBinder? onBind(android.content.Intent? intent);
+ }
+
+}
+
diff --git a/wear/wear-phone-interactions/api/restricted_1.0.0-beta02.txt b/wear/wear-phone-interactions/api/restricted_1.0.0-beta02.txt
new file mode 100644
index 0000000..bff73eca
--- /dev/null
+++ b/wear/wear-phone-interactions/api/restricted_1.0.0-beta02.txt
@@ -0,0 +1,146 @@
+// Signature format: 4.0
+package androidx.wear.phone.interactions {
+
+ public final class PhoneTypeHelper {
+ method public static int getPhoneDeviceType(android.content.Context context);
+ field public static final androidx.wear.phone.interactions.PhoneTypeHelper.Companion Companion;
+ field public static final int DEVICE_TYPE_ANDROID = 1; // 0x1
+ field public static final int DEVICE_TYPE_ERROR = 0; // 0x0
+ field public static final int DEVICE_TYPE_IOS = 2; // 0x2
+ field public static final int DEVICE_TYPE_UNKNOWN = 3; // 0x3
+ }
+
+ public static final class PhoneTypeHelper.Companion {
+ method public int getPhoneDeviceType(android.content.Context context);
+ }
+
+}
+
+package androidx.wear.phone.interactions.authentication {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeChallenge {
+ ctor public CodeChallenge(androidx.wear.phone.interactions.authentication.CodeVerifier codeVerifier);
+ method public String getValue();
+ property public final String value;
+ }
+
+ @RequiresApi(android.os.Build.VERSION_CODES.O) public final class CodeVerifier {
+ ctor public CodeVerifier(optional int byteLength);
+ ctor public CodeVerifier(String value);
+ method public String getValue();
+ property public final String value;
+ }
+
+ public final class OAuthRequest {
+ method public String getPackageName();
+ method public android.net.Uri getRequestUrl();
+ property public final String packageName;
+ property public final android.net.Uri requestUrl;
+ field public static final androidx.wear.phone.interactions.authentication.OAuthRequest.Companion Companion;
+ field public static final String WEAR_REDIRECT_URL_PREFIX = "https://wear.googleapis.com/3p_auth/";
+ field public static final String WEAR_REDIRECT_URL_PREFIX_CN = "https://wear.googleapis-cn.com/3p_auth/";
+ }
+
+ public static final class OAuthRequest.Builder {
+ ctor public OAuthRequest.Builder(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.wear.phone.interactions.authentication.OAuthRequest build();
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setAuthProviderUrl(android.net.Uri authProviderUrl);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setClientId(String clientId);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setCodeChallenge(androidx.wear.phone.interactions.authentication.CodeChallenge codeChallenge);
+ method public androidx.wear.phone.interactions.authentication.OAuthRequest.Builder setRedirectUrl(android.net.Uri redirectUrl);
+ }
+
+ public static final class OAuthRequest.Companion {
+ }
+
+ public final class OAuthResponse {
+ method public int getErrorCode();
+ method public android.net.Uri? getResponseUrl();
+ property public final int errorCode;
+ property public final android.net.Uri? responseUrl;
+ }
+
+ public static final class OAuthResponse.Builder {
+ ctor public OAuthResponse.Builder();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse build();
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setErrorCode(int errorCode);
+ method public androidx.wear.phone.interactions.authentication.OAuthResponse.Builder setResponseUrl(android.net.Uri responseUrl);
+ }
+
+ public final class RemoteAuthClient implements java.lang.AutoCloseable {
+ method @UiThread public void close();
+ method public static androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ method protected void finalize();
+ method @UiThread public void sendAuthorizationRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, java.util.concurrent.Executor executor, androidx.wear.phone.interactions.authentication.RemoteAuthClient.Callback clientCallback);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthClient.Companion Companion;
+ field public static final int ERROR_PHONE_UNAVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNSUPPORTED = 0; // 0x0
+ field public static final int NO_ERROR = -1; // 0xffffffff
+ }
+
+ public abstract static class RemoteAuthClient.Callback {
+ ctor public RemoteAuthClient.Callback();
+ method @UiThread public abstract void onAuthorizationError(androidx.wear.phone.interactions.authentication.OAuthRequest request, int errorCode);
+ method @UiThread public abstract void onAuthorizationResponse(androidx.wear.phone.interactions.authentication.OAuthRequest request, androidx.wear.phone.interactions.authentication.OAuthResponse response);
+ }
+
+ public static final class RemoteAuthClient.Companion {
+ method public androidx.wear.phone.interactions.authentication.RemoteAuthClient create(android.content.Context context);
+ }
+
+ public interface RemoteAuthRequestHandler {
+ method public boolean isAuthSupported();
+ method public void sendAuthRequest(androidx.wear.phone.interactions.authentication.OAuthRequest request, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+ public abstract class RemoteAuthService extends android.app.Service {
+ ctor public RemoteAuthService();
+ method protected final android.os.IBinder onBind(android.content.Intent intent, androidx.wear.phone.interactions.authentication.RemoteAuthRequestHandler remoteAuthRequestHandler);
+ method public static final void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ method protected boolean verifyPackageName(android.content.Context context, String? requestPackageName);
+ field public static final androidx.wear.phone.interactions.authentication.RemoteAuthService.Companion Companion;
+ }
+
+ public static final class RemoteAuthService.Companion {
+ method public void sendResponseToCallback(androidx.wear.phone.interactions.authentication.OAuthResponse response, kotlin.Pair<java.lang.String,java.lang.Integer> packageNameAndRequestId);
+ }
+
+}
+
+package androidx.wear.phone.interactions.notifications {
+
+ public final class BridgingConfig {
+ method public java.util.Set<java.lang.String>? getExcludedTags();
+ method public boolean isBridgingEnabled();
+ property public final java.util.Set<java.lang.String>? excludedTags;
+ property public final boolean isBridgingEnabled;
+ }
+
+ public static final class BridgingConfig.Builder {
+ ctor public BridgingConfig.Builder(android.content.Context context, boolean isBridgingEnabled);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTag(String tag);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig.Builder addExcludedTags(java.util.Collection<java.lang.String> tags);
+ method public androidx.wear.phone.interactions.notifications.BridgingConfig build();
+ }
+
+ public fun interface BridgingConfigurationHandler {
+ method public void applyBridgingConfiguration(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ }
+
+ public final class BridgingManager {
+ method public static androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ method public void setConfig(androidx.wear.phone.interactions.notifications.BridgingConfig bridgingConfig);
+ field public static final androidx.wear.phone.interactions.notifications.BridgingManager.Companion Companion;
+ }
+
+ public static final class BridgingManager.Companion {
+ method public androidx.wear.phone.interactions.notifications.BridgingManager fromContext(android.content.Context context);
+ }
+
+ public final class BridgingManagerService extends android.app.Service {
+ ctor public BridgingManagerService(android.content.Context context, androidx.wear.phone.interactions.notifications.BridgingConfigurationHandler bridgingConfigurationHandler);
+ method public android.os.IBinder? onBind(android.content.Intent? intent);
+ }
+
+}
+
diff --git a/wear/wear-phone-interactions/src/test/resources/robolectric.properties b/wear/wear-phone-interactions/src/test/resources/robolectric.properties
index 74bb2a9..1061465 100644
--- a/wear/wear-phone-interactions/src/test/resources/robolectric.properties
+++ b/wear/wear-phone-interactions/src/test/resources/robolectric.properties
@@ -14,7 +14,7 @@
# limitations under the License.
#
-# Robolectric currently doesn't support API 30, so we have to explicitly specify the target sdk
+# Robolectric currently doesn't support API 31, so we have to explicitly specify the target sdk
# levels for now.
# TODO(b/177072877): Remove when no longer necessary.
sdk=28
diff --git a/wear/wear-remote-interactions/api/1.0.0-beta02.txt b/wear/wear-remote-interactions/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..208fcb7
--- /dev/null
+++ b/wear/wear-remote-interactions/api/1.0.0-beta02.txt
@@ -0,0 +1,41 @@
+// Signature format: 4.0
+package androidx.wear.remote.interactions {
+
+ public final class RemoteActivityHelper {
+ ctor public RemoteActivityHelper(android.content.Context context, optional java.util.concurrent.Executor executor);
+ method public static android.content.Intent? getTargetIntent(android.content.Intent intent);
+ method public static String? getTargetNodeId(android.content.Intent intent);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startRemoteActivity(android.content.Intent targetIntent, optional String? targetNodeId);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startRemoteActivity(android.content.Intent targetIntent);
+ field public static final String ACTION_REMOTE_INTENT = "com.google.android.wearable.intent.action.REMOTE_INTENT";
+ field public static final androidx.wear.remote.interactions.RemoteActivityHelper.Companion Companion;
+ field public static final int RESULT_FAILED = 1; // 0x1
+ field public static final int RESULT_OK = 0; // 0x0
+ }
+
+ public static final class RemoteActivityHelper.Companion {
+ method public android.content.Intent? getTargetIntent(android.content.Intent intent);
+ method public String? getTargetNodeId(android.content.Intent intent);
+ }
+
+ public static final class RemoteActivityHelper.RemoteIntentException extends java.lang.Exception {
+ ctor public RemoteActivityHelper.RemoteIntentException(String message);
+ }
+
+ public final class WatchFaceConfigIntentHelper {
+ method public static String? getPeerIdExtra(android.content.Intent watchFaceIntent);
+ method public static android.content.ComponentName? getWatchFaceComponentExtra(android.content.Intent watchFaceIntent);
+ method public static android.content.Intent putPeerIdExtra(android.content.Intent watchFaceIntent, String peerId);
+ method public static android.content.Intent putWatchFaceComponentExtra(android.content.Intent watchFaceIntent, android.content.ComponentName componentName);
+ field public static final androidx.wear.remote.interactions.WatchFaceConfigIntentHelper.Companion Companion;
+ }
+
+ public static final class WatchFaceConfigIntentHelper.Companion {
+ method public String? getPeerIdExtra(android.content.Intent watchFaceIntent);
+ method public android.content.ComponentName? getWatchFaceComponentExtra(android.content.Intent watchFaceIntent);
+ method public android.content.Intent putPeerIdExtra(android.content.Intent watchFaceIntent, String peerId);
+ method public android.content.Intent putWatchFaceComponentExtra(android.content.Intent watchFaceIntent, android.content.ComponentName componentName);
+ }
+
+}
+
diff --git a/wear/wear-remote-interactions/api/public_plus_experimental_1.0.0-beta02.txt b/wear/wear-remote-interactions/api/public_plus_experimental_1.0.0-beta02.txt
new file mode 100644
index 0000000..208fcb7
--- /dev/null
+++ b/wear/wear-remote-interactions/api/public_plus_experimental_1.0.0-beta02.txt
@@ -0,0 +1,41 @@
+// Signature format: 4.0
+package androidx.wear.remote.interactions {
+
+ public final class RemoteActivityHelper {
+ ctor public RemoteActivityHelper(android.content.Context context, optional java.util.concurrent.Executor executor);
+ method public static android.content.Intent? getTargetIntent(android.content.Intent intent);
+ method public static String? getTargetNodeId(android.content.Intent intent);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startRemoteActivity(android.content.Intent targetIntent, optional String? targetNodeId);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startRemoteActivity(android.content.Intent targetIntent);
+ field public static final String ACTION_REMOTE_INTENT = "com.google.android.wearable.intent.action.REMOTE_INTENT";
+ field public static final androidx.wear.remote.interactions.RemoteActivityHelper.Companion Companion;
+ field public static final int RESULT_FAILED = 1; // 0x1
+ field public static final int RESULT_OK = 0; // 0x0
+ }
+
+ public static final class RemoteActivityHelper.Companion {
+ method public android.content.Intent? getTargetIntent(android.content.Intent intent);
+ method public String? getTargetNodeId(android.content.Intent intent);
+ }
+
+ public static final class RemoteActivityHelper.RemoteIntentException extends java.lang.Exception {
+ ctor public RemoteActivityHelper.RemoteIntentException(String message);
+ }
+
+ public final class WatchFaceConfigIntentHelper {
+ method public static String? getPeerIdExtra(android.content.Intent watchFaceIntent);
+ method public static android.content.ComponentName? getWatchFaceComponentExtra(android.content.Intent watchFaceIntent);
+ method public static android.content.Intent putPeerIdExtra(android.content.Intent watchFaceIntent, String peerId);
+ method public static android.content.Intent putWatchFaceComponentExtra(android.content.Intent watchFaceIntent, android.content.ComponentName componentName);
+ field public static final androidx.wear.remote.interactions.WatchFaceConfigIntentHelper.Companion Companion;
+ }
+
+ public static final class WatchFaceConfigIntentHelper.Companion {
+ method public String? getPeerIdExtra(android.content.Intent watchFaceIntent);
+ method public android.content.ComponentName? getWatchFaceComponentExtra(android.content.Intent watchFaceIntent);
+ method public android.content.Intent putPeerIdExtra(android.content.Intent watchFaceIntent, String peerId);
+ method public android.content.Intent putWatchFaceComponentExtra(android.content.Intent watchFaceIntent, android.content.ComponentName componentName);
+ }
+
+}
+
diff --git a/work/workmanager-multiprocess/api/res-2.6.0-beta02.txt b/wear/wear-remote-interactions/api/res-1.0.0-beta02.txt
similarity index 100%
rename from work/workmanager-multiprocess/api/res-2.6.0-beta02.txt
rename to wear/wear-remote-interactions/api/res-1.0.0-beta02.txt
diff --git a/wear/wear-remote-interactions/api/restricted_1.0.0-beta02.txt b/wear/wear-remote-interactions/api/restricted_1.0.0-beta02.txt
new file mode 100644
index 0000000..208fcb7
--- /dev/null
+++ b/wear/wear-remote-interactions/api/restricted_1.0.0-beta02.txt
@@ -0,0 +1,41 @@
+// Signature format: 4.0
+package androidx.wear.remote.interactions {
+
+ public final class RemoteActivityHelper {
+ ctor public RemoteActivityHelper(android.content.Context context, optional java.util.concurrent.Executor executor);
+ method public static android.content.Intent? getTargetIntent(android.content.Intent intent);
+ method public static String? getTargetNodeId(android.content.Intent intent);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startRemoteActivity(android.content.Intent targetIntent, optional String? targetNodeId);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startRemoteActivity(android.content.Intent targetIntent);
+ field public static final String ACTION_REMOTE_INTENT = "com.google.android.wearable.intent.action.REMOTE_INTENT";
+ field public static final androidx.wear.remote.interactions.RemoteActivityHelper.Companion Companion;
+ field public static final int RESULT_FAILED = 1; // 0x1
+ field public static final int RESULT_OK = 0; // 0x0
+ }
+
+ public static final class RemoteActivityHelper.Companion {
+ method public android.content.Intent? getTargetIntent(android.content.Intent intent);
+ method public String? getTargetNodeId(android.content.Intent intent);
+ }
+
+ public static final class RemoteActivityHelper.RemoteIntentException extends java.lang.Exception {
+ ctor public RemoteActivityHelper.RemoteIntentException(String message);
+ }
+
+ public final class WatchFaceConfigIntentHelper {
+ method public static String? getPeerIdExtra(android.content.Intent watchFaceIntent);
+ method public static android.content.ComponentName? getWatchFaceComponentExtra(android.content.Intent watchFaceIntent);
+ method public static android.content.Intent putPeerIdExtra(android.content.Intent watchFaceIntent, String peerId);
+ method public static android.content.Intent putWatchFaceComponentExtra(android.content.Intent watchFaceIntent, android.content.ComponentName componentName);
+ field public static final androidx.wear.remote.interactions.WatchFaceConfigIntentHelper.Companion Companion;
+ }
+
+ public static final class WatchFaceConfigIntentHelper.Companion {
+ method public String? getPeerIdExtra(android.content.Intent watchFaceIntent);
+ method public android.content.ComponentName? getWatchFaceComponentExtra(android.content.Intent watchFaceIntent);
+ method public android.content.Intent putPeerIdExtra(android.content.Intent watchFaceIntent, String peerId);
+ method public android.content.Intent putWatchFaceComponentExtra(android.content.Intent watchFaceIntent, android.content.ComponentName componentName);
+ }
+
+}
+
diff --git a/wear/wear-remote-interactions/src/test/resources/robolectric.properties b/wear/wear-remote-interactions/src/test/resources/robolectric.properties
index c0066c1..415d731 100644
--- a/wear/wear-remote-interactions/src/test/resources/robolectric.properties
+++ b/wear/wear-remote-interactions/src/test/resources/robolectric.properties
@@ -14,7 +14,7 @@
# limitations under the License.
#
-# Robolectric currently doesn't support API 30, so we have to explicitly the target sdk levels for
+# Robolectric currently doesn't support API 31, so we have to explicitly the target sdk levels for
# now.
# TODO(b/177072877): Remove when no longer necessary.
-sdk=25,26,27,28
+sdk=25,26,27,28,29,30
diff --git a/wear/wear-samples-ambient/src/main/AndroidManifest.xml b/wear/wear-samples-ambient/src/main/AndroidManifest.xml
index 2aeb86f..9362003 100644
--- a/wear/wear-samples-ambient/src/main/AndroidManifest.xml
+++ b/wear/wear-samples-ambient/src/main/AndroidManifest.xml
@@ -14,6 +14,7 @@
android:theme="@android:style/Theme.DeviceDefault">
<activity
android:name=".MainActivity"
+ android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/wear/wear-watchface-client-guava/src/androidTest/AndroidManifest.xml b/wear/wear-watchface-client-guava/src/androidTest/AndroidManifest.xml
index 1b3cfb2..9ea23e3 100644
--- a/wear/wear-watchface-client-guava/src/androidTest/AndroidManifest.xml
+++ b/wear/wear-watchface-client-guava/src/androidTest/AndroidManifest.xml
@@ -17,7 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.wear.watchface.client.guava.test">
<application android:requestLegacyExternalStorage="true">
- <service android:name="androidx.wear.watchface.client.guava.WatchFaceControlTestService">
+ <service android:name="androidx.wear.watchface.client.guava.WatchFaceControlTestService"
+ android:exported="true">
<intent-filter>
<action android:name="com.google.android.wearable.action.WATCH_FACE_CONTROL"/>
</intent-filter>
diff --git a/wear/wear-watchface-client-guava/src/main/java/androidx/wear/watchface/client/ListenableWatchFaceControlClient.kt b/wear/wear-watchface-client-guava/src/main/java/androidx/wear/watchface/client/ListenableWatchFaceControlClient.kt
index 73d7f12..dc33854d 100644
--- a/wear/wear-watchface-client-guava/src/main/java/androidx/wear/watchface/client/ListenableWatchFaceControlClient.kt
+++ b/wear/wear-watchface-client-guava/src/main/java/androidx/wear/watchface/client/ListenableWatchFaceControlClient.kt
@@ -87,9 +87,8 @@
/**
* Returns a [ListenableFuture] for a [ListenableWatchFaceControlClient] which attempts to
- * connect to a watch face in the android package [watchFacePackageName].
- * Resolves as [ServiceNotBoundException] if the watch face control service can not
- * be bound.
+ * connect to a watch face in the android package [watchFacePackageName]. Resolves as
+ * [ServiceNotBoundException] if the watch face control service can not be bound.
*
* Note the returned future may resolve immediately on the calling thread or it may resolve
* asynchronously when the service is connected on a background thread.
@@ -135,6 +134,15 @@
* [ListenableFuture] wrapper around
* [WatchFaceControlClient.getOrCreateInteractiveWatchFaceClient].
* This is open to allow mocking.
+ *
+ * @param id The Id of the interactive instance to get or create.
+ * @param deviceConfig The [DeviceConfig] of the interactive instance (only used when creating)
+ * @param watchUiState The initial [WatchUiState] for the wearable.
+ * @param userStyle Optional [UserStyleData] to apply to the instance (whether or not it's
+ * created). If `null` then the pre-existing user style is preserved (if the instance is created
+ * this will be the [androidx.wear.watchface.style.UserStyleSchema]'s default).
+ * @param slotIdToComplicationData The initial [androidx.wear.watchface.ComplicationSlot] data,
+ * or `null` if unavailable.
*/
public open fun listenableGetOrCreateInteractiveWatchFaceClient(
id: String,
diff --git a/wear/wear-watchface-client/api/current.txt b/wear/wear-watchface-client/api/current.txt
index 4dc5088..b220099 100644
--- a/wear/wear-watchface-client/api/current.txt
+++ b/wear/wear-watchface-client/api/current.txt
@@ -102,7 +102,6 @@
public interface InteractiveWatchFaceClient extends java.lang.AutoCloseable {
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.InteractiveWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
- method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public void displayPressedAnimation(int complicationSlotId) throws android.os.RemoteException;
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public default Integer? getComplicationIdAt(@Px int x, @Px int y) throws android.os.RemoteException;
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.List<androidx.wear.watchface.ContentDescriptionLabel> getContentDescriptionLabels();
diff --git a/wear/wear-watchface-client/api/public_plus_experimental_current.txt b/wear/wear-watchface-client/api/public_plus_experimental_current.txt
index 526f18e..4c99be7 100644
--- a/wear/wear-watchface-client/api/public_plus_experimental_current.txt
+++ b/wear/wear-watchface-client/api/public_plus_experimental_current.txt
@@ -122,7 +122,6 @@
public interface InteractiveWatchFaceClient extends java.lang.AutoCloseable {
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.InteractiveWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
- method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public void displayPressedAnimation(int complicationSlotId) throws android.os.RemoteException;
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public default Integer? getComplicationIdAt(@Px int x, @Px int y) throws android.os.RemoteException;
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.List<androidx.wear.watchface.ContentDescriptionLabel> getContentDescriptionLabels();
diff --git a/wear/wear-watchface-client/api/restricted_current.txt b/wear/wear-watchface-client/api/restricted_current.txt
index 2568de8..8479190 100644
--- a/wear/wear-watchface-client/api/restricted_current.txt
+++ b/wear/wear-watchface-client/api/restricted_current.txt
@@ -106,7 +106,6 @@
public interface InteractiveWatchFaceClient extends java.lang.AutoCloseable {
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.InteractiveWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
- method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public void displayPressedAnimation(int complicationSlotId) throws android.os.RemoteException;
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public default Integer? getComplicationIdAt(@Px int x, @Px int y) throws android.os.RemoteException;
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.List<androidx.wear.watchface.ContentDescriptionLabel> getContentDescriptionLabels();
diff --git a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/BindHelper.kt b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/BindHelper.kt
new file mode 100644
index 0000000..7871341
--- /dev/null
+++ b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/BindHelper.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.client
+
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.Build
+import androidx.annotation.RequiresApi
+
+/** Wrapper around [Context.bindService]. */
+internal class BindHelper {
+ companion object {
+ /**
+ * Wrapper around [Context.bindService] which uses an immediate executor where possible for
+ * [serviceConnection].
+ *
+ * @param context The [Context] on which to call [Context.bindService]
+ * @param intent The [Intent] to pass to [Context.bindService]
+ * @param serviceConnection The [ServiceConnection] to pass to [Context.bindService].
+ * Note on API 29 and above this will be called on a binder thread, before that it will be
+ * called on the UI thread.
+ * @return The result of [Context.bindService]
+ */
+ fun bindService(
+ context: Context,
+ intent: Intent,
+ serviceConnection: ServiceConnection
+ ): Boolean {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ // API 29 lets us specify an executor to avoid a round trip via the potentially
+ // congested UI thread.
+ BindHelper29.bindServiceWithImmediateExecutor(
+ context,
+ intent,
+ serviceConnection
+ )
+ } else {
+ /** Note serviceConnection will be dispatched on the UI thread. */
+ context.bindService(
+ intent,
+ serviceConnection,
+ Context.BIND_AUTO_CREATE or Context.BIND_IMPORTANT
+ )
+ }
+ }
+ }
+}
+
+private class BindHelper29 {
+ @RequiresApi(Build.VERSION_CODES.Q)
+ companion object {
+ /** Note serviceConnection will be dispatched on a binder thread. */
+ fun bindServiceWithImmediateExecutor(
+ context: Context,
+ intent: Intent,
+ serviceConnection: ServiceConnection
+ ) = context.bindService(
+ intent,
+ Context.BIND_AUTO_CREATE or Context.BIND_IMPORTANT,
+ { command -> command.run() },
+ serviceConnection
+ )
+ }
+}
\ No newline at end of file
diff --git a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt
index 9396ed3..888fcd0 100644
--- a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt
+++ b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt
@@ -126,6 +126,8 @@
/**
* Returns the ID of the [androidx.wear.watchface.ComplicationSlot] at the given coordinates or
* `null` if there isn't one.
+ *
+ * Note this currently doesn't support Edge complications.
*/
@SuppressWarnings("AutoBoxing")
@Throws(RemoteException::class)
@@ -139,13 +141,6 @@
}
}?.key
- /**
- * Requests that [ComplicationSlotsManager.displayPressedAnimation] is called for
- * [complicationSlotId].
- */
- @Throws(RemoteException::class)
- public fun displayPressedAnimation(complicationSlotId: Int)
-
public companion object {
/** Indicates a "down" touch event on the watch face. */
public const val TAP_TYPE_DOWN: Int = IInteractiveWatchFace.TAP_TYPE_DOWN
@@ -311,12 +306,6 @@
iInteractiveWatchFace.release()
}
- override fun displayPressedAnimation(complicationSlotId: Int) = TraceEvent(
- "InteractiveWatchFaceClientImpl.bringAttentionToComplication"
- ).use {
- iInteractiveWatchFace.bringAttentionToComplication(complicationSlotId)
- }
-
override fun sendTouchEvent(
xPosition: Int,
yPosition: Int,
diff --git a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt
index 2c7812b..d8e2e4cd 100644
--- a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt
+++ b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt
@@ -38,7 +38,6 @@
import androidx.wear.watchface.control.data.WallpaperInteractiveWatchFaceInstanceParams
import androidx.wear.watchface.data.IdAndComplicationDataWireFormat
import androidx.wear.watchface.data.WatchUiState
-import androidx.wear.watchface.style.UserStyle
import androidx.wear.watchface.style.UserStyleData
import androidx.wear.watchface.style.data.UserStyleWireFormat
import kotlinx.coroutines.CompletableDeferred
@@ -95,12 +94,7 @@
deferredService.completeExceptionally(ServiceStartFailureException())
}
}
- if (!context.bindService(
- intent,
- serviceConnection,
- Context.BIND_AUTO_CREATE or Context.BIND_IMPORTANT
- )
- ) {
+ if (!BindHelper.bindService(context, intent, serviceConnection)) {
traceEvent.close()
throw ServiceNotBoundException()
}
@@ -168,8 +162,9 @@
* @param id The ID for the requested [InteractiveWatchFaceClient].
* @param deviceConfig The [DeviceConfig] for the wearable.
* @param watchUiState The initial [WatchUiState] for the wearable.
- * @param userStyle The initial style map encoded as [UserStyleData] (see [UserStyle]), or
- * `null` if the default should be used.
+ * @param userStyle Optional [UserStyleData] to apply to the instance (whether or not it's
+ * created). If `null` then the pre-existing user style is preserved (if the instance is created
+ * this will be the [androidx.wear.watchface.style.UserStyleSchema]'s default).
* @param slotIdToComplicationData The initial [androidx.wear.watchface.ComplicationSlot] data,
* or `null` if unavailable.
* @return The [InteractiveWatchFaceClient], this should be closed when finished.
diff --git a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
index 1cd79b4..7028eb3 100644
--- a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
+++ b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
@@ -97,12 +97,7 @@
deferredService.completeExceptionally(ServiceStartFailureException())
}
}
- if (!context.bindService(
- intent,
- serviceConnection,
- Context.BIND_AUTO_CREATE or Context.BIND_IMPORTANT
- )
- ) {
+ if (!BindHelper.bindService(context, intent, serviceConnection)) {
traceEvent.close()
throw ServiceNotBoundException()
}
diff --git a/wear/wear-watchface-client/src/test/resources/robolectric.properties b/wear/wear-watchface-client/src/test/resources/robolectric.properties
index ce87047..ab64ba7 100644
--- a/wear/wear-watchface-client/src/test/resources/robolectric.properties
+++ b/wear/wear-watchface-client/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/CanvasComplicationDrawable.kt b/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/CanvasComplicationDrawable.kt
index c9f2b64..8e5c1bd 100644
--- a/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/CanvasComplicationDrawable.kt
+++ b/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/CanvasComplicationDrawable.kt
@@ -53,7 +53,10 @@
private val invalidateCallback: CanvasComplication.InvalidateCallback
) : CanvasComplication {
- private companion object {
+ internal companion object {
+ // Complications are highlighted when tapped and after this delay the highlight is removed.
+ internal const val COMPLICATION_HIGHLIGHT_DURATION_MS = 300L
+
internal const val EXPANSION_DP = 6.0f
internal const val STROKE_WIDTH_DP = 3.0f
}
@@ -112,7 +115,11 @@
drawable.isInAmbientMode = renderParameters.drawMode == DrawMode.AMBIENT
drawable.bounds = bounds
drawable.currentTimeMillis = calendar.timeInMillis
- drawable.isHighlighted = renderParameters.pressedComplicationSlotIds.contains(slotId)
+ drawable.isHighlighted = renderParameters.lastComplicationTapDownEvents[slotId]?.let {
+ val startTime = it.tapTimeMillis
+ val endTime = it.tapTimeMillis + COMPLICATION_HIGHLIGHT_DURATION_MS
+ calendar.timeInMillis in startTime until endTime
+ } ?: false
drawable.draw(canvas)
}
diff --git a/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationDrawable.kt b/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationDrawable.kt
index bdbf5aa..d90af48 100644
--- a/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationDrawable.kt
+++ b/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationDrawable.kt
@@ -192,10 +192,10 @@
internal var complicationRenderer: ComplicationRenderer? = null
private set
- /** Returns complication style for active mode. */
+ /** Returns complication style for active mode. */
public val activeStyle: ComplicationStyle
- /** Returns complication style for ambient mode. */
+ /** Returns complication style for ambient mode. */
public val ambientStyle: ComplicationStyle
private val mainThreadHandler = Handler(Looper.getMainLooper())
@@ -206,17 +206,17 @@
private val rendererInvalidateListener = OnInvalidateListener { invalidateSelf() }
/**
- * The time in milliseconds since the epoch used for rendering [ComplicationData]
- * with time dependent text.
+ * The time in milliseconds since the epoch used for rendering [ComplicationData] with time
+ * dependent text.
*/
public var currentTimeMillis: Long = 0
- /** Whether the complication is rendered in ambient mode. */
+ /** Whether the complication is rendered in ambient mode. */
public var isInAmbientMode: Boolean = false
/**
- * Whether the complication, when rendering in ambient mode, should apply a style
- * suitable for low bit ambient mode.
+ * Whether the complication, when rendering in ambient mode, should apply a style suitable for
+ * low bit ambient mode.
*/
public var isLowBitAmbient: Boolean = false
@@ -227,8 +227,8 @@
public var isBurnInProtectionOn: Boolean = false
/**
- * Whether the complication is currently highlighted. This may be called by a watch face
- * when a complication is tapped.
+ * Whether the complication is currently highlighted. This may be called by a watch face when
+ * a complication is tapped.
*
* If watch face is in ambient mode, highlight will not be visible even if this is set to
* `true`, because it may cause burn-in or power inefficiency.
@@ -238,7 +238,7 @@
private var isInflatedFromXml = false
private var alreadyStyled = false
- /** Default constructor. */
+ /** Default constructor. */
public constructor() {
activeStyle = ComplicationStyle()
ambientStyle = ComplicationStyle()
@@ -246,7 +246,9 @@
/**
* Creates a ComplicationDrawable using the given context. If this constructor is used, calling
- * [.setContext] may not be necessary.
+ * [setContext] may not be necessary.
+ *
+ * @param context The [Context] used to render the complication.
*/
public constructor(context: Context) : this() {
setContext(context)
@@ -269,12 +271,12 @@
}
/**
- * Sets the context used to render the complication. If a context is not set,
- * ComplicationDrawable will throw an [IllegalStateException] if one of [draw], [setBounds],
- * or [setComplicationData] is called.
+ * Sets the [Context] used to render the complication. If a context is not set,
+ * ComplicationDrawable will throw an [IllegalStateException] if one of [draw], [setBounds], or
+ * [setComplicationData] is called.
*
* While this can be called from any context, ideally, a
- * androidx.wear.watchface.WatchFaceService object should be passed here to allow creating
+ * [androidx.wear.watchface.WatchFaceService] object should be passed here to allow creating
* permission dialogs by the [onTap] method, in case current watch face doesn't have the
* permission to receive complication data.
*
@@ -282,8 +284,10 @@
* be called before calling any of the methods mentioned above.
*
* If this ComplicationDrawable is not inflated from an XML file, this method will reset the
- * style to match the default values, so if [ComplicationDrawable()] is used to construct a
- * ComplicationDrawable, this method should be called right after.
+ * style to match the default values, so if ComplicationDrawable(drawable: ComplicationDrawable)
+ * is used to construct a ComplicationDrawable, this method should be called right after.
+ *
+ * @param context The [Context] used to render the complication.
*/
public fun setContext(context: Context) {
if (context == this.context) {
@@ -556,8 +560,8 @@
}
/**
- * Sets the complication data to be drawn. If `complicationData` is `null`, nothing
- * will be drawn when [draw] is called.
+ * Sets the complication data to be drawn. If `complicationData` is `null`, nothing will be
+ * drawn when [draw] is called.
*
* @param complicationData The [ComplicationData] to set
* @param loadDrawablesAsync If true any drawables should be loaded asynchronously,
@@ -695,10 +699,10 @@
"ComplicationDrawable does not have a context. Use setContext(Context) to set it first."
}
}
+
/**
* The text to be rendered when [ComplicationData] is of type [NO_DATA]. If `noDataText` is
- * null, an empty text will be
- * rendered.
+ * null, an empty text will be rendered.
*/
public var noDataText: CharSequence? = null
set(noDataText) {
@@ -724,7 +728,7 @@
return drawable
}
- /** Sets the style to default values using resources. */
+ /** Sets the style to default values using resources. */
@JvmStatic
internal fun setStyleToDefaultValues(style: ComplicationStyle, r: Resources) {
style.backgroundColor = r.getColor(R.color.complicationDrawable_backgroundColor, null)
diff --git a/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java b/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
index 2c0dadd..868cee7 100644
--- a/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
+++ b/wear/wear-watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
@@ -174,7 +174,7 @@
/**
* Initializes complication renderer.
*
- * @param context Current context.
+ * @param context Current [Context].
* @param activeStyle ComplicationSlot style to be used when in active mode.
* @param ambientStyle ComplicationSlot style to be used when in ambient mode.
*/
diff --git a/wear/wear-watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/CanvasComplicationDrawableTest.kt b/wear/wear-watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/CanvasComplicationDrawableTest.kt
new file mode 100644
index 0000000..972e9fc
--- /dev/null
+++ b/wear/wear-watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/CanvasComplicationDrawableTest.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.complications.rendering
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Rect
+import android.icu.util.Calendar
+import android.icu.util.TimeZone
+import androidx.test.core.app.ApplicationProvider
+import androidx.wear.watchface.CanvasComplication
+import androidx.wear.watchface.DrawMode
+import androidx.wear.watchface.MutableWatchState
+import androidx.wear.watchface.RenderParameters
+import androidx.wear.watchface.TapEvent
+import androidx.wear.watchface.style.WatchFaceLayer
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+
+@RunWith(ComplicationsTestRunner::class)
+public class CanvasComplicationDrawableTest {
+ private val complicationDrawable =
+ ComplicationDrawable(ApplicationProvider.getApplicationContext())
+ private val watchState = MutableWatchState()
+ private val invalidateCallback = Mockito.mock(CanvasComplication.InvalidateCallback::class.java)
+ private val bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
+ private val bounds = Rect(0, 0, 100, 100)
+ private val canvas = Canvas(bitmap)
+ private val calendar = Calendar.getInstance(TimeZone.GMT_ZONE)
+ private val canvasComplicationDrawable = CanvasComplicationDrawable(
+ complicationDrawable,
+ watchState.asWatchState(),
+ invalidateCallback
+ )
+ private val slotId = 100
+
+ @Test
+ public fun render_ambientMode() {
+ canvasComplicationDrawable.render(
+ canvas,
+ bounds,
+ calendar,
+ RenderParameters(
+ DrawMode.AMBIENT,
+ setOf(WatchFaceLayer.BASE, WatchFaceLayer.COMPLICATIONS),
+ null,
+ emptyMap()
+ ),
+ slotId
+ )
+ assertThat(complicationDrawable.isInAmbientMode).isTrue()
+
+ canvasComplicationDrawable.render(
+ canvas,
+ bounds,
+ calendar,
+ RenderParameters(
+ DrawMode.INTERACTIVE,
+ setOf(WatchFaceLayer.BASE, WatchFaceLayer.COMPLICATIONS),
+ null,
+ emptyMap()
+ ),
+ slotId
+ )
+ assertThat(complicationDrawable.isInAmbientMode).isFalse()
+ }
+
+ @Test
+ public fun render_bounds() {
+ canvasComplicationDrawable.render(
+ canvas,
+ bounds,
+ calendar,
+ RenderParameters(
+ DrawMode.INTERACTIVE,
+ setOf(WatchFaceLayer.BASE, WatchFaceLayer.COMPLICATIONS),
+ null,
+ emptyMap()
+ ),
+ slotId
+ )
+ assertThat(complicationDrawable.bounds).isEqualTo(bounds)
+ }
+
+ @Test
+ public fun render_currentTimeMillis() {
+ calendar.timeInMillis = 1234
+ canvasComplicationDrawable.render(
+ canvas,
+ bounds,
+ calendar,
+ RenderParameters(
+ DrawMode.INTERACTIVE,
+ setOf(WatchFaceLayer.BASE, WatchFaceLayer.COMPLICATIONS),
+ null,
+ emptyMap()
+ ),
+ slotId
+ )
+ assertThat(complicationDrawable.currentTimeMillis).isEqualTo(1234)
+ }
+
+ @Test
+ public fun render_highlight() {
+ val renderParameters = RenderParameters(
+ DrawMode.INTERACTIVE,
+ setOf(WatchFaceLayer.BASE, WatchFaceLayer.COMPLICATIONS),
+ null,
+ mapOf(slotId to TapEvent(50, 50, 1100))
+ )
+
+ calendar.timeInMillis = 1099
+ canvasComplicationDrawable.render(canvas, bounds, calendar, renderParameters, slotId)
+ assertThat(complicationDrawable.isHighlighted).isFalse()
+
+ calendar.timeInMillis = 1100
+ canvasComplicationDrawable.render(canvas, bounds, calendar, renderParameters, slotId)
+ assertThat(complicationDrawable.isHighlighted).isTrue()
+
+ calendar.timeInMillis = 1099 + CanvasComplicationDrawable.COMPLICATION_HIGHLIGHT_DURATION_MS
+ canvasComplicationDrawable.render(canvas, bounds, calendar, renderParameters, slotId)
+ assertThat(complicationDrawable.isHighlighted).isTrue()
+
+ calendar.timeInMillis = 1100 + CanvasComplicationDrawable.COMPLICATION_HIGHLIGHT_DURATION_MS
+ canvasComplicationDrawable.render(canvas, bounds, calendar, renderParameters, slotId)
+ assertThat(complicationDrawable.isHighlighted).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/wear/wear-watchface-complications-rendering/src/test/resources/robolectric.properties b/wear/wear-watchface-complications-rendering/src/test/resources/robolectric.properties
index ce87047..ab64ba7 100644
--- a/wear/wear-watchface-complications-rendering/src/test/resources/robolectric.properties
+++ b/wear/wear-watchface-complications-rendering/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/wear/wear-watchface-data/api/restricted_current.txt b/wear/wear-watchface-data/api/restricted_current.txt
index 684c120..ecb5ee7 100644
--- a/wear/wear-watchface-data/api/restricted_current.txt
+++ b/wear/wear-watchface-data/api/restricted_current.txt
@@ -278,6 +278,17 @@
field public static final android.os.Parcelable.Creator<androidx.wear.watchface.data.IdAndComplicationStateWireFormat!>! CREATOR;
}
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.VersionedParcelize(allowSerialization=true) public final class IdAndTapEventWireFormat implements android.os.Parcelable androidx.versionedparcelable.VersionedParcelable {
+ ctor public IdAndTapEventWireFormat(int, int, int, long);
+ method public int describeContents();
+ method public long getCalendarTapTimeMillis();
+ method public int getId();
+ method public int getX();
+ method public int getY();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.wear.watchface.data.IdAndTapEventWireFormat!>! CREATOR;
+ }
+
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.VersionedParcelize public class LayerParameterWireFormat implements android.os.Parcelable androidx.versionedparcelable.VersionedParcelable {
ctor public LayerParameterWireFormat(int, int);
method public int describeContents();
@@ -288,7 +299,7 @@
}
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.VersionedParcelize public class RenderParametersWireFormat implements android.os.Parcelable androidx.versionedparcelable.VersionedParcelable {
- ctor public RenderParametersWireFormat(int, int, int, int, String?, @ColorInt int, @ColorInt int, int[]);
+ ctor public RenderParametersWireFormat(int, int, int, int, String?, @ColorInt int, @ColorInt int, java.util.List<androidx.wear.watchface.data.IdAndTapEventWireFormat!>);
method public int describeContents();
method @ColorInt public int getBackgroundTint();
method public int getDrawMode();
@@ -296,7 +307,7 @@
method public int getElementType();
method public String? getElementUserStyleSettingId();
method @ColorInt public int getHighlightTint();
- method public int[] getPressedComplicationSlotIds();
+ method public java.util.List<androidx.wear.watchface.data.IdAndTapEventWireFormat!>? getIdAndTapEventWireFormat();
method public int getWatchFaceLayerSetBitfield();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<androidx.wear.watchface.data.RenderParametersWireFormat!>! CREATOR;
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IdAndTapEventWireFormat.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IdAndTapEventWireFormat.java
new file mode 100644
index 0000000..2ea8987
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IdAndTapEventWireFormat.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.data;
+
+import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Px;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.ParcelUtils;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+/**
+ * Pair of a ComplicationSlotID and a TapEvent, the wire format of Map<Int, TapEvent>
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize(allowSerialization = true)
+@SuppressLint("BanParcelableUsage") // TODO(b/169214666): Remove Parcelable
+public final class IdAndTapEventWireFormat implements VersionedParcelable, Parcelable {
+
+ @ParcelField(1)
+ @Px
+ int mId;
+
+ @ParcelField(2)
+ @Px
+ int mX;
+
+ @ParcelField(3)
+ @Px
+ int mY;
+
+ @ParcelField(4)
+ @Px
+ long mCalendarTapTimeMillis;
+
+ IdAndTapEventWireFormat() {
+ }
+
+ public IdAndTapEventWireFormat(
+ int id,
+ int x,
+ int y,
+ long calendarTapTimeMillis) {
+ mId = id;
+ mX = x;
+ mY = y;
+ mCalendarTapTimeMillis = calendarTapTimeMillis;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public int getX() {
+ return mX;
+ }
+
+ public int getY() {
+ return mY;
+ }
+
+ public long getCalendarTapTimeMillis() {
+ return mCalendarTapTimeMillis;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Serializes this IdAndTapEventWireFormat to the specified {@link Parcel}. */
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeParcelable(ParcelUtils.toParcelable(this), flags);
+ }
+
+ public static final Parcelable.Creator<IdAndTapEventWireFormat> CREATOR =
+ new Parcelable.Creator<IdAndTapEventWireFormat>() {
+ @Override
+ public IdAndTapEventWireFormat createFromParcel(Parcel source) {
+ return ParcelUtils.fromParcelable(
+ source.readParcelable(getClass().getClassLoader()));
+ }
+
+ @Override
+ public IdAndTapEventWireFormat[] newArray(int size) {
+ return new IdAndTapEventWireFormat[size];
+ }
+ };
+}
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/RenderParametersWireFormat.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/RenderParametersWireFormat.java
index 59359aa..9c8c187 100644
--- a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/RenderParametersWireFormat.java
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/RenderParametersWireFormat.java
@@ -29,6 +29,8 @@
import androidx.versionedparcelable.VersionedParcelable;
import androidx.versionedparcelable.VersionedParcelize;
+import java.util.List;
+
/**
* Wire format for {@link androidx.wear.watchface.RenderParameters}.
*
@@ -108,10 +110,12 @@
@ColorInt
int mBackgroundTint;
+ // ParcelField(8) is reserved.
+
/** Optional set of ComplicationSlots to render as pressed. */
- @ParcelField(8)
- @NonNull
- int[] mPressedComplicationSlotIds = new int[0];
+ @ParcelField(9)
+ @Nullable
+ List<IdAndTapEventWireFormat> mIdAndTapEventWireFormats;
RenderParametersWireFormat() {
}
@@ -124,7 +128,7 @@
@Nullable String elementUserStyleSettingId,
@ColorInt int highlightTint,
@ColorInt int backgroundTint,
- @NonNull int[] pressedComplicationSlotIds) {
+ @NonNull List<IdAndTapEventWireFormat> idAndTapEventWireFormats) {
mDrawMode = drawMode;
mWatchFaceLayerSetBitfield = watchFaceLayerSetBitfield;
mElementType = elementType;
@@ -132,7 +136,7 @@
mElementUserStyleSettingId = elementUserStyleSettingId;
mHighlightTint = highlightTint;
mBackgroundTint = backgroundTint;
- mPressedComplicationSlotIds = pressedComplicationSlotIds;
+ mIdAndTapEventWireFormats = idAndTapEventWireFormats;
if (elementType == ELEMENT_TYPE_USER_STYLE) {
if (elementUserStyleSettingId == null) {
throw new IllegalArgumentException(
@@ -179,9 +183,9 @@
return mBackgroundTint;
}
- @NonNull
- public int[] getPressedComplicationSlotIds() {
- return mPressedComplicationSlotIds;
+ @Nullable
+ public List<IdAndTapEventWireFormat> getIdAndTapEventWireFormat() {
+ return mIdAndTapEventWireFormats;
}
/** Serializes this IndicatorState to the specified {@link Parcel}. */
diff --git a/wear/wear-watchface-editor-guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt b/wear/wear-watchface-editor-guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt
index e746e76..0c30a81 100644
--- a/wear/wear-watchface-editor-guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt
+++ b/wear/wear-watchface-editor-guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt
@@ -53,15 +53,15 @@
*
* If watch face editor takes more than 4s to create a watch face, returned future will be
* resolved with [TimeoutCancellationException] exception.
+ *
+ * @param activity The [ComponentActivity] associated with the EditorSession.
+ * @param editIntent [Intent] sent by SysUI to launch the editing session.
*/
@SuppressWarnings("ExecutorRegistration")
@JvmStatic
@UiThread
public fun listenableCreateOnWatchEditorSession(
- /** The [ComponentActivity] associated with the EditorSession. */
activity: ComponentActivity,
-
- /** [Intent] sent by SysUI to launch the editing session. */
editIntent: Intent
): ListenableFuture<ListenableEditorSession?> {
val result = ResolvableFuture.create<ListenableEditorSession?>()
@@ -85,17 +85,20 @@
return result
}
- /** Constructs an [ListenableEditorSession] for a remote watch face editor. */
+ /**
+ * Constructs an [ListenableEditorSession] for a remote watch face editor.
+ *
+ * @param activity The [ComponentActivity] associated with the EditorSession.
+ * @param editIntent [Intent] sent by SysUI to launch the editing session.
+ * @param headlessWatchFaceClient The [HeadlessWatchFaceClient] that backs the constructed
+ * EditorSession.
+ */
@JvmStatic
@RequiresApi(27)
@UiThread
public fun createHeadlessEditorSession(
- /** The [ComponentActivity] associated with the EditorSession. */
activity: ComponentActivity,
-
- /** [Intent] sent by SysUI to launch the editing session. */
editIntent: Intent,
-
headlessWatchFaceClient: HeadlessWatchFaceClient
): ListenableEditorSession = ListenableEditorSession(
EditorSession.createHeadlessEditorSession(
diff --git a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
index 28be503..39ad69f 100644
--- a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
+++ b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
@@ -82,10 +82,10 @@
*
* For EditorSessions backed by a headless instance (see [createHeadlessEditorSession] and
* [EditorRequest.headlessDeviceConfig]), style changes are not applied to the interactive
- * instance and it's up to the system to apply them. For EditorSessions backed by an
- * interactive instance style changes are applied immediately. Its possible the system might fail to
- * persist the style changes (e.g. to data base write failure or a crash) and if this happens its
- * the responsibility of the system to revert the style change.
+ * instance and it's up to the system to apply them. For EditorSessions backed by an interactive
+ * instance style changes are applied immediately. Its possible the system might fail to persist
+ * the style changes (e.g. to data base write failure or a crash) and if this happens it's the
+ * responsibility of the system to revert the style change.
*/
public interface EditorSession : AutoCloseable {
/** The [ComponentName] of the watch face being edited. */
@@ -99,8 +99,10 @@
@get:RequiresApi(Build.VERSION_CODES.R)
public val watchFaceId: WatchFaceId
- /** The current [UserStyle]. Assigning to this will cause the style to update. However, styling
- * changes to the watch face will be reverted upon exit. */
+ /**
+ * The current [UserStyle]. Assigning to this will cause the style to update. However, styling
+ * changes to the watch face will be reverted upon exit.
+ */
public var userStyle: UserStyle
/** The UTC reference preview time for this watch face in milliseconds since the epoch. */
diff --git a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
index 2cd6547..1e95ae4 100644
--- a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
+++ b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
@@ -53,8 +53,7 @@
* @param renderParameters The [RenderParameters] to use when rendering the screen shot
* @param calendarTimeMillis The UTC time in milliseconds since the epoch to render with. If
* [EditorSession.DEFAULT_PREVIEW_TIME_MILLIS] is passed then the watch face's default preview time
- * will be
- * used.
+ * will be used.
*/
public class PreviewScreenshotParams(
public val renderParameters: RenderParameters,
diff --git a/wear/wear-watchface-guava/src/test/resources/robolectric.properties b/wear/wear-watchface-guava/src/test/resources/robolectric.properties
index ce87047..ab64ba7 100644
--- a/wear/wear-watchface-guava/src/test/resources/robolectric.properties
+++ b/wear/wear-watchface-guava/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/wear/wear-watchface-samples-minimal-complications/src/main/AndroidManifest.xml b/wear/wear-watchface-samples-minimal-complications/src/main/AndroidManifest.xml
index e011344..1f06bf9 100644
--- a/wear/wear-watchface-samples-minimal-complications/src/main/AndroidManifest.xml
+++ b/wear/wear-watchface-samples-minimal-complications/src/main/AndroidManifest.xml
@@ -18,6 +18,7 @@
<activity
android:name=".ConfigActivity"
+ android:exported="true"
android:label="@string/configuration_title">
<intent-filter>
<action android:name="androidx.wear.watchface.editor.action.WATCH_FACE_EDITOR" />
diff --git a/wear/wear-watchface-samples-minimal-style/src/main/AndroidManifest.xml b/wear/wear-watchface-samples-minimal-style/src/main/AndroidManifest.xml
index 1852ba9..3b45f12 100644
--- a/wear/wear-watchface-samples-minimal-style/src/main/AndroidManifest.xml
+++ b/wear/wear-watchface-samples-minimal-style/src/main/AndroidManifest.xml
@@ -16,6 +16,7 @@
<activity
android:name=".ConfigActivity"
+ android:exported="true"
android:label="@string/configuration_title">
<intent-filter>
<action android:name="androidx.wear.watchface.editor.action.WATCH_FACE_EDITOR" />
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/CurrentUserStyleRepository.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/CurrentUserStyleRepository.kt
index 73891ce..cbe0b02 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/CurrentUserStyleRepository.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/CurrentUserStyleRepository.kt
@@ -34,14 +34,11 @@
* instance with [MutableUserStyle.toUserStyle].
*
* @param selectedOptions The [UserStyleSetting.Option] selected for each [UserStyleSetting]
+ * @param copySelectedOptions Whether to create a copy of the provided [selectedOptions]. If
+ * `false`, no mutable copy of the [selectedOptions] map should be retained outside this class.
*/
public class UserStyle private constructor(
- /** The selected option for each setting. */
selectedOptions: Map<UserStyleSetting, UserStyleSetting.Option>,
- /**
- * Whether to create a copy of the provided [selectedOptions]. If false, no mutable copy of
- * the [selectedOptions] map should be retained outside this class.
- */
copySelectedOptions: Boolean
) : Iterable<Map.Entry<UserStyleSetting, UserStyleSetting.Option>> {
private val selectedOptions =
@@ -322,8 +319,7 @@
* @param userStyleSettings The user configurable style categories associated with this watch face.
* Empty if the watch face doesn't support user styling. Note we allow at most one
* [UserStyleSetting.ComplicationSlotsUserStyleSetting] and one
- * [UserStyleSetting.CustomValueUserStyleSetting]
- * in the list.
+ * [UserStyleSetting.CustomValueUserStyleSetting] in the list.
*/
public class UserStyleSchema(
public val userStyleSettings: List<UserStyleSetting>
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt
index 86c8c07..cca7fe4 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt
@@ -261,8 +261,8 @@
* an arbitrary value depending on the nature of the style setting.
*
* @property id Machine readable [Id] for the style setting. Identifier for the option (or the
- * option itself for [CustomValueUserStyleSetting.CustomValueOption]), must be unique
- * within the UserStyleSetting. Short ids are encouraged.
+ * option itself for [CustomValueUserStyleSetting.CustomValueOption]), must be unique within
+ * the UserStyleSetting. Short ids are encouraged.
*/
public abstract class Option(public val id: Id) {
/**
@@ -278,6 +278,8 @@
/**
* Machine readable identifier for [Option]s. The length of this identifier may not exceed
* [MAX_LENGTH].
+ *
+ * @param value The [ByteArray] value of this Id.
*/
public class Id(public val value: ByteArray) {
/**
@@ -482,9 +484,11 @@
/** Returns the default value. */
public fun getDefaultValue(): Boolean = (options[defaultOptionIndex] as BooleanOption).value
- /** Represents a true or false option in the [BooleanUserStyleSetting]. */
+ /**
+ * Represents a true or false option in the [BooleanUserStyleSetting].
+ * @param value The boolean value this instance represents.
+ */
public class BooleanOption private constructor(
- /** The boolean value this instance represents. */
public val value: Boolean
) : Option(
Id(ByteArray(1).apply { this[0] = if (value) 1 else 0 })
@@ -560,8 +564,13 @@
@get:SuppressWarnings("AutoBoxing")
public val accessibilityTraversalIndex: Int? = null
) {
+ /**
+ * Constructs a [ComplicationSlotOverlay].Builder.
+ *
+ * @param complicationSlotId The id of the [androidx.wear.watchface.ComplicationSlot]
+ * to configure.
+ */
public class Builder(
- /** The id of the [androidx.wear.watchface.ComplicationSlot] to configure. */
private val complicationSlotId: Int
) {
private var enabled: Boolean? = null
@@ -1487,8 +1496,8 @@
)
/**
- * An application specific custom value. NB the [CustomValueOption.customValue] is the
- * same as the [CustomValueOption.id].
+ * An application specific custom value. NB the [CustomValueOption.customValue] is the same
+ * as the [CustomValueOption.id].
*/
public class CustomValueOption : Option {
/* The [ByteArray] value for this option which is the same as the [id]. */
diff --git a/wear/wear-watchface-style/src/test/resources/robolectric.properties b/wear/wear-watchface-style/src/test/resources/robolectric.properties
index ce87047..ab64ba7 100644
--- a/wear/wear-watchface-style/src/test/resources/robolectric.properties
+++ b/wear/wear-watchface-style/src/test/resources/robolectric.properties
@@ -1,3 +1,3 @@
-# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target
# sdk for now. Remove when no longer necessary.
-sdk=29
+sdk=30
diff --git a/wear/wear-watchface/api/current.txt b/wear/wear-watchface/api/current.txt
index 20299ac..90fb09f 100644
--- a/wear/wear-watchface/api/current.txt
+++ b/wear/wear-watchface/api/current.txt
@@ -81,15 +81,14 @@
public final class ComplicationSlotsManager {
ctor public ComplicationSlotsManager(java.util.Collection<androidx.wear.watchface.ComplicationSlot> complicationSlotCollection, androidx.wear.watchface.style.CurrentUserStyleRepository currentUserStyleRepository);
method @UiThread public void addTapListener(androidx.wear.watchface.ComplicationSlotsManager.TapCallback tapCallback);
- method @UiThread public void displayPressedAnimation(int complicationSlotId);
method public operator androidx.wear.watchface.ComplicationSlot? get(int id);
method public androidx.wear.watchface.ComplicationSlot? getBackgroundComplicationSlot();
method public androidx.wear.watchface.ComplicationSlot? getComplicationSlotAt(@Px int x, @Px int y);
method public java.util.Map<java.lang.Integer,androidx.wear.watchface.ComplicationSlot> getComplicationSlots();
- method public java.util.Set<java.lang.Integer> getPressedSlotIds();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> getLastComplicationTapDownEvents();
method @UiThread public void removeTapListener(androidx.wear.watchface.ComplicationSlotsManager.TapCallback tapCallback);
property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.ComplicationSlot> complicationSlots;
- property public final java.util.Set<java.lang.Integer> pressedSlotIds;
+ property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents;
}
public static interface ComplicationSlotsManager.TapCallback {
@@ -146,16 +145,16 @@
}
public final class RenderParameters {
- ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer, optional java.util.Set<java.lang.Integer> pressedComplicationSlotIds);
+ ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer, optional java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents);
ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer);
ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers);
method public androidx.wear.watchface.DrawMode getDrawMode();
method public androidx.wear.watchface.RenderParameters.HighlightLayer? getHighlightLayer();
- method public java.util.Set<java.lang.Integer> getPressedComplicationSlotIds();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> getLastComplicationTapDownEvents();
method public java.util.Set<androidx.wear.watchface.style.WatchFaceLayer> getWatchFaceLayers();
property public final androidx.wear.watchface.DrawMode drawMode;
property public final androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer;
- property public final java.util.Set<java.lang.Integer> pressedComplicationSlotIds;
+ property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents;
property public final java.util.Set<androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers;
field public static final androidx.wear.watchface.RenderParameters.Companion Companion;
field public static final androidx.wear.watchface.RenderParameters DEFAULT_INTERACTIVE;
@@ -260,6 +259,16 @@
method public boolean hitTest(androidx.wear.watchface.ComplicationSlot complicationSlot, android.graphics.Rect screenBounds, @Px int x, @Px int y);
}
+ public final class TapEvent {
+ ctor public TapEvent(@Px int xPos, @Px int yPos, long tapTimeMillis);
+ method public long getTapTimeMillis();
+ method public int getXPos();
+ method public int getYPos();
+ property public final long tapTimeMillis;
+ property public final int xPos;
+ property public final int yPos;
+ }
+
public final class WatchFace {
ctor public WatchFace(int watchFaceType, androidx.wear.watchface.Renderer renderer);
method public androidx.wear.watchface.WatchFace.LegacyWatchFaceOverlayStyle getLegacyWatchFaceStyle();
@@ -296,7 +305,7 @@
}
public static interface WatchFace.TapListener {
- method @UiThread public void onTap(int tapType, @Px int xPos, @Px int yPos);
+ method @UiThread public void onTapEvent(int tapType, androidx.wear.watchface.TapEvent tapEvent);
}
public final class WatchFaceKt {
diff --git a/wear/wear-watchface/api/public_plus_experimental_current.txt b/wear/wear-watchface/api/public_plus_experimental_current.txt
index 20299ac..90fb09f 100644
--- a/wear/wear-watchface/api/public_plus_experimental_current.txt
+++ b/wear/wear-watchface/api/public_plus_experimental_current.txt
@@ -81,15 +81,14 @@
public final class ComplicationSlotsManager {
ctor public ComplicationSlotsManager(java.util.Collection<androidx.wear.watchface.ComplicationSlot> complicationSlotCollection, androidx.wear.watchface.style.CurrentUserStyleRepository currentUserStyleRepository);
method @UiThread public void addTapListener(androidx.wear.watchface.ComplicationSlotsManager.TapCallback tapCallback);
- method @UiThread public void displayPressedAnimation(int complicationSlotId);
method public operator androidx.wear.watchface.ComplicationSlot? get(int id);
method public androidx.wear.watchface.ComplicationSlot? getBackgroundComplicationSlot();
method public androidx.wear.watchface.ComplicationSlot? getComplicationSlotAt(@Px int x, @Px int y);
method public java.util.Map<java.lang.Integer,androidx.wear.watchface.ComplicationSlot> getComplicationSlots();
- method public java.util.Set<java.lang.Integer> getPressedSlotIds();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> getLastComplicationTapDownEvents();
method @UiThread public void removeTapListener(androidx.wear.watchface.ComplicationSlotsManager.TapCallback tapCallback);
property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.ComplicationSlot> complicationSlots;
- property public final java.util.Set<java.lang.Integer> pressedSlotIds;
+ property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents;
}
public static interface ComplicationSlotsManager.TapCallback {
@@ -146,16 +145,16 @@
}
public final class RenderParameters {
- ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer, optional java.util.Set<java.lang.Integer> pressedComplicationSlotIds);
+ ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer, optional java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents);
ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer);
ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers);
method public androidx.wear.watchface.DrawMode getDrawMode();
method public androidx.wear.watchface.RenderParameters.HighlightLayer? getHighlightLayer();
- method public java.util.Set<java.lang.Integer> getPressedComplicationSlotIds();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> getLastComplicationTapDownEvents();
method public java.util.Set<androidx.wear.watchface.style.WatchFaceLayer> getWatchFaceLayers();
property public final androidx.wear.watchface.DrawMode drawMode;
property public final androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer;
- property public final java.util.Set<java.lang.Integer> pressedComplicationSlotIds;
+ property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents;
property public final java.util.Set<androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers;
field public static final androidx.wear.watchface.RenderParameters.Companion Companion;
field public static final androidx.wear.watchface.RenderParameters DEFAULT_INTERACTIVE;
@@ -260,6 +259,16 @@
method public boolean hitTest(androidx.wear.watchface.ComplicationSlot complicationSlot, android.graphics.Rect screenBounds, @Px int x, @Px int y);
}
+ public final class TapEvent {
+ ctor public TapEvent(@Px int xPos, @Px int yPos, long tapTimeMillis);
+ method public long getTapTimeMillis();
+ method public int getXPos();
+ method public int getYPos();
+ property public final long tapTimeMillis;
+ property public final int xPos;
+ property public final int yPos;
+ }
+
public final class WatchFace {
ctor public WatchFace(int watchFaceType, androidx.wear.watchface.Renderer renderer);
method public androidx.wear.watchface.WatchFace.LegacyWatchFaceOverlayStyle getLegacyWatchFaceStyle();
@@ -296,7 +305,7 @@
}
public static interface WatchFace.TapListener {
- method @UiThread public void onTap(int tapType, @Px int xPos, @Px int yPos);
+ method @UiThread public void onTapEvent(int tapType, androidx.wear.watchface.TapEvent tapEvent);
}
public final class WatchFaceKt {
diff --git a/wear/wear-watchface/api/restricted_current.txt b/wear/wear-watchface/api/restricted_current.txt
index dea99d6..0469576 100644
--- a/wear/wear-watchface/api/restricted_current.txt
+++ b/wear/wear-watchface/api/restricted_current.txt
@@ -143,15 +143,14 @@
public final class ComplicationSlotsManager {
ctor public ComplicationSlotsManager(java.util.Collection<androidx.wear.watchface.ComplicationSlot> complicationSlotCollection, androidx.wear.watchface.style.CurrentUserStyleRepository currentUserStyleRepository);
method @UiThread public void addTapListener(androidx.wear.watchface.ComplicationSlotsManager.TapCallback tapCallback);
- method @UiThread public void displayPressedAnimation(int complicationSlotId);
method public operator androidx.wear.watchface.ComplicationSlot? get(int id);
method public androidx.wear.watchface.ComplicationSlot? getBackgroundComplicationSlot();
method public androidx.wear.watchface.ComplicationSlot? getComplicationSlotAt(@Px int x, @Px int y);
method public java.util.Map<java.lang.Integer,androidx.wear.watchface.ComplicationSlot> getComplicationSlots();
- method public java.util.Set<java.lang.Integer> getPressedSlotIds();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> getLastComplicationTapDownEvents();
method @UiThread public void removeTapListener(androidx.wear.watchface.ComplicationSlotsManager.TapCallback tapCallback);
property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.ComplicationSlot> complicationSlots;
- property public final java.util.Set<java.lang.Integer> pressedSlotIds;
+ property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents;
field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @VisibleForTesting public androidx.wear.watchface.WatchState watchState;
}
@@ -240,18 +239,18 @@
}
public final class RenderParameters {
- ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer, optional java.util.Set<java.lang.Integer> pressedComplicationSlotIds);
+ ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer, optional java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents);
ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers, optional androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer);
ctor public RenderParameters(androidx.wear.watchface.DrawMode drawMode, java.util.Set<? extends androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers);
ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public RenderParameters(androidx.wear.watchface.data.RenderParametersWireFormat wireFormat);
method public androidx.wear.watchface.DrawMode getDrawMode();
method public androidx.wear.watchface.RenderParameters.HighlightLayer? getHighlightLayer();
- method public java.util.Set<java.lang.Integer> getPressedComplicationSlotIds();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> getLastComplicationTapDownEvents();
method public java.util.Set<androidx.wear.watchface.style.WatchFaceLayer> getWatchFaceLayers();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.wear.watchface.data.RenderParametersWireFormat toWireFormat();
property public final androidx.wear.watchface.DrawMode drawMode;
property public final androidx.wear.watchface.RenderParameters.HighlightLayer? highlightLayer;
- property public final java.util.Set<java.lang.Integer> pressedComplicationSlotIds;
+ property public final java.util.Map<java.lang.Integer,androidx.wear.watchface.TapEvent> lastComplicationTapDownEvents;
property public final java.util.Set<androidx.wear.watchface.style.WatchFaceLayer> watchFaceLayers;
field public static final androidx.wear.watchface.RenderParameters.Companion Companion;
field public static final androidx.wear.watchface.RenderParameters DEFAULT_INTERACTIVE;
@@ -356,6 +355,16 @@
method public boolean hitTest(androidx.wear.watchface.ComplicationSlot complicationSlot, android.graphics.Rect screenBounds, @Px int x, @Px int y);
}
+ public final class TapEvent {
+ ctor public TapEvent(@Px int xPos, @Px int yPos, long tapTimeMillis);
+ method public long getTapTimeMillis();
+ method public int getXPos();
+ method public int getYPos();
+ property public final long tapTimeMillis;
+ property public final int xPos;
+ property public final int yPos;
+ }
+
public final class WatchFace {
ctor public WatchFace(int watchFaceType, androidx.wear.watchface.Renderer renderer);
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @UiThread @VisibleForTesting public static void clearAllEditorDelegates();
@@ -423,7 +432,7 @@
}
public static interface WatchFace.TapListener {
- method @UiThread public void onTap(int tapType, @Px int xPos, @Px int yPos);
+ method @UiThread public void onTapEvent(int tapType, androidx.wear.watchface.TapEvent tapEvent);
}
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public interface WatchFaceHostApi {
diff --git a/wear/wear-watchface/lint-baseline.xml b/wear/wear-watchface/lint-baseline.xml
index 440a9f8..0dbe68b 100644
--- a/wear/wear-watchface/lint-baseline.xml
+++ b/wear/wear-watchface/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
+<issues format="6" by="lint 7.1.0-alpha03" type="baseline" client="gradle" name="AGP (7.1.0-alpha03)" variant="all" version="7.1.0-alpha03">
<issue
id="MissingClass"
@@ -250,7 +250,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="291"
+ line="292"
column="34"/>
</issue>
@@ -261,7 +261,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="329"
+ line="330"
column="38"/>
</issue>
@@ -272,7 +272,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="367"
+ line="368"
column="38"/>
</issue>
@@ -283,7 +283,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="412"
+ line="413"
column="14"/>
</issue>
@@ -294,7 +294,7 @@
errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="462"
+ line="463"
column="38"/>
</issue>
@@ -305,95 +305,18 @@
errorLine2=" ~~~~~~~">
<location
file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="468"
+ line="469"
column="38"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 27 (current min is 25): `ashmemReadImageBundle`"
- errorLine1=" bitmap = SharedMemoryImage.ashmemReadImageBundle("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="545"
- column="40"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 27 (current min is 25): `ashmemReadImageBundle`"
- errorLine1=" bitmap = SharedMemoryImage.ashmemReadImageBundle("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="579"
- column="40"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 27 (current min is 25): `ashmemReadImageBundle`"
- errorLine1=" bitmap = SharedMemoryImage.ashmemReadImageBundle("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="632"
- column="40"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 27 (current min is 25): `ashmemReadImageBundle`"
- errorLine1=" bitmap = SharedMemoryImage.ashmemReadImageBundle("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="670"
- column="40"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 27 (current min is 25): `ashmemReadImageBundle`"
- errorLine1=" bitmap = SharedMemoryImage.ashmemReadImageBundle("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="732"
- column="40"/>
- </issue>
-
- <issue
- id="NewApi"
message="Call requires API level 26 (current min is 25): `android.view.SurfaceHolder#lockHardwareCanvas`"
errorLine1=" Mockito.`when`(surfaceHolder.lockHardwareCanvas()).thenReturn(canvas)"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="760"
- column="38"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 27 (current min is 25): `sendTouchEvent`"
- errorLine1=" interactiveWatchFaceInstance.sendTouchEvent("
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="828"
- column="38"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 27 (current min is 25): `release`"
- errorLine1=" interactiveWatchFaceInstance.release()"
- errorLine2=" ~~~~~~~">
- <location
- file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt"
- line="835"
+ line="802"
column="38"/>
</issue>
@@ -404,7 +327,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="430"
+ line="434"
column="14"/>
</issue>
@@ -415,7 +338,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2654"
+ line="2699"
column="14"/>
</issue>
@@ -426,7 +349,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2720"
+ line="2765"
column="31"/>
</issue>
@@ -437,7 +360,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2754"
+ line="2939"
column="32"/>
</issue>
@@ -448,7 +371,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2754"
+ line="2939"
column="22"/>
</issue>
@@ -459,7 +382,7 @@
errorLine2=" ~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2755"
+ line="2940"
column="20"/>
</issue>
@@ -470,7 +393,7 @@
errorLine2=" ~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2756"
+ line="2941"
column="11"/>
</issue>
@@ -481,7 +404,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2759"
+ line="2944"
column="22"/>
</issue>
@@ -492,7 +415,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2759"
+ line="2944"
column="32"/>
</issue>
@@ -503,7 +426,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2760"
+ line="2945"
column="31"/>
</issue>
@@ -514,7 +437,7 @@
errorLine2=" ~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2761"
+ line="2946"
column="20"/>
</issue>
@@ -525,18 +448,40 @@
errorLine2=" ~~~~~">
<location
file="src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt"
- line="2762"
+ line="2947"
column="11"/>
</issue>
<issue
+ id="WrongThread"
+ message="Method addUserStyleChangeListener must be called from the UI thread, currently inferred thread is worker thread"
+ errorLine1=" currentUserStyleRepository.addUserStyleChangeListener("
+ errorLine2=" ^">
+ <location
+ file="src/test/java/androidx/wear/watchface/TestCommon.kt"
+ line="89"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="WrongThread"
+ message="Method addTapListener must be called from the UI thread, currently inferred thread is worker thread"
+ errorLine1=" complicationSlotsManager.addTapListener("
+ errorLine2=" ^">
+ <location
+ file="src/test/java/androidx/wear/watchface/TestCommon.kt"
+ line="99"
+ column="9"/>
+ </issue>
+
+ <issue
id="ClassVerificationFailure"
message="This call references a method added in API level 30; however, the containing class androidx.wear.watchface.WatchFaceImpl is reachable from earlier API levels and will fail run-time class verification."
errorLine1=" renderer.surfaceHolder.surface.setFrameRate("
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/wear/watchface/WatchFace.kt"
- line="528"
+ line="593"
column="44"/>
</issue>
diff --git a/wear/wear-watchface/src/androidTest/AndroidManifest.xml b/wear/wear-watchface/src/androidTest/AndroidManifest.xml
index b18d5a3c..732a3b9 100644
--- a/wear/wear-watchface/src/androidTest/AndroidManifest.xml
+++ b/wear/wear-watchface/src/androidTest/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.wear.watchface.test">
<application android:requestLegacyExternalStorage="true">
- <activity android:name=".ComplicationTapActivity"/>
+ <activity android:name=".ComplicationTapActivity" android:exported="false"/>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
index 314edbe..d1d7dbe 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
@@ -50,6 +50,7 @@
import androidx.wear.watchface.MutableWatchState
import androidx.wear.watchface.RenderParameters
import androidx.wear.watchface.Renderer
+import androidx.wear.watchface.TapEvent
import androidx.wear.watchface.TapType
import androidx.wear.watchface.WatchFace
import androidx.wear.watchface.WatchFaceService
@@ -679,7 +680,10 @@
DrawMode.INTERACTIVE,
WatchFaceLayer.ALL_WATCH_FACE_LAYERS,
null,
- setOf(EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID)
+ mapOf(
+ EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID to
+ TapEvent(1, 1, 123456789)
+ )
).toWireFormat(),
123456789,
null,
diff --git a/wear/wear-watchface/src/main/AndroidManifest.xml b/wear/wear-watchface/src/main/AndroidManifest.xml
index af4bd44..85cb6cf 100644
--- a/wear/wear-watchface/src/main/AndroidManifest.xml
+++ b/wear/wear-watchface/src/main/AndroidManifest.xml
@@ -27,6 +27,7 @@
<service
android:name="androidx.wear.watchface.control.WatchFaceControlService"
android:enabled="@bool/watch_face_instance_service_enabled"
+ android:exported="true"
android:permission="com.google.android.wearable.permission.BIND_WATCH_FACE_CONTROL">
<meta-data android:name="androidx.wear.watchface.api_version" android:value="3" />
<intent-filter>
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
index 5a639a5..f91f60a 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
@@ -38,7 +38,6 @@
import androidx.wear.watchface.style.UserStyle
import androidx.wear.watchface.style.UserStyleSetting.ComplicationSlotsUserStyleSetting
import androidx.wear.watchface.style.UserStyleSetting.ComplicationSlotsUserStyleSetting.ComplicationSlotsOption
-import java.lang.ref.WeakReference
private fun getComponentName(context: Context) = ComponentName(
context.packageName,
@@ -90,8 +89,11 @@
public val complicationSlots: Map<Int, ComplicationSlot> =
complicationSlotCollection.associateBy(ComplicationSlot::id)
- /** The set of slot ids that are rendered as pressed. */
- public val pressedSlotIds: Set<Int> = HashSet()
+ /**
+ * Map of [ComplicationSlot] id to the latest [TapType.DOWN] [TapEvent] that the
+ * ComplicationSlot received, if any.
+ */
+ public val lastComplicationTapDownEvents: Map<Int, TapEvent> = HashMap()
private class InitialComplicationConfig(
val complicationSlotBounds: ComplicationSlotBounds,
@@ -278,31 +280,6 @@
}
/**
- * Starts a short animation, briefly highlighting the complication to provide visual feedback
- * when the user has tapped on it.
- *
- * @param complicationSlotId The ID of the complication slot to briefly highlight
- */
- @UiThread
- public fun displayPressedAnimation(complicationSlotId: Int) {
- requireNotNull(complicationSlots[complicationSlotId]) {
- "No complication found with ID $complicationSlotId"
- }
- (pressedSlotIds as HashSet<Int>).add(complicationSlotId)
-
- val weakRef = WeakReference(this)
- watchFaceHostApi.getUiThreadHandler().postDelayed(
- {
- // The watch face might go away before this can run.
- if (weakRef.get() != null) {
- pressedSlotIds.remove(complicationSlotId)
- }
- },
- WatchFaceImpl.CANCEL_COMPLICATION_HIGHLIGHTED_DELAY_MS
- )
- }
-
- /**
* Returns the id of the complication slot at coordinates x, y or `null` if there isn't one.
*
* @param x The x coordinate of the point to perform a hit test
@@ -361,6 +338,11 @@
}
}
+ @UiThread
+ internal fun onTapDown(complicationSlotId: Int, tapEvent: TapEvent) {
+ (lastComplicationTapDownEvents as HashMap)[complicationSlotId] = tapEvent
+ }
+
/**
* Adds a [TapCallback] which is called whenever the user interacts with a complication slot.
*/
@@ -381,7 +363,11 @@
@UiThread
internal fun dump(writer: IndentingPrintWriter) {
writer.println("ComplicationSlotsManager:")
- writer.println("renderer.pressedSlotIds=${pressedSlotIds.joinToString()}")
+ writer.println(
+ "lastComplicationTapDownEvents=" + lastComplicationTapDownEvents.map {
+ it.key.toString() + "->" + it.value
+ }.joinToString(", ")
+ )
writer.increaseIndent()
for ((_, complication) in complicationSlots) {
complication.dump(writer)
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/RenderParameters.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/RenderParameters.kt
index 8b66e7f..f2d75bcb0 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/RenderParameters.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/RenderParameters.kt
@@ -20,6 +20,7 @@
import androidx.annotation.ColorInt
import androidx.annotation.RestrictTo
import androidx.wear.watchface.RenderParameters.HighlightLayer
+import androidx.wear.watchface.data.IdAndTapEventWireFormat
import androidx.wear.watchface.data.RenderParametersWireFormat
import androidx.wear.watchface.style.WatchFaceLayer
import androidx.wear.watchface.style.UserStyleSetting
@@ -81,13 +82,14 @@
* @param highlightLayer Optional [HighlightLayer] used by editors to visually highlight an
* aspect of the watch face. Rendered last on top of [watchFaceLayers]. If highlighting isn't needed
* this will be `null`.
- * @param pressedComplicationSlotIds A set of [ComplicationSlot.id]s to render as pressed.
+ * @param lastComplicationTapDownEvents Map of [ComplicationSlot] id to the latest [TapType.DOWN]
+ * [TapEvent] that ComplicationSlot received, if any.
*/
public class RenderParameters @JvmOverloads constructor(
public val drawMode: DrawMode,
public val watchFaceLayers: Set<WatchFaceLayer>,
public val highlightLayer: HighlightLayer? = null,
- public val pressedComplicationSlotIds: Set<Int> = emptySet()
+ public val lastComplicationTapDownEvents: Map<Int, TapEvent> = emptyMap()
) {
init {
require(watchFaceLayers.isNotEmpty() || highlightLayer != null) {
@@ -243,13 +245,23 @@
else -> null
},
- wireFormat.pressedComplicationSlotIds.toSet()
+ wireFormat.idAndTapEventWireFormat?.associate {
+ Pair(it.id, TapEvent(it.x, it.y, it.calendarTapTimeMillis))
+ } ?: emptyMap()
)
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
- public fun toWireFormat(): RenderParametersWireFormat =
- when (val thingHighlighted = highlightLayer?.highlightedElement) {
+ public fun toWireFormat(): RenderParametersWireFormat {
+ val idAndTapEventWireFormats = lastComplicationTapDownEvents.map {
+ IdAndTapEventWireFormat(
+ it.key,
+ it.value.xPos,
+ it.value.yPos,
+ it.value.tapTimeMillis
+ )
+ }
+ return when (val thingHighlighted = highlightLayer?.highlightedElement) {
is HighlightedElement.AllComplicationSlots -> RenderParametersWireFormat(
drawMode.ordinal,
computeLayersBitfield(),
@@ -258,7 +270,7 @@
null,
highlightLayer!!.highlightTint,
highlightLayer.backgroundTint,
- pressedComplicationSlotIds.toIntArray()
+ idAndTapEventWireFormats
)
is HighlightedElement.ComplicationSlot -> RenderParametersWireFormat(
@@ -269,7 +281,7 @@
null,
highlightLayer!!.highlightTint,
highlightLayer.backgroundTint,
- pressedComplicationSlotIds.toIntArray()
+ idAndTapEventWireFormats
)
is HighlightedElement.UserStyle -> RenderParametersWireFormat(
@@ -280,7 +292,7 @@
thingHighlighted.id.value,
highlightLayer!!.highlightTint,
highlightLayer.backgroundTint,
- pressedComplicationSlotIds.toIntArray()
+ idAndTapEventWireFormats
)
else -> RenderParametersWireFormat(
@@ -291,9 +303,10 @@
null,
Color.BLACK,
Color.BLACK,
- pressedComplicationSlotIds.toIntArray()
+ idAndTapEventWireFormats
)
}
+ }
private fun computeLayersBitfield(): Int {
var bitfield = 0
@@ -310,6 +323,11 @@
writer.increaseIndent()
writer.println("drawMode=${drawMode.name}")
writer.println("watchFaceLayers=${watchFaceLayers.joinToString()}")
+ writer.println(
+ "lastComplicationTapDownEvents=" + lastComplicationTapDownEvents.map {
+ it.key.toString() + "->" + it.value
+ }.joinToString(", ")
+ )
highlightLayer?.let {
writer.println("HighlightLayer:")
@@ -349,7 +367,7 @@
if (drawMode != other.drawMode) return false
if (watchFaceLayers != other.watchFaceLayers) return false
if (highlightLayer != other.highlightLayer) return false
- if (pressedComplicationSlotIds != other.pressedComplicationSlotIds) return false
+ if (lastComplicationTapDownEvents != other.lastComplicationTapDownEvents) return false
return true
}
@@ -358,7 +376,7 @@
var result = drawMode.hashCode()
result = 31 * result + watchFaceLayers.hashCode()
result = 31 * result + (highlightLayer?.hashCode() ?: 0)
- result = 31 * result + pressedComplicationSlotIds.hashCode()
+ result = 31 * result + lastComplicationTapDownEvents.hashCode()
return result
}
}
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
index 083f409..0da2f9f 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
@@ -316,9 +316,9 @@
* @param interactiveDrawModeUpdateDelayMillis The interval in milliseconds between frames in
* interactive [DrawMode]s. To render at 60hz set to 16. Note when battery is low, the frame
* rate will be clamped to 10fps. Watch faces are recommended to use lower frame rates if
- * possible for better battery life. Variable frame rates can also help preserve battery
- * life, e.g. if a watch face has a short animation once per second it can adjust the frame
- * rate inorder to sleep when not animating.
+ * possible for better battery life. Variable frame rates can also help preserve battery life,
+ * e.g. if a watch face has a short animation once per second it can adjust the framerate
+ * inorder to sleep when not animating.
*/
public abstract class CanvasRenderer @WorkerThread constructor(
surfaceHolder: SurfaceHolder,
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/TapEvent.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/TapEvent.kt
new file mode 100644
index 0000000..87e91a5
--- /dev/null
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/TapEvent.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface
+
+import androidx.annotation.IntDef
+import androidx.annotation.Px
+import androidx.wear.watchface.control.IInteractiveWatchFace
+
+/** @hide */
+@IntDef(
+ value = [
+ TapType.DOWN,
+ TapType.UP,
+ TapType.CANCEL
+ ]
+)
+public annotation class TapType {
+ public companion object {
+ /**
+ * Used to indicate a "down" touch event on the watch face.
+ *
+ * The watch face will receive an [UP] or a [CANCEL] event to follow this event, to
+ * indicate whether this down event corresponds to a tap gesture to be handled by the watch
+ * face, or a different type of gesture that is handled by the system, respectively.
+ */
+ public const val DOWN: Int = IInteractiveWatchFace.TAP_TYPE_DOWN
+
+ /**
+ * Used in to indicate that a previous [TapType.DOWN] touch event has been canceled. This
+ * generally happens when the watch face is touched but then a move or long press occurs.
+ *
+ * The watch face should not trigger any action, as the system is already processing the
+ * gesture.
+ */
+ public const val CANCEL: Int = IInteractiveWatchFace.TAP_TYPE_CANCEL
+
+ /**
+ * Used to indicate that an "up" event on the watch face has occurred that has not been
+ * consumed by the system. A [TapType.DOWN] will always occur first. This event will not
+ * be sent if a [TapType.CANCEL] is sent.
+ *
+ * Therefore, a [TapType.DOWN] event and the successive [TapType.UP] event are guaranteed
+ * to be close enough to be considered a tap according to the value returned by
+ * [android.view.ViewConfiguration.getScaledTouchSlop].
+ */
+ public const val UP: Int = IInteractiveWatchFace.TAP_TYPE_UP
+ }
+}
+
+/**
+ * An input event received by the watch face.
+ *
+ * @param xPos X coordinate of the event
+ * @param yPos Y coordinate of the event
+ * @param tapTimeMillis The UTC time of the tap in milliseconds since the epoch
+ */
+public class TapEvent(
+ @Px public val xPos: Int,
+ @Px public val yPos: Int,
+ public val tapTimeMillis: Long // TODO(b/195536041): Maybe use Instant
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as TapEvent
+
+ if (xPos != other.xPos) return false
+ if (yPos != other.yPos) return false
+ if (tapTimeMillis != other.tapTimeMillis) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = xPos
+ result = 31 * result + yPos
+ result = 31 * result + tapTimeMillis.hashCode()
+ return result
+ }
+
+ override fun toString(): String = "[$xPos, $yPos @$tapTimeMillis]"
+}
\ No newline at end of file
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
index 7599696..c53d63b 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
@@ -38,7 +38,6 @@
import androidx.annotation.ColorInt
import androidx.annotation.IntDef
import androidx.annotation.IntRange
-import androidx.annotation.Px
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.annotation.UiThread
@@ -64,7 +63,7 @@
import kotlin.math.max
// Human reaction time is limited to ~100ms.
-private const val MIN_PERCEPTABLE_DELAY_MILLIS = 100
+private const val MIN_PERCEPTIBLE_DELAY_MILLIS = 100
// Zero is a special value meaning we will accept the system's choice for the
// display frame rate, which is the default behavior if this function isn't called.
@@ -277,15 +276,10 @@
* the system is already processing the gesture.
*
* @param tapType the type of touch event sent to the watch face
- * @param xPos the horizontal position in pixels on the screen where the touch happened
- * @param yPos the vertical position in pixels on the screen where the touch happened
+ * @param tapEvent the received [TapEvent]
*/
@UiThread
- public fun onTap(
- @TapType tapType: Int,
- @Px xPos: Int,
- @Px yPos: Int
- )
+ public fun onTapEvent(@TapType tapType: Int, tapEvent: TapEvent)
}
/**
@@ -429,9 +423,6 @@
// clamp the framerate to a maximum of 10fps to conserve power.
internal const val MAX_LOW_POWER_INTERACTIVE_UPDATE_RATE_MS = 100L
- // Complications are highlighted when tapped and after this delay the highlight is removed.
- internal const val CANCEL_COMPLICATION_HIGHLIGHTED_DELAY_MS = 300L
-
// The threshold used to judge whether the battery is low during initialization. Ideally
// we would use the threshold for Intent.ACTION_BATTERY_LOW but it's not documented or
// available programmatically. The value below is the default but it could be overridden
@@ -446,28 +437,28 @@
DrawMode.AMBIENT,
WatchFaceLayer.ALL_WATCH_FACE_LAYERS,
null,
- complicationSlotsManager.pressedSlotIds
+ complicationSlotsManager.lastComplicationTapDownEvents
),
DrawMode.INTERACTIVE to
RenderParameters(
DrawMode.INTERACTIVE,
WatchFaceLayer.ALL_WATCH_FACE_LAYERS,
null,
- complicationSlotsManager.pressedSlotIds
+ complicationSlotsManager.lastComplicationTapDownEvents
),
DrawMode.LOW_BATTERY_INTERACTIVE to
RenderParameters(
DrawMode.LOW_BATTERY_INTERACTIVE,
WatchFaceLayer.ALL_WATCH_FACE_LAYERS,
null,
- complicationSlotsManager.pressedSlotIds
+ complicationSlotsManager.lastComplicationTapDownEvents
),
DrawMode.MUTE to
RenderParameters(
DrawMode.MUTE,
WatchFaceLayer.ALL_WATCH_FACE_LAYERS,
null,
- complicationSlotsManager.pressedSlotIds
+ complicationSlotsManager.lastComplicationTapDownEvents
),
)
@@ -628,20 +619,17 @@
}
internal fun invalidateIfNotAnimating() {
- // Ensure we render a frame if the ComplicationSlot needs rendering, e.g.
- // because it loaded an image. However if we're animating there's no need
- // to trigger an extra invalidation.
+ // Ensure we render a frame if the ComplicationSlot needs rendering, e.g. because it loaded
+ // an image. However if we're animating there's no need to trigger an extra invalidation.
if (!renderer.shouldAnimate() || computeDelayTillNextFrame(
nextDrawTimeMillis,
systemTimeProvider.getSystemTimeMillis()
- ) > MIN_PERCEPTABLE_DELAY_MILLIS
+ ) > MIN_PERCEPTIBLE_DELAY_MILLIS
) {
watchFaceHostApi.invalidate()
}
}
- internal fun createWFEditorDelegate() = WFEditorDelegate() as WatchFace.EditorDelegate
-
internal inner class WFEditorDelegate : WatchFace.EditorDelegate {
override val userStyleSchema: UserStyleSchema
get() = currentUserStyleRepository.schema
@@ -716,9 +704,8 @@
(batteryPercent < INITIAL_LOW_BATTERY_THRESHOLD) && !isCharging
}
- /**
- * Called by the system in response to remote configuration, on the main thread.
- */
+ /** Called by the system in response to remote configuration. */
+ @UiThread
internal fun onSetStyleInternal(style: UserStyle) {
// No need to echo the userStyle back.
inOnSetStyle = true
@@ -778,9 +765,8 @@
}
}
- /**
- * Sets the calendar's time in milliseconds adjusted by the mock time controls.
- */
+ /** Sets the calendar's time in milliseconds adjusted by the mock time controls. */
+ @UiThread
private fun setCalendarTime(timeMillis: Long) {
// This adjustment allows time to be sped up or slowed down and to wrap between two
// instants. This is useful when developing animations that occur infrequently (e.g.
@@ -860,7 +846,7 @@
// Drop frames if needed (happens when onDraw is slow).
if (nextFrameTimeMillis <= currentTimeMillis) {
// Compute the next runtime after currentTimeMillis with the same phase as
- // beginFrameTimeMillis to keep the animation smooth.
+ // beginFrameTimeMillis to keep the animation smooth.
val phaseAdjust =
updateRateMillis +
((nextFrameTimeMillis - currentTimeMillis) % updateRateMillis)
@@ -892,21 +878,17 @@
* Called when a tap or touch related event occurs. Detects taps on [ComplicationSlot]s and
* triggers the associated action.
*
- * @param tapType Value representing the event sent to the wallpaper
- * @param x X coordinate of the event
- * @param y Y coordinate of the event
+ * @param tapType The [TapType] of the event
+ * @param tapEvent The received [TapEvent]
*/
@UiThread
- internal fun onTapCommand(
- @TapType tapType: Int,
- x: Int,
- y: Int
- ) {
- val tappedComplication = complicationSlotsManager.getComplicationSlotAt(x, y)
+ internal fun onTapCommand(@TapType tapType: Int, tapEvent: TapEvent) {
+ val tappedComplication =
+ complicationSlotsManager.getComplicationSlotAt(tapEvent.xPos, tapEvent.yPos)
if (tappedComplication == null) {
// The event does not belong to any of the complicationSlots, pass to the listener.
lastTappedComplicationId = null
- tapListener?.onTap(tapType, x, y)
+ tapListener?.onTapEvent(tapType, tapEvent)
return
}
@@ -920,12 +902,12 @@
lastTappedComplicationId = null
return
}
- complicationSlotsManager.displayPressedAnimation(tappedComplication.id)
complicationSlotsManager.onComplicationSlotSingleTapped(tappedComplication.id)
watchFaceHostApi.invalidate()
lastTappedComplicationId = null
}
TapType.DOWN -> {
+ complicationSlotsManager.onTapDown(tappedComplication.id, tapEvent)
lastTappedComplicationId = tappedComplication.id
}
else -> lastTappedComplicationId = null
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceHostApi.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceHostApi.kt
index f25d5ad..4d940fe 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceHostApi.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceHostApi.kt
@@ -90,16 +90,16 @@
* that may be used before your watch face has the permission, use a safe complication data
* source instead.
*
- * A complication data source not satisfying the above conditions may still be set as a default using
- * this method, but the watch face will receive placeholder data of type
+ * A complication data source not satisfying the above conditions may still be set as a default
+ * using this method, but the watch face will receive placeholder data of type
* [ComplicationData.TYPE_NO_PERMISSION] until the permission has been granted.
*
* @param complicationSlotId The [ComplicationSlot] id.
* @param dataSources data sources The list of non-system complication data sources to try in
* order before falling back to
* fallbackSystemProvider. This list may be null.
- * @param fallbackSystemProvider The system complication data source to use if none of the complication data sources could be
- * used.
+ * @param fallbackSystemProvider The system complication data source to use if none of the
+ * complication data sources could be used.
* @param type The type of complication data that should be provided. Must be one of the types
* defined in [ComplicationData].
*/
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index 3a5fdff..a34102f 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -43,7 +43,6 @@
import android.view.SurfaceHolder
import android.view.WindowInsets
import android.view.accessibility.AccessibilityManager
-import androidx.annotation.IntDef
import androidx.annotation.Px
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
@@ -58,7 +57,6 @@
import androidx.wear.utility.AsyncTraceEvent
import androidx.wear.utility.TraceEvent
import androidx.wear.watchface.control.HeadlessWatchFaceImpl
-import androidx.wear.watchface.control.IInteractiveWatchFace
import androidx.wear.watchface.control.InteractiveInstanceManager
import androidx.wear.watchface.control.InteractiveWatchFaceImpl
import androidx.wear.watchface.control.data.CrashInfoParcel
@@ -101,47 +99,6 @@
*/
internal const val SURFACE_DRAW_TIMEOUT_MS = 100L
-/** @hide */
-@IntDef(
- value = [
- TapType.DOWN,
- TapType.UP,
- TapType.CANCEL
- ]
-)
-public annotation class TapType {
- public companion object {
- /**
- * Used to indicate a "down" touch event on the watch face.
- *
- * The watch face will receive an [UP] or a [CANCEL] event to follow this event, to
- * indicate whether this down event corresponds to a tap gesture to be handled by the watch
- * face, or a different type of gesture that is handled by the system, respectively.
- */
- public const val DOWN: Int = IInteractiveWatchFace.TAP_TYPE_DOWN
-
- /**
- * Used in to indicate that a previous [TapType.DOWN] touch event has been canceled. This
- * generally happens when the watch face is touched but then a move or long press occurs.
- *
- * The watch face should not trigger any action, as the system is already processing the
- * gesture.
- */
- public const val CANCEL: Int = IInteractiveWatchFace.TAP_TYPE_CANCEL
-
- /**
- * Used to indicate that an "up" event on the watch face has occurred that has not been
- * consumed by the system. A [TapType.DOWN] will always occur first. This event will not
- * be sent if a [TapType.CANCEL] is sent.
- *
- * Therefore, a [TapType.DOWN] event and the successive [TapType.UP] event are guaranteed
- * to be close enough to be considered a tap according to the value returned by
- * [android.view.ViewConfiguration.getScaledTouchSlop].
- */
- public const val UP: Int = IInteractiveWatchFace.TAP_TYPE_UP
- }
-}
-
/**
* WatchFaceService and [WatchFace] are a pair of classes intended to handle much of
* the boilerplate needed to implement a watch face without being too opinionated. The suggested
@@ -736,7 +693,7 @@
internal var pendingUserStyle: UserStyleWireFormat? = null
/**
- * Whether or not we allow watchfaces to animate. In some tests or for headless
+ * Whether or not we allow watch faces to animate. In some tests or for headless
* rendering (for remote config) we don't want this.
*/
internal var allowWatchfaceToAnimate = allowWatchFaceToAnimate()
@@ -911,7 +868,7 @@
ambientUpdateWakelock.acquire()
// It's unlikely an ambient tick would be sent to a watch face that hasn't loaded
// yet. The watch face will render at least once upon loading so we don't need to do
- // anyhting special here.
+ // anything special here.
getWatchFaceImplOrNull()?.renderer?.invalidate()
ambientUpdateWakelock.acquire(SURFACE_DRAW_TIMEOUT_MS)
}
@@ -997,14 +954,6 @@
}
}
- internal fun clearComplicationData() {
- val watchFaceImpl = getWatchFaceImplOrNull()
- require(watchFaceImpl != null) {
- "WatchFace must have been created first"
- }
- watchFaceImpl.clearComplicationData()
- }
-
@UiThread
internal fun setComplicationDataList(
complicationDataWireFormats: MutableList<IdAndComplicationDataWireFormat>
@@ -1170,17 +1119,29 @@
}
Constants.COMMAND_TAP ->
uiThreadCoroutineScope.runBlockingWithTracing("onCommand COMMAND_TAP") {
- deferredWatchFaceImpl.await().onTapCommand(TapType.UP, x, y)
+ val watchFaceImpl = deferredWatchFaceImpl.await()
+ watchFaceImpl.onTapCommand(
+ TapType.UP,
+ TapEvent(x, y, watchFaceImpl.calendar.timeInMillis)
+ )
}
Constants.COMMAND_TOUCH ->
uiThreadCoroutineScope.runBlockingWithTracing("onCommand COMMAND_TOUCH") {
- deferredWatchFaceImpl.await().onTapCommand(TapType.DOWN, x, y)
+ val watchFaceImpl = deferredWatchFaceImpl.await()
+ watchFaceImpl.onTapCommand(
+ TapType.DOWN,
+ TapEvent(x, y, watchFaceImpl.calendar.timeInMillis)
+ )
}
Constants.COMMAND_TOUCH_CANCEL ->
uiThreadCoroutineScope.runBlockingWithTracing(
"onCommand COMMAND_TOUCH_CANCEL"
) {
- deferredWatchFaceImpl.await().onTapCommand(TapType.CANCEL, x, y)
+ val watchFaceImpl = deferredWatchFaceImpl.await()
+ watchFaceImpl.onTapCommand(
+ TapType.CANCEL,
+ TapEvent(x, y, watchFaceImpl.calendar.timeInMillis)
+ )
}
else -> {
}
@@ -1440,7 +1401,7 @@
initStyleAndComplicationsDone.complete(Unit)
// validateSchemaWireSize is fairly expensive so only perform it for
- // interactive watchfaces.
+ // interactive watch faces.
if (!watchState.isHeadless) {
validateSchemaWireSize(currentUserStyleRepository.schema)
}
@@ -1508,7 +1469,7 @@
initStyleAndComplicationsDone.await()
// Its possible a second getOrCreateInteractiveWatchFaceClient call came in before
- // the watch face for the first one had finished initalizing, in that case we want
+ // the watch face for the first one had finished initializing, in that case we want
// to apply the updated style. NB pendingUserStyle is accessed on the UiThread so
// there shouldn't be any problems with race conditions.
pendingUserStyle?.let {
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/control/InteractiveWatchFaceImpl.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/control/InteractiveWatchFaceImpl.kt
index 3ab58d0..03c763b 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/control/InteractiveWatchFaceImpl.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/control/InteractiveWatchFaceImpl.kt
@@ -19,6 +19,7 @@
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.wear.utility.TraceEvent
+import androidx.wear.watchface.TapEvent
import androidx.wear.watchface.WatchFaceImpl
import androidx.wear.watchface.WatchFaceService
import androidx.wear.watchface.control.data.WatchFaceRenderParams
@@ -62,7 +63,12 @@
override fun sendTouchEvent(xPos: Int, yPos: Int, tapType: Int) =
awaitDeferredWatchFaceImplThenRunOnUiThreadBlocking(
"InteractiveWatchFaceImpl.sendTouchEvent"
- ) { watchFaceImpl -> watchFaceImpl.onTapCommand(tapType, xPos, yPos) }
+ ) { watchFaceImpl ->
+ watchFaceImpl.onTapCommand(
+ tapType,
+ TapEvent(xPos, yPos, watchFaceImpl.calendar.timeInMillis)
+ )
+ }
override fun getContentDescriptionLabels() =
awaitDeferredWatchFaceImplThenRunOnUiThreadBlocking(
@@ -142,8 +148,6 @@
) { watchFaceImpl -> watchFaceImpl.currentUserStyleRepository.schema.toWireFormat() }
override fun bringAttentionToComplication(id: Int) {
- awaitDeferredWatchFaceImplThenRunOnUiThreadBlocking(
- "InteractiveWatchFaceImpl.getUserStyleSchema"
- ) { watchFaceImpl -> watchFaceImpl.complicationSlotsManager.displayPressedAnimation(id) }
+ // Unsupported.
}
}
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index 8701f02..4fc4e68 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -709,52 +709,59 @@
private fun tapAt(x: Int, y: Int) {
// The eventTime is ignored.
- watchFaceImpl.onTapCommand(TapType.DOWN, x, y)
- watchFaceImpl.onTapCommand(TapType.UP, x, y)
+ watchFaceImpl.onTapCommand(TapType.DOWN, TapEvent(x, y, looperTimeMillis))
+ watchFaceImpl.onTapCommand(TapType.UP, TapEvent(x, y, looperTimeMillis))
}
private fun tapCancelAt(x: Int, y: Int) {
- watchFaceImpl.onTapCommand(TapType.DOWN, x, y)
- watchFaceImpl.onTapCommand(TapType.CANCEL, x, y)
+ watchFaceImpl.onTapCommand(TapType.DOWN, TapEvent(x, y, looperTimeMillis))
+ watchFaceImpl.onTapCommand(TapType.CANCEL, TapEvent(x, y, looperTimeMillis))
}
@Test
- public fun singleTaps_correctlyDetected_and_highlightComplications() {
+ public fun singleTaps_correctlyDetected() {
initEngine(
WatchFaceType.ANALOG,
listOf(leftComplication, rightComplication),
UserStyleSchema(emptyList())
)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(LEFT_COMPLICATION_ID)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(RIGHT_COMPLICATION_ID)
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[LEFT_COMPLICATION_ID])
+ .isNull()
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[RIGHT_COMPLICATION_ID])
+ .isNull()
// Tap left complication.
tapAt(30, 50)
- assertThat(complicationSlotsManager.pressedSlotIds).contains(LEFT_COMPLICATION_ID)
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[LEFT_COMPLICATION_ID])
+ .isEqualTo(TapEvent(30, 50, 0))
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[RIGHT_COMPLICATION_ID])
+ .isNull()
assertThat(testWatchFaceService.tappedComplicationSlotIds)
.isEqualTo(listOf(LEFT_COMPLICATION_ID))
- runPostedTasksFor(WatchFaceImpl.CANCEL_COMPLICATION_HIGHLIGHTED_DELAY_MS)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(LEFT_COMPLICATION_ID)
+ runPostedTasksFor(100)
// Tap right complication.
testWatchFaceService.reset()
tapAt(70, 50)
- assertThat(complicationSlotsManager.pressedSlotIds).contains(RIGHT_COMPLICATION_ID)
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[LEFT_COMPLICATION_ID])
+ .isEqualTo(TapEvent(30, 50, 0))
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[RIGHT_COMPLICATION_ID])
+ .isEqualTo(TapEvent(70, 50, 100))
assertThat(testWatchFaceService.tappedComplicationSlotIds)
.isEqualTo(listOf(RIGHT_COMPLICATION_ID))
- runPostedTasksFor(WatchFaceImpl.CANCEL_COMPLICATION_HIGHLIGHTED_DELAY_MS)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(LEFT_COMPLICATION_ID)
+ runPostedTasksFor(100)
// Tap on blank space.
testWatchFaceService.reset()
tapAt(1, 1)
- assertThat(testWatchFaceService.tappedComplicationSlotIds).isEmpty()
-
- runPostedTasksFor(WatchFaceImpl.CANCEL_COMPLICATION_HIGHLIGHTED_DELAY_MS)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(LEFT_COMPLICATION_ID)
+ // No change in lastComplicationTapDownEvents
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[LEFT_COMPLICATION_ID])
+ .isEqualTo(TapEvent(30, 50, 0))
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[RIGHT_COMPLICATION_ID])
+ .isEqualTo(TapEvent(70, 50, 100))
assertThat(testWatchFaceService.tappedComplicationSlotIds).isEmpty()
}
@@ -766,23 +773,20 @@
UserStyleSchema(emptyList())
)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(LEFT_COMPLICATION_ID)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(RIGHT_COMPLICATION_ID)
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[LEFT_COMPLICATION_ID])
+ .isNull()
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[RIGHT_COMPLICATION_ID])
+ .isNull()
// Rapidly tap left then right complication.
tapAt(30, 50)
tapAt(70, 50)
- // Both complicationSlots get temporarily highlighted.
- assertThat(complicationSlotsManager.pressedSlotIds).contains(LEFT_COMPLICATION_ID)
- assertThat(complicationSlotsManager.pressedSlotIds).contains(RIGHT_COMPLICATION_ID)
-
- // And the highlight goes away after a delay.
- runPostedTasksFor(WatchFaceImpl.CANCEL_COMPLICATION_HIGHLIGHTED_DELAY_MS)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(LEFT_COMPLICATION_ID)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(RIGHT_COMPLICATION_ID)
-
// Taps are registered on both complicationSlots.
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[LEFT_COMPLICATION_ID])
+ .isEqualTo(TapEvent(30, 50, 0))
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[RIGHT_COMPLICATION_ID])
+ .isEqualTo(TapEvent(70, 50, 0))
assertThat(testWatchFaceService.tappedComplicationSlotIds)
.isEqualTo(listOf(LEFT_COMPLICATION_ID, RIGHT_COMPLICATION_ID))
}
@@ -810,7 +814,8 @@
tapListener = tapListener
)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(EDGE_COMPLICATION_ID)
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[EDGE_COMPLICATION_ID])
+ .isNull()
`when`(
edgeComplicationHitTester.hitTest(
@@ -823,12 +828,10 @@
// Tap the edge complication.
tapAt(0, 50)
- assertThat(complicationSlotsManager.pressedSlotIds).contains(EDGE_COMPLICATION_ID)
+ assertThat(complicationSlotsManager.lastComplicationTapDownEvents[EDGE_COMPLICATION_ID])
+ .isEqualTo(TapEvent(0, 50, 0))
assertThat(testWatchFaceService.tappedComplicationSlotIds)
.isEqualTo(listOf(EDGE_COMPLICATION_ID))
-
- runPostedTasksFor(WatchFaceImpl.CANCEL_COMPLICATION_HIGHLIGHTED_DELAY_MS)
- assertThat(complicationSlotsManager.pressedSlotIds).doesNotContain(EDGE_COMPLICATION_ID)
}
@Test
@@ -843,8 +846,8 @@
// Tap on nothing.
tapAt(1, 1)
- verify(tapListener).onTap(TapType.DOWN, 1, 1)
- verify(tapListener).onTap(TapType.UP, 1, 1)
+ verify(tapListener).onTapEvent(TapType.DOWN, TapEvent(1, 1, looperTimeMillis))
+ verify(tapListener).onTapEvent(TapType.UP, TapEvent(1, 1, looperTimeMillis))
}
@Test
@@ -885,8 +888,8 @@
false
)
- verify(tapListener).onTap(TapType.DOWN, 10, 20)
- verify(tapListener).onTap(TapType.UP, 10, 20)
+ verify(tapListener).onTapEvent(TapType.DOWN, TapEvent(10, 20, looperTimeMillis))
+ verify(tapListener).onTapEvent(TapType.UP, TapEvent(10, 20, looperTimeMillis))
}
@Test
@@ -901,8 +904,8 @@
// Tap right complication.
tapAt(70, 50)
- verify(tapListener, times(0)).onTap(TapType.DOWN, 70, 50)
- verify(tapListener, times(0)).onTap(TapType.UP, 70, 50)
+ verify(tapListener, times(0)).onTapEvent(TapType.DOWN, TapEvent(70, 50, looperTimeMillis))
+ verify(tapListener, times(0)).onTapEvent(TapType.UP, TapEvent(70, 50, looperTimeMillis))
}
@Test
diff --git a/wear/wear/api/1.2.0-beta01.txt b/wear/wear/api/1.2.0-beta01.txt
new file mode 100644
index 0000000..65a6853
--- /dev/null
+++ b/wear/wear/api/1.2.0-beta01.txt
@@ -0,0 +1,463 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor public AmbientModeSupport();
+ method public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor public AmbientModeSupport.AmbientCallback();
+ method public void onAmbientOffloadInvalidated();
+ method public void onEnterAmbient(android.os.Bundle!);
+ method public void onExitAmbient();
+ method public void onUpdateAmbient();
+ }
+
+ public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ public final class AmbientModeSupport.AmbientController {
+ method public boolean isAmbient();
+ method public void setAmbientOffloadEnabled(boolean);
+ method public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(int, int);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method public int getVerticalAlignment();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(int);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ method public void setTypeface(android.graphics.Typeface?);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/wear/wear/api/1.2.0-beta02.txt b/wear/wear/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..65a6853
--- /dev/null
+++ b/wear/wear/api/1.2.0-beta02.txt
@@ -0,0 +1,463 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor public AmbientModeSupport();
+ method public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor public AmbientModeSupport.AmbientCallback();
+ method public void onAmbientOffloadInvalidated();
+ method public void onEnterAmbient(android.os.Bundle!);
+ method public void onExitAmbient();
+ method public void onUpdateAmbient();
+ }
+
+ public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ public final class AmbientModeSupport.AmbientController {
+ method public boolean isAmbient();
+ method public void setAmbientOffloadEnabled(boolean);
+ method public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(int, int);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method public int getVerticalAlignment();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(int);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ method public void setTypeface(android.graphics.Typeface?);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/wear/wear/api/public_plus_experimental_1.2.0-beta01.txt b/wear/wear/api/public_plus_experimental_1.2.0-beta01.txt
new file mode 100644
index 0000000..65a6853
--- /dev/null
+++ b/wear/wear/api/public_plus_experimental_1.2.0-beta01.txt
@@ -0,0 +1,463 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor public AmbientModeSupport();
+ method public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor public AmbientModeSupport.AmbientCallback();
+ method public void onAmbientOffloadInvalidated();
+ method public void onEnterAmbient(android.os.Bundle!);
+ method public void onExitAmbient();
+ method public void onUpdateAmbient();
+ }
+
+ public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ public final class AmbientModeSupport.AmbientController {
+ method public boolean isAmbient();
+ method public void setAmbientOffloadEnabled(boolean);
+ method public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(int, int);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method public int getVerticalAlignment();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(int);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ method public void setTypeface(android.graphics.Typeface?);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/wear/wear/api/public_plus_experimental_1.2.0-beta02.txt b/wear/wear/api/public_plus_experimental_1.2.0-beta02.txt
new file mode 100644
index 0000000..65a6853
--- /dev/null
+++ b/wear/wear/api/public_plus_experimental_1.2.0-beta02.txt
@@ -0,0 +1,463 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor public AmbientModeSupport();
+ method public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor public AmbientModeSupport.AmbientCallback();
+ method public void onAmbientOffloadInvalidated();
+ method public void onEnterAmbient(android.os.Bundle!);
+ method public void onExitAmbient();
+ method public void onUpdateAmbient();
+ }
+
+ public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ public final class AmbientModeSupport.AmbientController {
+ method public boolean isAmbient();
+ method public void setAmbientOffloadEnabled(boolean);
+ method public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(int, int);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method public int getVerticalAlignment();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(int);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ method public void setTypeface(android.graphics.Typeface?);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/wear/wear/api/res-1.2.0-beta01.txt b/wear/wear/api/res-1.2.0-beta01.txt
new file mode 100644
index 0000000..44b0b55
--- /dev/null
+++ b/wear/wear/api/res-1.2.0-beta01.txt
@@ -0,0 +1 @@
+style Widget_Wear_RoundSwitch
diff --git a/wear/wear/api/res-1.2.0-beta02.txt b/wear/wear/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..44b0b55
--- /dev/null
+++ b/wear/wear/api/res-1.2.0-beta02.txt
@@ -0,0 +1 @@
+style Widget_Wear_RoundSwitch
diff --git a/wear/wear/api/restricted_1.2.0-beta01.txt b/wear/wear/api/restricted_1.2.0-beta01.txt
new file mode 100644
index 0000000..9fa9f23
--- /dev/null
+++ b/wear/wear/api/restricted_1.2.0-beta01.txt
@@ -0,0 +1,470 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor public AmbientModeSupport();
+ method public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor public AmbientModeSupport.AmbientCallback();
+ method public void onAmbientOffloadInvalidated();
+ method public void onEnterAmbient(android.os.Bundle!);
+ method public void onExitAmbient();
+ method public void onUpdateAmbient();
+ }
+
+ public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ public final class AmbientModeSupport.AmbientController {
+ method public boolean isAmbient();
+ method public void setAmbientOffloadEnabled(boolean);
+ method public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method @androidx.wear.widget.ArcLayout.AnchorType public int getAnchorType();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(@androidx.wear.widget.ArcLayout.AnchorType int);
+ method public void setClockwise(boolean);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ @IntDef({androidx.wear.widget.ArcLayout.ANCHOR_START, androidx.wear.widget.ArcLayout.ANCHOR_CENTER, androidx.wear.widget.ArcLayout.ANCHOR_END}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ArcLayout.AnchorType {
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(int, int);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method @androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment public int getVerticalAlignment();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(@androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment int);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ @IntDef({androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_OUTER, androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_CENTER, androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_INNER}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ArcLayout.LayoutParams.VerticalAlignment {
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method @MainThread @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public void hide();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method @androidx.wear.widget.ArcLayout.AnchorType public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(@androidx.wear.widget.ArcLayout.AnchorType int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ method public void setTypeface(android.graphics.Typeface?);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/wear/wear/api/restricted_1.2.0-beta02.txt b/wear/wear/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..9fa9f23
--- /dev/null
+++ b/wear/wear/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,470 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor public AmbientModeSupport();
+ method public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor public AmbientModeSupport.AmbientCallback();
+ method public void onAmbientOffloadInvalidated();
+ method public void onEnterAmbient(android.os.Bundle!);
+ method public void onExitAmbient();
+ method public void onUpdateAmbient();
+ }
+
+ public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ public final class AmbientModeSupport.AmbientController {
+ method public boolean isAmbient();
+ method public void setAmbientOffloadEnabled(boolean);
+ method public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method @androidx.wear.widget.ArcLayout.AnchorType public int getAnchorType();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(@androidx.wear.widget.ArcLayout.AnchorType int);
+ method public void setClockwise(boolean);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ @IntDef({androidx.wear.widget.ArcLayout.ANCHOR_START, androidx.wear.widget.ArcLayout.ANCHOR_CENTER, androidx.wear.widget.ArcLayout.ANCHOR_END}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ArcLayout.AnchorType {
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(int, int);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method @androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment public int getVerticalAlignment();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(@androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment int);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ @IntDef({androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_OUTER, androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_CENTER, androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_INNER}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ArcLayout.LayoutParams.VerticalAlignment {
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method @MainThread @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public void hide();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method @androidx.wear.widget.ArcLayout.AnchorType public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(@androidx.wear.widget.ArcLayout.AnchorType int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ method public void setTypeface(android.graphics.Typeface?);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/wear/wear/src/androidTest/AndroidManifest.xml b/wear/wear/src/androidTest/AndroidManifest.xml
index 00fc129..f6f09b4 100644
--- a/wear/wear/src/androidTest/AndroidManifest.xml
+++ b/wear/wear/src/androidTest/AndroidManifest.xml
@@ -15,99 +15,120 @@
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.wear.test">
-
- <uses-permission android:name="android.permission.WAKE_LOCK"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ package="androidx.wear.test">
<application
- android:supportsRtl="true"
- android:requestLegacyExternalStorage="true">
- <activity android:name="androidx.wear.widget.LayoutTestActivity">
+ android:requestLegacyExternalStorage="true"
+ android:supportsRtl="true">
+ <activity
+ android:name="androidx.wear.widget.LayoutTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.widget.DismissibleFrameLayoutTestActivity"
- android:theme="@style/AppThemeNoSwipe">
+ <activity
+ android:name="androidx.wear.widget.DismissibleFrameLayoutTestActivity"
+ android:exported="false"
+ android:theme="@style/AppThemeNoSwipe">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.widget.WearableRecyclerViewTestActivity">
+ <activity
+ android:name="androidx.wear.widget.WearableRecyclerViewTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.widget.drawer.DrawerTestActivity">
+ <activity
+ android:name="androidx.wear.widget.drawer.DrawerTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.widget.drawer.DrawerRecyclerViewTestActivity">
+ <activity
+ android:name="androidx.wear.widget.drawer.DrawerRecyclerViewTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.ambient.AmbientModeTestActivity">
+ <activity
+ android:name="androidx.wear.ambient.AmbientModeTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.ambient.AmbientModeResumeTestActivity">
+ <activity
+ android:name="androidx.wear.ambient.AmbientModeResumeTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.ambient.AmbientModeSupportTestActivity">
+ <activity
+ android:name="androidx.wear.ambient.AmbientModeSupportTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.ambient.AmbientModeSupportResumeTestActivity">
+ <activity
+ android:name="androidx.wear.ambient.AmbientModeSupportResumeTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
-
- <activity android:name="androidx.wear.widget.ConfirmationOverlayTestActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.activity.ConfirmationActivityTestActivity">
+ <activity
+ android:name="androidx.wear.widget.ConfirmationOverlayTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="androidx.wear.activity.ConfirmationActivity">
+ <activity
+ android:name="androidx.wear.activity.ConfirmationActivityTestActivity"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
</activity>
- <activity android:name="androidx.wear.widget.TouchTestActivity">
+ <activity
+ android:name="androidx.wear.activity.ConfirmationActivity"
+ android:exported="false"></activity>
+
+ <activity
+ android:name="androidx.wear.widget.TouchTestActivity"
+ android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
@@ -124,4 +145,8 @@
android:name="com.google.android.wearable.watchface.preview_circular"
android:resource="@drawable/preview_face_circular" />
</application>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>
diff --git a/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java b/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java
index ebf9c6c..efaed67 100644
--- a/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java
+++ b/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import android.graphics.Bitmap;
@@ -31,6 +32,9 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -184,7 +188,7 @@
// Loading a page with dark-theme support should result in a green background (as
// specified in media-query)
mWebViewOnUiThread.loadDataAndWaitForCompletion(mDarkThemeSupport, "text/html", "base64");
- assertTrue("Bitmap colour should be green", isGreen(getWebPageColor()));
+ assertThat("Bitmap colour should be green", getWebPageColor(), isGreen());
assertTrue(prefersDarkTheme());
}
@@ -216,8 +220,7 @@
// Loading a page with dark-theme support should result in a green background (as
// specified in media-query)
mWebViewOnUiThread.loadDataAndWaitForCompletion(mDarkThemeSupport, "text/html", "base64");
- assertTrue("Bitmap colour should be green",
- isGreen(getWebPageColor()));
+ assertThat("Bitmap colour should be green", getWebPageColor(), isGreen());
assertTrue(prefersDarkTheme());
}
@@ -273,9 +276,30 @@
return "true".equals(result);
}
- private boolean isGreen(int color) {
- return Color.green(color) > 200
- && Color.red(color) < 50
- && Color.blue(color) < 50;
+ /**
+ * Returns a matcher to check if a color int is mostly green.
+ */
+ private static Matcher<Integer> isGreen() {
+ return new TypeSafeMatcher<Integer>() {
+ private int mPageColor;
+ @Override
+ public boolean matchesSafely(Integer pageColor) {
+ mPageColor = pageColor;
+ return Color.green(pageColor) > 200
+ && Color.red(pageColor) < 90
+ && Color.blue(pageColor) < 90;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("expected color to be green but was "
+ + toHex(mPageColor) + " (in ARGB format)");
+ }
+ };
+ }
+
+ private static String toHex(int i) {
+ long l = Integer.toUnsignedLong(i);
+ return "0x" + Long.toString(l, 16);
}
}
diff --git a/window/window-extensions/api/api_lint.ignore b/window/window-extensions/api/api_lint.ignore
index d5594c7..c929e8e 100644
--- a/window/window-extensions/api/api_lint.ignore
+++ b/window/window-extensions/api/api_lint.ignore
@@ -1,3 +1,3 @@
// Baseline format: 1.0
-ExecutorRegistration: androidx.window.extensions.ExtensionInterface#setExtensionCallback(androidx.window.extensions.ExtensionInterface.ExtensionCallback):
+ExecutorRegistration: androidx.window.extensions.layout.ExtensionInterface#setExtensionCallback(androidx.window.extensions.layout.ExtensionInterface.ExtensionCallback):
Registration methods should have overload that accepts delivery Executor: `setExtensionCallback`
diff --git a/window/window-extensions/api/current.txt b/window/window-extensions/api/current.txt
index 4e1cb6c..61c0df3 100644
--- a/window/window-extensions/api/current.txt
+++ b/window/window-extensions/api/current.txt
@@ -1,12 +1,31 @@
// Signature format: 4.0
package androidx.window.extensions {
- public interface ExtensionDisplayFeature {
+ public final class ExtensionProvider {
+ method public static String? getApiVersion();
+ method public static androidx.window.extensions.layout.ExtensionInterface? getExtensionImpl(android.content.Context);
+ }
+
+}
+
+package androidx.window.extensions.layout {
+
+ public interface DisplayFeature {
method public android.graphics.Rect getBounds();
}
- public class ExtensionFoldingFeature implements androidx.window.extensions.ExtensionDisplayFeature {
- ctor public ExtensionFoldingFeature(android.graphics.Rect, int, int);
+ public interface ExtensionInterface {
+ method public void onWindowLayoutChangeListenerAdded(android.app.Activity);
+ method public void onWindowLayoutChangeListenerRemoved(android.app.Activity);
+ method public void setExtensionCallback(androidx.window.extensions.layout.ExtensionInterface.ExtensionCallback);
+ }
+
+ public static interface ExtensionInterface.ExtensionCallback {
+ method public void onWindowLayoutChanged(android.app.Activity, androidx.window.extensions.layout.WindowLayoutInfo);
+ }
+
+ public class FoldingFeature implements androidx.window.extensions.layout.DisplayFeature {
+ ctor public FoldingFeature(android.graphics.Rect, int, int);
method public android.graphics.Rect getBounds();
method public int getState();
method public int getType();
@@ -16,24 +35,9 @@
field public static final int TYPE_HINGE = 2; // 0x2
}
- public interface ExtensionInterface {
- method public void onWindowLayoutChangeListenerAdded(android.app.Activity);
- method public void onWindowLayoutChangeListenerRemoved(android.app.Activity);
- method public void setExtensionCallback(androidx.window.extensions.ExtensionInterface.ExtensionCallback);
- }
-
- public static interface ExtensionInterface.ExtensionCallback {
- method public void onWindowLayoutChanged(android.app.Activity, androidx.window.extensions.ExtensionWindowLayoutInfo);
- }
-
- public final class ExtensionProvider {
- method public static String? getApiVersion();
- method public static androidx.window.extensions.ExtensionInterface? getExtensionImpl(android.content.Context);
- }
-
- public class ExtensionWindowLayoutInfo {
- ctor public ExtensionWindowLayoutInfo(java.util.List<androidx.window.extensions.ExtensionDisplayFeature!>);
- method public java.util.List<androidx.window.extensions.ExtensionDisplayFeature!> getDisplayFeatures();
+ public class WindowLayoutInfo {
+ ctor public WindowLayoutInfo(java.util.List<androidx.window.extensions.layout.DisplayFeature!>);
+ method public java.util.List<androidx.window.extensions.layout.DisplayFeature!> getDisplayFeatures();
}
}
diff --git a/window/window-extensions/api/public_plus_experimental_current.txt b/window/window-extensions/api/public_plus_experimental_current.txt
index 4e1cb6c..61c0df3 100644
--- a/window/window-extensions/api/public_plus_experimental_current.txt
+++ b/window/window-extensions/api/public_plus_experimental_current.txt
@@ -1,12 +1,31 @@
// Signature format: 4.0
package androidx.window.extensions {
- public interface ExtensionDisplayFeature {
+ public final class ExtensionProvider {
+ method public static String? getApiVersion();
+ method public static androidx.window.extensions.layout.ExtensionInterface? getExtensionImpl(android.content.Context);
+ }
+
+}
+
+package androidx.window.extensions.layout {
+
+ public interface DisplayFeature {
method public android.graphics.Rect getBounds();
}
- public class ExtensionFoldingFeature implements androidx.window.extensions.ExtensionDisplayFeature {
- ctor public ExtensionFoldingFeature(android.graphics.Rect, int, int);
+ public interface ExtensionInterface {
+ method public void onWindowLayoutChangeListenerAdded(android.app.Activity);
+ method public void onWindowLayoutChangeListenerRemoved(android.app.Activity);
+ method public void setExtensionCallback(androidx.window.extensions.layout.ExtensionInterface.ExtensionCallback);
+ }
+
+ public static interface ExtensionInterface.ExtensionCallback {
+ method public void onWindowLayoutChanged(android.app.Activity, androidx.window.extensions.layout.WindowLayoutInfo);
+ }
+
+ public class FoldingFeature implements androidx.window.extensions.layout.DisplayFeature {
+ ctor public FoldingFeature(android.graphics.Rect, int, int);
method public android.graphics.Rect getBounds();
method public int getState();
method public int getType();
@@ -16,24 +35,9 @@
field public static final int TYPE_HINGE = 2; // 0x2
}
- public interface ExtensionInterface {
- method public void onWindowLayoutChangeListenerAdded(android.app.Activity);
- method public void onWindowLayoutChangeListenerRemoved(android.app.Activity);
- method public void setExtensionCallback(androidx.window.extensions.ExtensionInterface.ExtensionCallback);
- }
-
- public static interface ExtensionInterface.ExtensionCallback {
- method public void onWindowLayoutChanged(android.app.Activity, androidx.window.extensions.ExtensionWindowLayoutInfo);
- }
-
- public final class ExtensionProvider {
- method public static String? getApiVersion();
- method public static androidx.window.extensions.ExtensionInterface? getExtensionImpl(android.content.Context);
- }
-
- public class ExtensionWindowLayoutInfo {
- ctor public ExtensionWindowLayoutInfo(java.util.List<androidx.window.extensions.ExtensionDisplayFeature!>);
- method public java.util.List<androidx.window.extensions.ExtensionDisplayFeature!> getDisplayFeatures();
+ public class WindowLayoutInfo {
+ ctor public WindowLayoutInfo(java.util.List<androidx.window.extensions.layout.DisplayFeature!>);
+ method public java.util.List<androidx.window.extensions.layout.DisplayFeature!> getDisplayFeatures();
}
}
diff --git a/window/window-extensions/api/restricted_current.txt b/window/window-extensions/api/restricted_current.txt
index 4e1cb6c..61c0df3 100644
--- a/window/window-extensions/api/restricted_current.txt
+++ b/window/window-extensions/api/restricted_current.txt
@@ -1,12 +1,31 @@
// Signature format: 4.0
package androidx.window.extensions {
- public interface ExtensionDisplayFeature {
+ public final class ExtensionProvider {
+ method public static String? getApiVersion();
+ method public static androidx.window.extensions.layout.ExtensionInterface? getExtensionImpl(android.content.Context);
+ }
+
+}
+
+package androidx.window.extensions.layout {
+
+ public interface DisplayFeature {
method public android.graphics.Rect getBounds();
}
- public class ExtensionFoldingFeature implements androidx.window.extensions.ExtensionDisplayFeature {
- ctor public ExtensionFoldingFeature(android.graphics.Rect, int, int);
+ public interface ExtensionInterface {
+ method public void onWindowLayoutChangeListenerAdded(android.app.Activity);
+ method public void onWindowLayoutChangeListenerRemoved(android.app.Activity);
+ method public void setExtensionCallback(androidx.window.extensions.layout.ExtensionInterface.ExtensionCallback);
+ }
+
+ public static interface ExtensionInterface.ExtensionCallback {
+ method public void onWindowLayoutChanged(android.app.Activity, androidx.window.extensions.layout.WindowLayoutInfo);
+ }
+
+ public class FoldingFeature implements androidx.window.extensions.layout.DisplayFeature {
+ ctor public FoldingFeature(android.graphics.Rect, int, int);
method public android.graphics.Rect getBounds();
method public int getState();
method public int getType();
@@ -16,24 +35,9 @@
field public static final int TYPE_HINGE = 2; // 0x2
}
- public interface ExtensionInterface {
- method public void onWindowLayoutChangeListenerAdded(android.app.Activity);
- method public void onWindowLayoutChangeListenerRemoved(android.app.Activity);
- method public void setExtensionCallback(androidx.window.extensions.ExtensionInterface.ExtensionCallback);
- }
-
- public static interface ExtensionInterface.ExtensionCallback {
- method public void onWindowLayoutChanged(android.app.Activity, androidx.window.extensions.ExtensionWindowLayoutInfo);
- }
-
- public final class ExtensionProvider {
- method public static String? getApiVersion();
- method public static androidx.window.extensions.ExtensionInterface? getExtensionImpl(android.content.Context);
- }
-
- public class ExtensionWindowLayoutInfo {
- ctor public ExtensionWindowLayoutInfo(java.util.List<androidx.window.extensions.ExtensionDisplayFeature!>);
- method public java.util.List<androidx.window.extensions.ExtensionDisplayFeature!> getDisplayFeatures();
+ public class WindowLayoutInfo {
+ ctor public WindowLayoutInfo(java.util.List<androidx.window.extensions.layout.DisplayFeature!>);
+ method public java.util.List<androidx.window.extensions.layout.DisplayFeature!> getDisplayFeatures();
}
}
diff --git a/window/window-extensions/src/androidTest/java/androidx/window/extensions/ExtensionDisplayFeatureTest.java b/window/window-extensions/src/androidTest/java/androidx/window/extensions/ExtensionDisplayFeatureTest.java
deleted file mode 100644
index 151fe2d..0000000
--- a/window/window-extensions/src/androidTest/java/androidx/window/extensions/ExtensionDisplayFeatureTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.graphics.Rect;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests for {@link ExtensionFoldingFeature} class. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class ExtensionDisplayFeatureTest {
-
- @Test
- public void testEquals_sameAttributes() {
- Rect bounds = new Rect(1, 0, 1, 10);
- int type = ExtensionFoldingFeature.TYPE_FOLD;
- int state = ExtensionFoldingFeature.STATE_FLAT;
-
- ExtensionFoldingFeature original = new ExtensionFoldingFeature(bounds, type, state);
- ExtensionFoldingFeature copy = new ExtensionFoldingFeature(bounds, type, state);
-
- assertEquals(original, copy);
- }
-
- @Test
- public void testEquals_differentRect() {
- Rect originalRect = new Rect(1, 0, 1, 10);
- Rect otherRect = new Rect(2, 0, 2, 10);
- int type = ExtensionFoldingFeature.TYPE_FOLD;
- int state = ExtensionFoldingFeature.STATE_FLAT;
-
- ExtensionFoldingFeature original = new ExtensionFoldingFeature(originalRect, type,
- state);
- ExtensionFoldingFeature other = new ExtensionFoldingFeature(otherRect, type, state);
-
- assertNotEquals(original, other);
- }
-
- @Test
- public void testEquals_differentType() {
- Rect rect = new Rect(1, 0, 1, 10);
- int originalType = ExtensionFoldingFeature.TYPE_FOLD;
- int otherType = ExtensionFoldingFeature.TYPE_HINGE;
- int state = ExtensionFoldingFeature.STATE_FLAT;
-
- ExtensionFoldingFeature original = new ExtensionFoldingFeature(rect, originalType,
- state);
- ExtensionFoldingFeature other = new ExtensionFoldingFeature(rect, otherType, state);
-
- assertNotEquals(original, other);
- }
-
- @Test
- public void testEquals_differentState() {
- Rect rect = new Rect(1, 0, 1, 10);
- int type = ExtensionFoldingFeature.TYPE_FOLD;
- int originalState = ExtensionFoldingFeature.STATE_FLAT;
- int otherState = ExtensionFoldingFeature.STATE_HALF_OPENED;
-
- ExtensionFoldingFeature original = new ExtensionFoldingFeature(rect, type,
- originalState);
- ExtensionFoldingFeature other = new ExtensionFoldingFeature(rect, type, otherState);
-
- assertNotEquals(original, other);
- }
-
- @Test
- public void testHashCode_matchesIfEqual() {
- Rect originalRect = new Rect(1, 0, 1, 10);
- Rect matchingRect = new Rect(1, 0, 1, 10);
- int type = ExtensionFoldingFeature.TYPE_FOLD;
- int state = ExtensionFoldingFeature.STATE_FLAT;
-
- ExtensionFoldingFeature original = new ExtensionFoldingFeature(originalRect, type,
- state);
- ExtensionFoldingFeature matching = new ExtensionFoldingFeature(matchingRect, type,
- state);
-
- assertEquals(original, matching);
- assertEquals(original.hashCode(), matching.hashCode());
- }
-}
diff --git a/window/window-extensions/src/androidTest/java/androidx/window/extensions/ExtensionWindowLayoutInfoTest.java b/window/window-extensions/src/androidTest/java/androidx/window/extensions/ExtensionWindowLayoutInfoTest.java
deleted file mode 100644
index 968ddb9..0000000
--- a/window/window-extensions/src/androidTest/java/androidx/window/extensions/ExtensionWindowLayoutInfoTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.graphics.Rect;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/** Tests for {@link ExtensionWindowLayoutInfo} class. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class ExtensionWindowLayoutInfoTest {
-
- @Test
- public void testEquals_sameFeatures() {
- List<ExtensionDisplayFeature> features = new ArrayList<>();
-
- ExtensionWindowLayoutInfo original = new ExtensionWindowLayoutInfo(features);
- ExtensionWindowLayoutInfo copy = new ExtensionWindowLayoutInfo(features);
-
- assertEquals(original, copy);
- }
-
- @Test
- public void testEquals_differentFeatures() {
- List<ExtensionDisplayFeature> originalFeatures = new ArrayList<>();
- List<ExtensionDisplayFeature> differentFeatures = new ArrayList<>();
- Rect rect = new Rect(1, 0, 1, 10);
- differentFeatures.add(new ExtensionFoldingFeature(
- rect, ExtensionFoldingFeature.TYPE_HINGE,
- ExtensionFoldingFeature.STATE_FLAT));
-
- ExtensionWindowLayoutInfo original = new ExtensionWindowLayoutInfo(originalFeatures);
- ExtensionWindowLayoutInfo different = new ExtensionWindowLayoutInfo(differentFeatures);
-
- assertNotEquals(original, different);
- }
-
- @Test
- public void testHashCode_matchesIfEqual() {
- List<ExtensionDisplayFeature> firstFeatures = new ArrayList<>();
- List<ExtensionDisplayFeature> secondFeatures = new ArrayList<>();
- ExtensionWindowLayoutInfo first = new ExtensionWindowLayoutInfo(firstFeatures);
- ExtensionWindowLayoutInfo second = new ExtensionWindowLayoutInfo(secondFeatures);
-
- assertEquals(first, second);
- assertEquals(first.hashCode(), second.hashCode());
- }
-
- @Test
- public void testHashCode_matchesIfEqualFeatures() {
- ExtensionDisplayFeature originalFeature = new ExtensionFoldingFeature(
- new Rect(0, 0, 100, 0),
- ExtensionFoldingFeature.TYPE_HINGE,
- ExtensionFoldingFeature.STATE_FLAT
- );
- ExtensionDisplayFeature matchingFeature = new ExtensionFoldingFeature(
- new Rect(0, 0, 100, 0),
- ExtensionFoldingFeature.TYPE_HINGE,
- ExtensionFoldingFeature.STATE_FLAT
- );
- List<ExtensionDisplayFeature> firstFeatures = Collections.singletonList(originalFeature);
- List<ExtensionDisplayFeature> secondFeatures = Collections.singletonList(matchingFeature);
- ExtensionWindowLayoutInfo first = new ExtensionWindowLayoutInfo(firstFeatures);
- ExtensionWindowLayoutInfo second = new ExtensionWindowLayoutInfo(secondFeatures);
-
- assertEquals(first, second);
- assertEquals(first.hashCode(), second.hashCode());
- }
-}
diff --git a/window/window-extensions/src/androidTest/java/androidx/window/extensions/layout/FoldingFeatureTest.java b/window/window-extensions/src/androidTest/java/androidx/window/extensions/layout/FoldingFeatureTest.java
new file mode 100644
index 0000000..49dcb8f
--- /dev/null
+++ b/window/window-extensions/src/androidTest/java/androidx/window/extensions/layout/FoldingFeatureTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.graphics.Rect;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for {@link FoldingFeature} class. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class FoldingFeatureTest {
+
+ @Test
+ public void testEquals_sameAttributes() {
+ Rect bounds = new Rect(1, 0, 1, 10);
+ int type = FoldingFeature.TYPE_FOLD;
+ int state = FoldingFeature.STATE_FLAT;
+
+ FoldingFeature original = new FoldingFeature(bounds, type, state);
+ FoldingFeature copy = new FoldingFeature(bounds, type, state);
+
+ assertEquals(original, copy);
+ }
+
+ @Test
+ public void testEquals_differentRect() {
+ Rect originalRect = new Rect(1, 0, 1, 10);
+ Rect otherRect = new Rect(2, 0, 2, 10);
+ int type = FoldingFeature.TYPE_FOLD;
+ int state = FoldingFeature.STATE_FLAT;
+
+ FoldingFeature original = new FoldingFeature(originalRect, type,
+ state);
+ FoldingFeature other = new FoldingFeature(otherRect, type, state);
+
+ assertNotEquals(original, other);
+ }
+
+ @Test
+ public void testEquals_differentType() {
+ Rect rect = new Rect(1, 0, 1, 10);
+ int originalType = FoldingFeature.TYPE_FOLD;
+ int otherType = FoldingFeature.TYPE_HINGE;
+ int state = FoldingFeature.STATE_FLAT;
+
+ FoldingFeature original = new FoldingFeature(rect, originalType,
+ state);
+ FoldingFeature other = new FoldingFeature(rect, otherType, state);
+
+ assertNotEquals(original, other);
+ }
+
+ @Test
+ public void testEquals_differentState() {
+ Rect rect = new Rect(1, 0, 1, 10);
+ int type = FoldingFeature.TYPE_FOLD;
+ int originalState = FoldingFeature.STATE_FLAT;
+ int otherState = FoldingFeature.STATE_HALF_OPENED;
+
+ FoldingFeature original = new FoldingFeature(rect, type,
+ originalState);
+ FoldingFeature other = new FoldingFeature(rect, type, otherState);
+
+ assertNotEquals(original, other);
+ }
+
+ @Test
+ public void testHashCode_matchesIfEqual() {
+ Rect originalRect = new Rect(1, 0, 1, 10);
+ Rect matchingRect = new Rect(1, 0, 1, 10);
+ int type = FoldingFeature.TYPE_FOLD;
+ int state = FoldingFeature.STATE_FLAT;
+
+ FoldingFeature original = new FoldingFeature(originalRect, type,
+ state);
+ FoldingFeature matching = new FoldingFeature(matchingRect, type,
+ state);
+
+ assertEquals(original, matching);
+ assertEquals(original.hashCode(), matching.hashCode());
+ }
+}
diff --git a/window/window-extensions/src/androidTest/java/androidx/window/extensions/layout/WindowLayoutInfoTest.java b/window/window-extensions/src/androidTest/java/androidx/window/extensions/layout/WindowLayoutInfoTest.java
new file mode 100644
index 0000000..3d51790
--- /dev/null
+++ b/window/window-extensions/src/androidTest/java/androidx/window/extensions/layout/WindowLayoutInfoTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.graphics.Rect;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** Tests for {@link WindowLayoutInfo} class. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class WindowLayoutInfoTest {
+
+ @Test
+ public void testEquals_sameFeatures() {
+ List<DisplayFeature> features = new ArrayList<>();
+
+ WindowLayoutInfo original = new WindowLayoutInfo(features);
+ WindowLayoutInfo copy = new WindowLayoutInfo(features);
+
+ assertEquals(original, copy);
+ }
+
+ @Test
+ public void testEquals_differentFeatures() {
+ List<DisplayFeature> originalFeatures = new ArrayList<>();
+ List<DisplayFeature> differentFeatures = new ArrayList<>();
+ Rect rect = new Rect(1, 0, 1, 10);
+ differentFeatures.add(new FoldingFeature(
+ rect, FoldingFeature.TYPE_HINGE,
+ FoldingFeature.STATE_FLAT));
+
+ WindowLayoutInfo original = new WindowLayoutInfo(originalFeatures);
+ WindowLayoutInfo different = new WindowLayoutInfo(differentFeatures);
+
+ assertNotEquals(original, different);
+ }
+
+ @Test
+ public void testHashCode_matchesIfEqual() {
+ List<DisplayFeature> firstFeatures = new ArrayList<>();
+ List<DisplayFeature> secondFeatures = new ArrayList<>();
+ WindowLayoutInfo first = new WindowLayoutInfo(firstFeatures);
+ WindowLayoutInfo second = new WindowLayoutInfo(secondFeatures);
+
+ assertEquals(first, second);
+ assertEquals(first.hashCode(), second.hashCode());
+ }
+
+ @Test
+ public void testHashCode_matchesIfEqualFeatures() {
+ DisplayFeature originalFeature = new FoldingFeature(
+ new Rect(0, 0, 100, 0),
+ FoldingFeature.TYPE_HINGE,
+ FoldingFeature.STATE_FLAT
+ );
+ DisplayFeature matchingFeature = new FoldingFeature(
+ new Rect(0, 0, 100, 0),
+ FoldingFeature.TYPE_HINGE,
+ FoldingFeature.STATE_FLAT
+ );
+ List<DisplayFeature> firstFeatures = Collections.singletonList(originalFeature);
+ List<DisplayFeature> secondFeatures = Collections.singletonList(matchingFeature);
+ WindowLayoutInfo first = new WindowLayoutInfo(firstFeatures);
+ WindowLayoutInfo second = new WindowLayoutInfo(secondFeatures);
+
+ assertEquals(first, second);
+ assertEquals(first.hashCode(), second.hashCode());
+ }
+}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionDisplayFeature.java b/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionDisplayFeature.java
deleted file mode 100644
index 76625ac..0000000
--- a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionDisplayFeature.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import android.graphics.Rect;
-
-import androidx.annotation.NonNull;
-
-/**
- * Description of a physical feature on the display.
- */
-public interface ExtensionDisplayFeature {
-
- /**
- * The bounding rectangle of the feature within the application window
- * in the window coordinate space.
- *
- * @return bounds of display feature.
- */
- @NonNull
- Rect getBounds();
-}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionFoldingFeature.java b/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionFoldingFeature.java
deleted file mode 100644
index 89d184d..0000000
--- a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionFoldingFeature.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import android.graphics.Rect;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A feature that describes a fold in a flexible display
- * or a hinge between two physical display panels.
- */
-public class ExtensionFoldingFeature implements ExtensionDisplayFeature {
-
- /**
- * A fold in the flexible screen without a physical gap.
- */
- public static final int TYPE_FOLD = 1;
-
- /**
- * A physical separation with a hinge that allows two display panels to fold.
- */
- public static final int TYPE_HINGE = 2;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- TYPE_FOLD,
- TYPE_HINGE,
- })
- @interface Type{}
-
- /**
- * The foldable device's hinge is completely open, the screen space that is presented to the
- * user is flat. See the
- * <a href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a>
- * section in the official documentation for visual samples and references.
- */
- public static final int STATE_FLAT = 1;
-
- /**
- * The foldable device's hinge is in an intermediate position between opened and closed state,
- * there is a non-flat angle between parts of the flexible screen or between physical screen
- * panels. See the
- * <a href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a>
- * section in the official documentation for visual samples and references.
- */
- public static final int STATE_HALF_OPENED = 2;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- STATE_HALF_OPENED,
- STATE_FLAT
- })
- @interface State {}
-
- /**
- * The bounding rectangle of the feature within the application window in the window
- * coordinate space.
- */
- @NonNull
- private final Rect mBounds;
-
- /**
- * The physical type of the feature.
- */
- @Type
- private final int mType;
-
- /**
- * The state of the feature.
- */
- @State
- private final int mState;
-
- public ExtensionFoldingFeature(@NonNull Rect bounds, @Type int type, @State int state) {
- validateFeatureBounds(bounds);
- mBounds = new Rect(bounds);
- mType = type;
- mState = state;
- }
-
- /** Gets the bounding rect of the display feature in window coordinate space. */
- @NonNull
- @Override
- public Rect getBounds() {
- return new Rect(mBounds);
- }
-
- /** Gets the type of the display feature. */
- @Type
- public int getType() {
- return mType;
- }
-
- /** Gets the state of the display feature. */
- @State
- public int getState() {
- return mState;
- }
-
- /**
- * Verifies the bounds of the folding feature.
- */
- private static void validateFeatureBounds(@NonNull Rect bounds) {
- if (bounds.width() == 0 && bounds.height() == 0) {
- throw new IllegalArgumentException("Bounds must be non zero");
- }
- if (bounds.left != 0 && bounds.top != 0) {
- throw new IllegalArgumentException("Bounding rectangle must start at the top or "
- + "left window edge for folding features");
- }
- }
-
- @NonNull
- private static String typeToString(int type) {
- switch (type) {
- case TYPE_FOLD:
- return "FOLD";
- case TYPE_HINGE:
- return "HINGE";
- default:
- return "Unknown feature type (" + type + ")";
- }
- }
-
- @NonNull
- private static String stateToString(int state) {
- switch (state) {
- case STATE_FLAT:
- return "FLAT";
- case STATE_HALF_OPENED:
- return "HALF_OPENED";
- default:
- return "Unknown feature state (" + state + ")";
- }
- }
-
- @NonNull
- @Override
- public String toString() {
- return "ExtensionDisplayFoldFeature { " + mBounds
- + ", type=" + typeToString(getType()) + ", state=" + stateToString(mState) + " }";
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof ExtensionFoldingFeature)) {
- return false;
- }
- final ExtensionFoldingFeature other = (ExtensionFoldingFeature) obj;
- if (mType != other.mType) {
- return false;
- }
- if (mState != other.mState) {
- return false;
- }
- return mBounds.equals(other.mBounds);
- }
-
- /**
- * Manually computes the hashCode for the {@link Rect} since it is not implemented
- * on API 15
- */
- private static int hashBounds(Rect bounds) {
- int result = bounds.left;
- result = 31 * result + bounds.top;
- result = 31 * result + bounds.right;
- result = 31 * result + bounds.bottom;
- return result;
- }
-
- @Override
- public int hashCode() {
- int result = hashBounds(mBounds);
- result = 31 * result + mType;
- result = 31 * result + mState;
- return result;
- }
-}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionInterface.java b/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionInterface.java
deleted file mode 100644
index 62e04ee..0000000
--- a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionInterface.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import android.app.Activity;
-
-import androidx.annotation.NonNull;
-
-/**
- * Main Extension interface definition that will be used by the WindowManager library to get custom
- * OEM-provided information that isn't covered by platform APIs.
- *
- * <p>This interface should be implemented by OEM and deployed to the target devices.
- *
- * @see ExtensionProvider
- */
-public interface ExtensionInterface {
-
- /**
- * Registers the support library as the callback for the extension. This interface will be used
- * to report all extension changes to the support library.
- */
- void setExtensionCallback(@NonNull ExtensionCallback callback);
-
- /**
- * Notifies extension that a listener for display feature layout changes was registered for the
- * given {@link Activity} context.
- */
- void onWindowLayoutChangeListenerAdded(@NonNull Activity activity);
-
- /**
- * Notifies extension that a listener for display feature layout changes was removed for the
- * given {@link Activity} context.
- */
- void onWindowLayoutChangeListenerRemoved(@NonNull Activity activity);
-
- /**
- * Callback that will be registered with the WindowManager library, and that the extension
- * should use to report all state changes.
- */
- interface ExtensionCallback {
- /**
- * Called by extension when the feature layout inside the window changes. Initial value
- * should be provided as soon as possible.
- */
- void onWindowLayoutChanged(@NonNull Activity activity,
- @NonNull ExtensionWindowLayoutInfo newLayout);
- }
-}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionProvider.java b/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionProvider.java
index 536389a..fe75056 100644
--- a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionProvider.java
+++ b/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.window.extensions.layout.ExtensionInterface;
/**
* A stub implementation for the class that will instantiate the Extension.
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionWindowLayoutInfo.java b/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionWindowLayoutInfo.java
deleted file mode 100644
index fe2ef90..0000000
--- a/window/window-extensions/src/main/java/androidx/window/extensions/ExtensionWindowLayoutInfo.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Contains information about the layout of display features within the window.
- */
-public class ExtensionWindowLayoutInfo {
-
- /**
- * List of display features within the window.
- * <p>NOTE: All display features returned with this container must be cropped to the application
- * window and reported within the coordinate space of the window that was provided by the app.
- */
- @NonNull
- private List<ExtensionDisplayFeature> mDisplayFeatures;
-
- public ExtensionWindowLayoutInfo(@NonNull List<ExtensionDisplayFeature> displayFeatures) {
- mDisplayFeatures = Collections.unmodifiableList(displayFeatures);
- }
-
- /**
- * Gets the list of display features present within the window.
- */
- @NonNull
- public List<ExtensionDisplayFeature> getDisplayFeatures() {
- return mDisplayFeatures;
- }
-
- @NonNull
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("ExtensionWindowLayoutInfo { ExtensionDisplayFeatures[ ");
- for (int i = 0; i < mDisplayFeatures.size(); i = i + 1) {
- sb.append(mDisplayFeatures.get(i));
- if (i < mDisplayFeatures.size() - 1) {
- sb.append(", ");
- }
- }
- sb.append(" ] }");
- return sb.toString();
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof ExtensionWindowLayoutInfo)) {
- return false;
- }
- final ExtensionWindowLayoutInfo
- other = (ExtensionWindowLayoutInfo) obj;
- if (mDisplayFeatures == null) {
- return other.mDisplayFeatures == null;
- }
- return mDisplayFeatures.equals(other.mDisplayFeatures);
- }
-
- @Override
- public int hashCode() {
- return mDisplayFeatures != null ? mDisplayFeatures.size() : 0;
- }
-}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/StubExtension.java b/window/window-extensions/src/main/java/androidx/window/extensions/StubExtension.java
index 283b5a1..f764c2f 100644
--- a/window/window-extensions/src/main/java/androidx/window/extensions/StubExtension.java
+++ b/window/window-extensions/src/main/java/androidx/window/extensions/StubExtension.java
@@ -19,6 +19,8 @@
import android.app.Activity;
import androidx.annotation.NonNull;
+import androidx.window.extensions.layout.ExtensionInterface;
+import androidx.window.extensions.layout.WindowLayoutInfo;
import java.util.HashSet;
import java.util.Set;
@@ -49,7 +51,7 @@
}
protected void updateWindowLayout(@NonNull Activity activity,
- @NonNull ExtensionWindowLayoutInfo newLayout) {
+ @NonNull WindowLayoutInfo newLayout) {
if (mExtensionCallback != null) {
mExtensionCallback.onWindowLayoutChanged(activity, newLayout);
}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java b/window/window-extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java
new file mode 100644
index 0000000..32b0fa1
--- /dev/null
+++ b/window/window-extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import android.graphics.Rect;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Description of a physical feature on the display.
+ */
+public interface DisplayFeature {
+
+ /**
+ * The bounding rectangle of the feature within the application window
+ * in the window coordinate space.
+ *
+ * @return bounds of display feature.
+ */
+ @NonNull
+ Rect getBounds();
+}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/layout/ExtensionInterface.java b/window/window-extensions/src/main/java/androidx/window/extensions/layout/ExtensionInterface.java
new file mode 100644
index 0000000..b708006
--- /dev/null
+++ b/window/window-extensions/src/main/java/androidx/window/extensions/layout/ExtensionInterface.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+import androidx.window.extensions.ExtensionProvider;
+
+/**
+ * Main Extension interface definition that will be used by the WindowManager library to get custom
+ * OEM-provided information that isn't covered by platform APIs.
+ *
+ * <p>This interface should be implemented by OEM and deployed to the target devices.
+ *
+ * @see ExtensionProvider
+ */
+public interface ExtensionInterface {
+
+ /**
+ * Registers the support library as the callback for the extension. This interface will be used
+ * to report all extension changes to the support library.
+ */
+ void setExtensionCallback(@NonNull ExtensionCallback callback);
+
+ /**
+ * Notifies extension that a listener for display feature layout changes was registered for the
+ * given {@link Activity} context.
+ */
+ void onWindowLayoutChangeListenerAdded(@NonNull Activity activity);
+
+ /**
+ * Notifies extension that a listener for display feature layout changes was removed for the
+ * given {@link Activity} context.
+ */
+ void onWindowLayoutChangeListenerRemoved(@NonNull Activity activity);
+
+ /**
+ * Callback that will be registered with the WindowManager library, and that the extension
+ * should use to report all state changes.
+ */
+ interface ExtensionCallback {
+ /**
+ * Called by extension when the feature layout inside the window changes. Initial value
+ * should be provided as soon as possible.
+ */
+ void onWindowLayoutChanged(@NonNull Activity activity,
+ @NonNull WindowLayoutInfo newLayout);
+ }
+}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java b/window/window-extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java
new file mode 100644
index 0000000..0e74057
--- /dev/null
+++ b/window/window-extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import android.graphics.Rect;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A feature that describes a fold in a flexible display
+ * or a hinge between two physical display panels.
+ */
+public class FoldingFeature implements DisplayFeature {
+
+ /**
+ * A fold in the flexible screen without a physical gap.
+ */
+ public static final int TYPE_FOLD = 1;
+
+ /**
+ * A physical separation with a hinge that allows two display panels to fold.
+ */
+ public static final int TYPE_HINGE = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TYPE_FOLD,
+ TYPE_HINGE,
+ })
+ @interface Type{}
+
+ /**
+ * The foldable device's hinge is completely open, the screen space that is presented to the
+ * user is flat. See the
+ * <a href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a>
+ * section in the official documentation for visual samples and references.
+ */
+ public static final int STATE_FLAT = 1;
+
+ /**
+ * The foldable device's hinge is in an intermediate position between opened and closed state,
+ * there is a non-flat angle between parts of the flexible screen or between physical screen
+ * panels. See the
+ * <a href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a>
+ * section in the official documentation for visual samples and references.
+ */
+ public static final int STATE_HALF_OPENED = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ STATE_HALF_OPENED,
+ STATE_FLAT
+ })
+ @interface State {}
+
+ /**
+ * The bounding rectangle of the feature within the application window in the window
+ * coordinate space.
+ */
+ @NonNull
+ private final Rect mBounds;
+
+ /**
+ * The physical type of the feature.
+ */
+ @Type
+ private final int mType;
+
+ /**
+ * The state of the feature.
+ */
+ @State
+ private final int mState;
+
+ public FoldingFeature(@NonNull Rect bounds, @Type int type, @State int state) {
+ validateFeatureBounds(bounds);
+ mBounds = new Rect(bounds);
+ mType = type;
+ mState = state;
+ }
+
+ /** Gets the bounding rect of the display feature in window coordinate space. */
+ @NonNull
+ @Override
+ public Rect getBounds() {
+ return new Rect(mBounds);
+ }
+
+ /** Gets the type of the display feature. */
+ @Type
+ public int getType() {
+ return mType;
+ }
+
+ /** Gets the state of the display feature. */
+ @State
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * Verifies the bounds of the folding feature.
+ */
+ private static void validateFeatureBounds(@NonNull Rect bounds) {
+ if (bounds.width() == 0 && bounds.height() == 0) {
+ throw new IllegalArgumentException("Bounds must be non zero");
+ }
+ if (bounds.left != 0 && bounds.top != 0) {
+ throw new IllegalArgumentException("Bounding rectangle must start at the top or "
+ + "left window edge for folding features");
+ }
+ }
+
+ @NonNull
+ private static String typeToString(int type) {
+ switch (type) {
+ case TYPE_FOLD:
+ return "FOLD";
+ case TYPE_HINGE:
+ return "HINGE";
+ default:
+ return "Unknown feature type (" + type + ")";
+ }
+ }
+
+ @NonNull
+ private static String stateToString(int state) {
+ switch (state) {
+ case STATE_FLAT:
+ return "FLAT";
+ case STATE_HALF_OPENED:
+ return "HALF_OPENED";
+ default:
+ return "Unknown feature state (" + state + ")";
+ }
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "ExtensionDisplayFoldFeature { " + mBounds
+ + ", type=" + typeToString(getType()) + ", state=" + stateToString(mState) + " }";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof FoldingFeature)) {
+ return false;
+ }
+ final FoldingFeature other = (FoldingFeature) obj;
+ if (mType != other.mType) {
+ return false;
+ }
+ if (mState != other.mState) {
+ return false;
+ }
+ return mBounds.equals(other.mBounds);
+ }
+
+ /**
+ * Manually computes the hashCode for the {@link Rect} since it is not implemented
+ * on API 15
+ */
+ private static int hashBounds(Rect bounds) {
+ int result = bounds.left;
+ result = 31 * result + bounds.top;
+ result = 31 * result + bounds.right;
+ result = 31 * result + bounds.bottom;
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = hashBounds(mBounds);
+ result = 31 * result + mType;
+ result = 31 * result + mState;
+ return result;
+ }
+}
diff --git a/window/window-extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java b/window/window-extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java
new file mode 100644
index 0000000..9041f0a
--- /dev/null
+++ b/window/window-extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Contains information about the layout of display features within the window.
+ */
+public class WindowLayoutInfo {
+
+ /**
+ * List of display features within the window.
+ * <p>NOTE: All display features returned with this container must be cropped to the application
+ * window and reported within the coordinate space of the window that was provided by the app.
+ */
+ @NonNull
+ private List<DisplayFeature> mDisplayFeatures;
+
+ public WindowLayoutInfo(@NonNull List<DisplayFeature> displayFeatures) {
+ mDisplayFeatures = Collections.unmodifiableList(displayFeatures);
+ }
+
+ /**
+ * Gets the list of display features present within the window.
+ */
+ @NonNull
+ public List<DisplayFeature> getDisplayFeatures() {
+ return mDisplayFeatures;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("ExtensionWindowLayoutInfo { ExtensionDisplayFeatures[ ");
+ for (int i = 0; i < mDisplayFeatures.size(); i = i + 1) {
+ sb.append(mDisplayFeatures.get(i));
+ if (i < mDisplayFeatures.size() - 1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(" ] }");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WindowLayoutInfo)) {
+ return false;
+ }
+ final WindowLayoutInfo
+ other = (WindowLayoutInfo) obj;
+ if (mDisplayFeatures == null) {
+ return other.mDisplayFeatures == null;
+ }
+ return mDisplayFeatures.equals(other.mDisplayFeatures);
+ }
+
+ @Override
+ public int hashCode() {
+ return mDisplayFeatures != null ? mDisplayFeatures.size() : 0;
+ }
+}
diff --git a/window/window-java/api/1.0.0-beta01.txt b/window/window-java/api/1.0.0-beta01.txt
new file mode 100644
index 0000000..8ea20c0
--- /dev/null
+++ b/window/window-java/api/1.0.0-beta01.txt
@@ -0,0 +1,13 @@
+// Signature format: 4.0
+package androidx.window.java.layout {
+
+ public final class WindowInfoRepositoryCallbackAdapter implements androidx.window.layout.WindowInfoRepository {
+ ctor public WindowInfoRepositoryCallbackAdapter(androidx.window.layout.WindowInfoRepository repository);
+ method public void addCurrentWindowMetricsListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowMetrics> consumer);
+ method public void addWindowLayoutInfoListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ method public void removeCurrentWindowMetricsListener(androidx.core.util.Consumer<androidx.window.layout.WindowMetrics> consumer);
+ method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ }
+
+}
+
diff --git a/window/window-java/api/public_plus_experimental_1.0.0-beta01.txt b/window/window-java/api/public_plus_experimental_1.0.0-beta01.txt
new file mode 100644
index 0000000..8ea20c0
--- /dev/null
+++ b/window/window-java/api/public_plus_experimental_1.0.0-beta01.txt
@@ -0,0 +1,13 @@
+// Signature format: 4.0
+package androidx.window.java.layout {
+
+ public final class WindowInfoRepositoryCallbackAdapter implements androidx.window.layout.WindowInfoRepository {
+ ctor public WindowInfoRepositoryCallbackAdapter(androidx.window.layout.WindowInfoRepository repository);
+ method public void addCurrentWindowMetricsListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowMetrics> consumer);
+ method public void addWindowLayoutInfoListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ method public void removeCurrentWindowMetricsListener(androidx.core.util.Consumer<androidx.window.layout.WindowMetrics> consumer);
+ method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ }
+
+}
+
diff --git a/work/workmanager-gcm/api/res-2.6.0-beta01.txt b/window/window-java/api/res-1.0.0-beta01.txt
similarity index 100%
copy from work/workmanager-gcm/api/res-2.6.0-beta01.txt
copy to window/window-java/api/res-1.0.0-beta01.txt
diff --git a/window/window-java/api/restricted_1.0.0-beta01.txt b/window/window-java/api/restricted_1.0.0-beta01.txt
new file mode 100644
index 0000000..8ea20c0
--- /dev/null
+++ b/window/window-java/api/restricted_1.0.0-beta01.txt
@@ -0,0 +1,13 @@
+// Signature format: 4.0
+package androidx.window.java.layout {
+
+ public final class WindowInfoRepositoryCallbackAdapter implements androidx.window.layout.WindowInfoRepository {
+ ctor public WindowInfoRepositoryCallbackAdapter(androidx.window.layout.WindowInfoRepository repository);
+ method public void addCurrentWindowMetricsListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowMetrics> consumer);
+ method public void addWindowLayoutInfoListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ method public void removeCurrentWindowMetricsListener(androidx.core.util.Consumer<androidx.window.layout.WindowMetrics> consumer);
+ method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ }
+
+}
+
diff --git a/window/window-rxjava2/api/1.0.0-beta01.txt b/window/window-rxjava2/api/1.0.0-beta01.txt
new file mode 100644
index 0000000..ba57afd
--- /dev/null
+++ b/window/window-rxjava2/api/1.0.0-beta01.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+ public final class WindowInfoRepositoryRx {
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowMetrics> currentWindowMetricsFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowMetrics> currentWindowMetricsObservable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoRepository);
+ }
+
+}
+
diff --git a/window/window-rxjava2/api/public_plus_experimental_1.0.0-beta01.txt b/window/window-rxjava2/api/public_plus_experimental_1.0.0-beta01.txt
new file mode 100644
index 0000000..ba57afd
--- /dev/null
+++ b/window/window-rxjava2/api/public_plus_experimental_1.0.0-beta01.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+ public final class WindowInfoRepositoryRx {
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowMetrics> currentWindowMetricsFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowMetrics> currentWindowMetricsObservable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoRepository);
+ }
+
+}
+
diff --git a/work/workmanager-rxjava2/api/res-2.6.0-beta01.txt b/window/window-rxjava2/api/res-1.0.0-beta01.txt
similarity index 100%
copy from work/workmanager-rxjava2/api/res-2.6.0-beta01.txt
copy to window/window-rxjava2/api/res-1.0.0-beta01.txt
diff --git a/window/window-rxjava2/api/restricted_1.0.0-beta01.txt b/window/window-rxjava2/api/restricted_1.0.0-beta01.txt
new file mode 100644
index 0000000..ba57afd
--- /dev/null
+++ b/window/window-rxjava2/api/restricted_1.0.0-beta01.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+ public final class WindowInfoRepositoryRx {
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowMetrics> currentWindowMetricsFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowMetrics> currentWindowMetricsObservable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoRepository);
+ }
+
+}
+
diff --git a/window/window-rxjava3/api/1.0.0-beta01.txt b/window/window-rxjava3/api/1.0.0-beta01.txt
new file mode 100644
index 0000000..f4a0b0e
--- /dev/null
+++ b/window/window-rxjava3/api/1.0.0-beta01.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+ public final class WindowInfoRepositoryRx {
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowMetrics> currentWindowMetricsFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowMetrics> currentWindowMetricsObservable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoRepository);
+ }
+
+}
+
diff --git a/window/window-rxjava3/api/public_plus_experimental_1.0.0-beta01.txt b/window/window-rxjava3/api/public_plus_experimental_1.0.0-beta01.txt
new file mode 100644
index 0000000..f4a0b0e
--- /dev/null
+++ b/window/window-rxjava3/api/public_plus_experimental_1.0.0-beta01.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+ public final class WindowInfoRepositoryRx {
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowMetrics> currentWindowMetricsFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowMetrics> currentWindowMetricsObservable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoRepository);
+ }
+
+}
+
diff --git a/work/workmanager-rxjava3/api/res-2.6.0-beta01.txt b/window/window-rxjava3/api/res-1.0.0-beta01.txt
similarity index 100%
copy from work/workmanager-rxjava3/api/res-2.6.0-beta01.txt
copy to window/window-rxjava3/api/res-1.0.0-beta01.txt
diff --git a/window/window-rxjava3/api/restricted_1.0.0-beta01.txt b/window/window-rxjava3/api/restricted_1.0.0-beta01.txt
new file mode 100644
index 0000000..f4a0b0e
--- /dev/null
+++ b/window/window-rxjava3/api/restricted_1.0.0-beta01.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+ public final class WindowInfoRepositoryRx {
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowMetrics> currentWindowMetricsFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowMetrics> currentWindowMetricsObservable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoRepository);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoRepository);
+ }
+
+}
+
diff --git a/window/window-samples/src/main/AndroidManifest.xml b/window/window-samples/src/main/AndroidManifest.xml
index edabb02..f933814 100644
--- a/window/window-samples/src/main/AndroidManifest.xml
+++ b/window/window-samples/src/main/AndroidManifest.xml
@@ -24,6 +24,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".WindowDemosActivity"
+ android:exported="true"
android:label="@string/windowManagerDemos">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -31,12 +32,15 @@
</intent-filter>
</activity>
<activity android:name=".PresentationActivity"
+ android:exported="false"
android:label="@string/presentation" />
<activity
android:name=".DisplayFeaturesActivity"
+ android:exported="false"
android:label="@string/display_features" />
<activity
android:name=".SplitLayoutActivity"
+ android:exported="false"
android:label="@string/split_layout" />
</application>
diff --git a/window/window-sidecar/api/0.1.0-beta01.txt b/window/window-sidecar/api/0.1.0-beta01.txt
new file mode 100644
index 0000000..9a84465
--- /dev/null
+++ b/window/window-sidecar/api/0.1.0-beta01.txt
@@ -0,0 +1,49 @@
+// Signature format: 4.0
+package androidx.window.sidecar {
+
+ @Deprecated public final class SidecarDeviceState {
+ ctor @Deprecated public SidecarDeviceState();
+ field @Deprecated public static final int POSTURE_CLOSED = 1; // 0x1
+ field @Deprecated public static final int POSTURE_FLIPPED = 4; // 0x4
+ field @Deprecated public static final int POSTURE_HALF_OPENED = 2; // 0x2
+ field @Deprecated public static final int POSTURE_OPENED = 3; // 0x3
+ field @Deprecated public static final int POSTURE_UNKNOWN = 0; // 0x0
+ field @Deprecated public int posture;
+ }
+
+ @Deprecated public final class SidecarDisplayFeature {
+ ctor @Deprecated public SidecarDisplayFeature();
+ method @Deprecated public android.graphics.Rect getRect();
+ method @Deprecated public int getType();
+ method @Deprecated public void setRect(android.graphics.Rect);
+ method @Deprecated public void setType(int);
+ field @Deprecated public static final int TYPE_FOLD = 1; // 0x1
+ field @Deprecated public static final int TYPE_HINGE = 2; // 0x2
+ }
+
+ @Deprecated public interface SidecarInterface {
+ method @Deprecated public androidx.window.sidecar.SidecarDeviceState getDeviceState();
+ method @Deprecated public androidx.window.sidecar.SidecarWindowLayoutInfo getWindowLayoutInfo(android.os.IBinder);
+ method @Deprecated public void onDeviceStateListenersChanged(boolean);
+ method @Deprecated public void onWindowLayoutChangeListenerAdded(android.os.IBinder);
+ method @Deprecated public void onWindowLayoutChangeListenerRemoved(android.os.IBinder);
+ method @Deprecated public void setSidecarCallback(androidx.window.sidecar.SidecarInterface.SidecarCallback);
+ }
+
+ @Deprecated public static interface SidecarInterface.SidecarCallback {
+ method @Deprecated public void onDeviceStateChanged(androidx.window.sidecar.SidecarDeviceState);
+ method @Deprecated public void onWindowLayoutChanged(android.os.IBinder, androidx.window.sidecar.SidecarWindowLayoutInfo);
+ }
+
+ @Deprecated public class SidecarProvider {
+ method @Deprecated public static String? getApiVersion();
+ method @Deprecated public static androidx.window.sidecar.SidecarInterface? getSidecarImpl(android.content.Context);
+ }
+
+ @Deprecated public final class SidecarWindowLayoutInfo {
+ ctor @Deprecated public SidecarWindowLayoutInfo();
+ field @Deprecated public java.util.List<androidx.window.sidecar.SidecarDisplayFeature!>? displayFeatures;
+ }
+
+}
+
diff --git a/window/window-sidecar/api/public_plus_experimental_0.1.0-beta01.txt b/window/window-sidecar/api/public_plus_experimental_0.1.0-beta01.txt
new file mode 100644
index 0000000..9a84465
--- /dev/null
+++ b/window/window-sidecar/api/public_plus_experimental_0.1.0-beta01.txt
@@ -0,0 +1,49 @@
+// Signature format: 4.0
+package androidx.window.sidecar {
+
+ @Deprecated public final class SidecarDeviceState {
+ ctor @Deprecated public SidecarDeviceState();
+ field @Deprecated public static final int POSTURE_CLOSED = 1; // 0x1
+ field @Deprecated public static final int POSTURE_FLIPPED = 4; // 0x4
+ field @Deprecated public static final int POSTURE_HALF_OPENED = 2; // 0x2
+ field @Deprecated public static final int POSTURE_OPENED = 3; // 0x3
+ field @Deprecated public static final int POSTURE_UNKNOWN = 0; // 0x0
+ field @Deprecated public int posture;
+ }
+
+ @Deprecated public final class SidecarDisplayFeature {
+ ctor @Deprecated public SidecarDisplayFeature();
+ method @Deprecated public android.graphics.Rect getRect();
+ method @Deprecated public int getType();
+ method @Deprecated public void setRect(android.graphics.Rect);
+ method @Deprecated public void setType(int);
+ field @Deprecated public static final int TYPE_FOLD = 1; // 0x1
+ field @Deprecated public static final int TYPE_HINGE = 2; // 0x2
+ }
+
+ @Deprecated public interface SidecarInterface {
+ method @Deprecated public androidx.window.sidecar.SidecarDeviceState getDeviceState();
+ method @Deprecated public androidx.window.sidecar.SidecarWindowLayoutInfo getWindowLayoutInfo(android.os.IBinder);
+ method @Deprecated public void onDeviceStateListenersChanged(boolean);
+ method @Deprecated public void onWindowLayoutChangeListenerAdded(android.os.IBinder);
+ method @Deprecated public void onWindowLayoutChangeListenerRemoved(android.os.IBinder);
+ method @Deprecated public void setSidecarCallback(androidx.window.sidecar.SidecarInterface.SidecarCallback);
+ }
+
+ @Deprecated public static interface SidecarInterface.SidecarCallback {
+ method @Deprecated public void onDeviceStateChanged(androidx.window.sidecar.SidecarDeviceState);
+ method @Deprecated public void onWindowLayoutChanged(android.os.IBinder, androidx.window.sidecar.SidecarWindowLayoutInfo);
+ }
+
+ @Deprecated public class SidecarProvider {
+ method @Deprecated public static String? getApiVersion();
+ method @Deprecated public static androidx.window.sidecar.SidecarInterface? getSidecarImpl(android.content.Context);
+ }
+
+ @Deprecated public final class SidecarWindowLayoutInfo {
+ ctor @Deprecated public SidecarWindowLayoutInfo();
+ field @Deprecated public java.util.List<androidx.window.sidecar.SidecarDisplayFeature!>? displayFeatures;
+ }
+
+}
+
diff --git a/work/workmanager/api/res-2.6.0-beta01.txt b/window/window-sidecar/api/res-0.1.0-beta01.txt
similarity index 100%
copy from work/workmanager/api/res-2.6.0-beta01.txt
copy to window/window-sidecar/api/res-0.1.0-beta01.txt
diff --git a/window/window-sidecar/api/restricted_0.1.0-beta01.txt b/window/window-sidecar/api/restricted_0.1.0-beta01.txt
new file mode 100644
index 0000000..9a84465
--- /dev/null
+++ b/window/window-sidecar/api/restricted_0.1.0-beta01.txt
@@ -0,0 +1,49 @@
+// Signature format: 4.0
+package androidx.window.sidecar {
+
+ @Deprecated public final class SidecarDeviceState {
+ ctor @Deprecated public SidecarDeviceState();
+ field @Deprecated public static final int POSTURE_CLOSED = 1; // 0x1
+ field @Deprecated public static final int POSTURE_FLIPPED = 4; // 0x4
+ field @Deprecated public static final int POSTURE_HALF_OPENED = 2; // 0x2
+ field @Deprecated public static final int POSTURE_OPENED = 3; // 0x3
+ field @Deprecated public static final int POSTURE_UNKNOWN = 0; // 0x0
+ field @Deprecated public int posture;
+ }
+
+ @Deprecated public final class SidecarDisplayFeature {
+ ctor @Deprecated public SidecarDisplayFeature();
+ method @Deprecated public android.graphics.Rect getRect();
+ method @Deprecated public int getType();
+ method @Deprecated public void setRect(android.graphics.Rect);
+ method @Deprecated public void setType(int);
+ field @Deprecated public static final int TYPE_FOLD = 1; // 0x1
+ field @Deprecated public static final int TYPE_HINGE = 2; // 0x2
+ }
+
+ @Deprecated public interface SidecarInterface {
+ method @Deprecated public androidx.window.sidecar.SidecarDeviceState getDeviceState();
+ method @Deprecated public androidx.window.sidecar.SidecarWindowLayoutInfo getWindowLayoutInfo(android.os.IBinder);
+ method @Deprecated public void onDeviceStateListenersChanged(boolean);
+ method @Deprecated public void onWindowLayoutChangeListenerAdded(android.os.IBinder);
+ method @Deprecated public void onWindowLayoutChangeListenerRemoved(android.os.IBinder);
+ method @Deprecated public void setSidecarCallback(androidx.window.sidecar.SidecarInterface.SidecarCallback);
+ }
+
+ @Deprecated public static interface SidecarInterface.SidecarCallback {
+ method @Deprecated public void onDeviceStateChanged(androidx.window.sidecar.SidecarDeviceState);
+ method @Deprecated public void onWindowLayoutChanged(android.os.IBinder, androidx.window.sidecar.SidecarWindowLayoutInfo);
+ }
+
+ @Deprecated public class SidecarProvider {
+ method @Deprecated public static String? getApiVersion();
+ method @Deprecated public static androidx.window.sidecar.SidecarInterface? getSidecarImpl(android.content.Context);
+ }
+
+ @Deprecated public final class SidecarWindowLayoutInfo {
+ ctor @Deprecated public SidecarWindowLayoutInfo();
+ field @Deprecated public java.util.List<androidx.window.sidecar.SidecarDisplayFeature!>? displayFeatures;
+ }
+
+}
+
diff --git a/window/window-testing/api/1.0.0-beta01.txt b/window/window-testing/api/1.0.0-beta01.txt
new file mode 100644
index 0000000..f47d528
--- /dev/null
+++ b/window/window-testing/api/1.0.0-beta01.txt
@@ -0,0 +1,19 @@
+// Signature format: 4.0
+package androidx.window.testing.layout {
+
+ public final class DisplayFeatureTesting {
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+ }
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+ }
+
+}
+
diff --git a/window/window-testing/api/public_plus_experimental_1.0.0-beta01.txt b/window/window-testing/api/public_plus_experimental_1.0.0-beta01.txt
new file mode 100644
index 0000000..5712b93
--- /dev/null
+++ b/window/window-testing/api/public_plus_experimental_1.0.0-beta01.txt
@@ -0,0 +1,19 @@
+// Signature format: 4.0
+package androidx.window.testing.layout {
+
+ public final class DisplayFeatureTesting {
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+ }
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+ }
+
+}
+
diff --git a/work/workmanager-testing/api/res-2.6.0-beta01.txt b/window/window-testing/api/res-1.0.0-beta01.txt
similarity index 100%
copy from work/workmanager-testing/api/res-2.6.0-beta01.txt
copy to window/window-testing/api/res-1.0.0-beta01.txt
diff --git a/window/window-testing/api/restricted_1.0.0-beta01.txt b/window/window-testing/api/restricted_1.0.0-beta01.txt
new file mode 100644
index 0000000..f47d528
--- /dev/null
+++ b/window/window-testing/api/restricted_1.0.0-beta01.txt
@@ -0,0 +1,19 @@
+// Signature format: 4.0
+package androidx.window.testing.layout {
+
+ public final class DisplayFeatureTesting {
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+ }
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+ }
+
+}
+
diff --git a/window/window/api/1.0.0-beta01.txt b/window/window/api/1.0.0-beta01.txt
new file mode 100644
index 0000000..f87dfd1
--- /dev/null
+++ b/window/window/api/1.0.0-beta01.txt
@@ -0,0 +1,89 @@
+// Signature format: 4.0
+package androidx.window.layout {
+
+ public interface DisplayFeature {
+ method public android.graphics.Rect getBounds();
+ property public abstract android.graphics.Rect bounds;
+ }
+
+ public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+ method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+ method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+ method public androidx.window.layout.FoldingFeature.State getState();
+ method public boolean isSeparating();
+ property public abstract boolean isSeparating;
+ property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+ property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+ property public abstract androidx.window.layout.FoldingFeature.State state;
+ }
+
+ public static final class FoldingFeature.OcclusionType {
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+ }
+
+ public static final class FoldingFeature.OcclusionType.Companion {
+ }
+
+ public static final class FoldingFeature.Orientation {
+ field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+ field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+ }
+
+ public static final class FoldingFeature.Orientation.Companion {
+ }
+
+ public static final class FoldingFeature.State {
+ field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.State FLAT;
+ field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+ }
+
+ public static final class FoldingFeature.State.Companion {
+ }
+
+ public interface WindowInfoRepository {
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowMetrics> getCurrentWindowMetrics();
+ method public default static androidx.window.layout.WindowInfoRepository getOrCreate(android.app.Activity);
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> getWindowLayoutInfo();
+ property public abstract kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowMetrics> currentWindowMetrics;
+ property public abstract kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo;
+ field public static final androidx.window.layout.WindowInfoRepository.Companion Companion;
+ }
+
+ public static final class WindowInfoRepository.Companion {
+ method public androidx.window.layout.WindowInfoRepository getOrCreate(android.app.Activity);
+ }
+
+ public final class WindowLayoutInfo {
+ method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+ property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+ }
+
+ public static final class WindowLayoutInfo.Builder {
+ ctor public WindowLayoutInfo.Builder();
+ method public androidx.window.layout.WindowLayoutInfo build();
+ method public androidx.window.layout.WindowLayoutInfo.Builder setDisplayFeatures(java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+ }
+
+ public final class WindowMetrics {
+ ctor public WindowMetrics(android.graphics.Rect bounds);
+ method public android.graphics.Rect getBounds();
+ property public final android.graphics.Rect bounds;
+ }
+
+ public interface WindowMetricsCalculator {
+ method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+ method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+ method public default static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+ }
+
+ public static final class WindowMetricsCalculator.Companion {
+ method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ }
+
+}
+
diff --git a/window/window/api/public_plus_experimental_1.0.0-beta01.txt b/window/window/api/public_plus_experimental_1.0.0-beta01.txt
new file mode 100644
index 0000000..f87dfd1
--- /dev/null
+++ b/window/window/api/public_plus_experimental_1.0.0-beta01.txt
@@ -0,0 +1,89 @@
+// Signature format: 4.0
+package androidx.window.layout {
+
+ public interface DisplayFeature {
+ method public android.graphics.Rect getBounds();
+ property public abstract android.graphics.Rect bounds;
+ }
+
+ public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+ method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+ method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+ method public androidx.window.layout.FoldingFeature.State getState();
+ method public boolean isSeparating();
+ property public abstract boolean isSeparating;
+ property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+ property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+ property public abstract androidx.window.layout.FoldingFeature.State state;
+ }
+
+ public static final class FoldingFeature.OcclusionType {
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+ }
+
+ public static final class FoldingFeature.OcclusionType.Companion {
+ }
+
+ public static final class FoldingFeature.Orientation {
+ field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+ field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+ }
+
+ public static final class FoldingFeature.Orientation.Companion {
+ }
+
+ public static final class FoldingFeature.State {
+ field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.State FLAT;
+ field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+ }
+
+ public static final class FoldingFeature.State.Companion {
+ }
+
+ public interface WindowInfoRepository {
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowMetrics> getCurrentWindowMetrics();
+ method public default static androidx.window.layout.WindowInfoRepository getOrCreate(android.app.Activity);
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> getWindowLayoutInfo();
+ property public abstract kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowMetrics> currentWindowMetrics;
+ property public abstract kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo;
+ field public static final androidx.window.layout.WindowInfoRepository.Companion Companion;
+ }
+
+ public static final class WindowInfoRepository.Companion {
+ method public androidx.window.layout.WindowInfoRepository getOrCreate(android.app.Activity);
+ }
+
+ public final class WindowLayoutInfo {
+ method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+ property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+ }
+
+ public static final class WindowLayoutInfo.Builder {
+ ctor public WindowLayoutInfo.Builder();
+ method public androidx.window.layout.WindowLayoutInfo build();
+ method public androidx.window.layout.WindowLayoutInfo.Builder setDisplayFeatures(java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+ }
+
+ public final class WindowMetrics {
+ ctor public WindowMetrics(android.graphics.Rect bounds);
+ method public android.graphics.Rect getBounds();
+ property public final android.graphics.Rect bounds;
+ }
+
+ public interface WindowMetricsCalculator {
+ method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+ method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+ method public default static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+ }
+
+ public static final class WindowMetricsCalculator.Companion {
+ method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ }
+
+}
+
diff --git a/work/workmanager/api/res-2.6.0-beta01.txt b/window/window/api/res-1.0.0-beta01.txt
similarity index 100%
copy from work/workmanager/api/res-2.6.0-beta01.txt
copy to window/window/api/res-1.0.0-beta01.txt
diff --git a/window/window/api/restricted_1.0.0-beta01.txt b/window/window/api/restricted_1.0.0-beta01.txt
new file mode 100644
index 0000000..082d83a
--- /dev/null
+++ b/window/window/api/restricted_1.0.0-beta01.txt
@@ -0,0 +1,97 @@
+// Signature format: 4.0
+package androidx.window.layout {
+
+ public interface DisplayFeature {
+ method public android.graphics.Rect getBounds();
+ property public abstract android.graphics.Rect bounds;
+ }
+
+ public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+ method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+ method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+ method public androidx.window.layout.FoldingFeature.State getState();
+ method public boolean isSeparating();
+ property public abstract boolean isSeparating;
+ property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+ property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+ property public abstract androidx.window.layout.FoldingFeature.State state;
+ }
+
+ public static final class FoldingFeature.OcclusionType {
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+ }
+
+ public static final class FoldingFeature.OcclusionType.Companion {
+ }
+
+ public static final class FoldingFeature.Orientation {
+ field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+ field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+ }
+
+ public static final class FoldingFeature.Orientation.Companion {
+ }
+
+ public static final class FoldingFeature.State {
+ field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.State FLAT;
+ field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+ }
+
+ public static final class FoldingFeature.State.Companion {
+ }
+
+ public interface WindowInfoRepository {
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowMetrics> getCurrentWindowMetrics();
+ method public default static androidx.window.layout.WindowInfoRepository getOrCreate(android.app.Activity);
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> getWindowLayoutInfo();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public default static void overrideDecorator(androidx.window.layout.WindowInfoRepositoryDecorator overridingDecorator);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public default static void reset();
+ property public abstract kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowMetrics> currentWindowMetrics;
+ property public abstract kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo;
+ field public static final androidx.window.layout.WindowInfoRepository.Companion Companion;
+ }
+
+ public static final class WindowInfoRepository.Companion {
+ method public androidx.window.layout.WindowInfoRepository getOrCreate(android.app.Activity);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void overrideDecorator(androidx.window.layout.WindowInfoRepositoryDecorator overridingDecorator);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void reset();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public interface WindowInfoRepositoryDecorator {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.window.layout.WindowInfoRepository decorate(androidx.window.layout.WindowInfoRepository repository);
+ }
+
+ public final class WindowLayoutInfo {
+ method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+ property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+ }
+
+ public static final class WindowLayoutInfo.Builder {
+ ctor public WindowLayoutInfo.Builder();
+ method public androidx.window.layout.WindowLayoutInfo build();
+ method public androidx.window.layout.WindowLayoutInfo.Builder setDisplayFeatures(java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+ }
+
+ public final class WindowMetrics {
+ ctor public WindowMetrics(android.graphics.Rect bounds);
+ method public android.graphics.Rect getBounds();
+ property public final android.graphics.Rect bounds;
+ }
+
+ public interface WindowMetricsCalculator {
+ method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+ method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+ method public default static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+ }
+
+ public static final class WindowMetricsCalculator.Companion {
+ method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ }
+
+}
+
diff --git a/window/window/build.gradle b/window/window/build.gradle
index e263c33..77bdc9b 100644
--- a/window/window/build.gradle
+++ b/window/window/build.gradle
@@ -50,7 +50,6 @@
implementation("androidx.collection:collection:1.1.0")
implementation("androidx.core:core:1.3.2")
- compileOnly(project(":window:window-extensions"))
compileOnly(project(":window:window-sidecar"))
testImplementation(libs.testCore)
@@ -61,7 +60,6 @@
testImplementation(libs.mockitoCore)
testImplementation(libs.mockitoKotlin)
testImplementation(libs.kotlinCoroutinesTest)
- testImplementation(compileOnly(project(":window:window-extensions")))
testImplementation(compileOnly(project(":window:window-sidecar")))
androidTestImplementation(libs.testCore)
diff --git a/window/window/src/androidTest/java/androidx/window/layout/ExtensionAdapterTest.kt b/window/window/src/androidTest/java/androidx/window/layout/ExtensionAdapterTest.kt
deleted file mode 100644
index b27753d..0000000
--- a/window/window/src/androidTest/java/androidx/window/layout/ExtensionAdapterTest.kt
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.window.layout
-
-import android.app.Activity
-import android.graphics.Rect
-import androidx.window.core.Bounds
-import androidx.window.extensions.ExtensionDisplayFeature
-import androidx.window.extensions.ExtensionFoldingFeature
-import androidx.window.extensions.ExtensionFoldingFeature.STATE_FLAT
-import androidx.window.extensions.ExtensionFoldingFeature.TYPE_FOLD
-import androidx.window.extensions.ExtensionFoldingFeature.TYPE_HINGE
-import androidx.window.extensions.ExtensionWindowLayoutInfo
-import androidx.window.layout.FoldingFeature.State.Companion.FLAT
-import androidx.window.layout.HardwareFoldingFeature.Type.Companion.FOLD
-import com.nhaarman.mockitokotlin2.mock
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-
-/**
- * Tests for [ExtensionAdapter] checking that the data is translated correctly from
- * window.extensions to window.window. Implements [TranslatorTestInterface] to ensure same
- * requirements are met as [SidecarAdapter]
- *
- * Run: ./gradlew window:window:connectedAndroidTest
- */
-public class ExtensionAdapterTest : TranslatorTestInterface {
-
- private lateinit var windowBoundsCalculator: TestWindowMetricsCalculator
-
- @Before
- public fun setUp() {
- windowBoundsCalculator = TestWindowMetricsCalculator()
- windowBoundsCalculator.setCurrentBounds(WINDOW_BOUNDS)
- }
-
- @Test
- override fun testTranslate_validFeature() {
- val mockActivity = mock<Activity>()
- val bounds = Rect(WINDOW_BOUNDS.left, 0, WINDOW_BOUNDS.right, 0)
- val foldFeature =
- ExtensionFoldingFeature(
- bounds,
- TYPE_FOLD,
- STATE_FLAT
- )
- val extensionDisplayFeatures = listOf(foldFeature)
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- extensionDisplayFeatures
- )
- val expectedFeatures = listOf(
- HardwareFoldingFeature(Bounds(foldFeature.bounds), FOLD, FLAT)
- )
- val expected = WindowLayoutInfo(expectedFeatures)
- val adapter = ExtensionAdapter(windowBoundsCalculator)
- val actual = adapter.translate(mockActivity, windowLayoutInfo)
- assertEquals(expected, actual)
- }
-
- @Test
- override fun testTranslateWindowLayoutInfo_filterRemovesHingeFeatureNotSpanningFullDimension() {
- val fullWidthBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top,
- WINDOW_BOUNDS.right / 2, 2
- )
- val fullHeightBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top, 2,
- WINDOW_BOUNDS.bottom / 2
- )
- val extensionDisplayFeatures = listOf(
- ExtensionFoldingFeature(
- fullWidthBounds,
- TYPE_HINGE,
- STATE_FLAT
- ),
- ExtensionFoldingFeature(
- fullHeightBounds,
- TYPE_HINGE,
- STATE_FLAT
- )
- )
- val extensionCallbackAdapter = ExtensionAdapter(windowBoundsCalculator)
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- extensionDisplayFeatures
- )
- val mockActivity = mock<Activity>()
- val actual = extensionCallbackAdapter.translate(
- mockActivity,
- windowLayoutInfo
- )
- assertTrue(
- "Remove hinge feature not spanning full dimension",
- actual.displayFeatures.isEmpty()
- )
- }
-
- @Test
- override fun testTranslateWindowLayoutInfo_filterRemovesFoldFeatureNotSpanningFullDimension() {
- val fullWidthBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top,
- WINDOW_BOUNDS.right / 2, WINDOW_BOUNDS.top
- )
- val fullHeightBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top, WINDOW_BOUNDS.left,
- WINDOW_BOUNDS.bottom / 2
- )
- val extensionDisplayFeatures = listOf(
- ExtensionFoldingFeature(
- fullWidthBounds,
- TYPE_HINGE,
- STATE_FLAT
- ),
- ExtensionFoldingFeature(
- fullHeightBounds,
- TYPE_HINGE,
- STATE_FLAT
- )
- )
- val adapter = ExtensionAdapter(windowBoundsCalculator)
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- extensionDisplayFeatures
- )
- val mockActivity = mock<Activity>()
- val actual = adapter.translate(mockActivity, windowLayoutInfo)
- assertTrue(
- "Remove fold feature not spanning full dimension",
- actual.displayFeatures.isEmpty()
- )
- }
-
- @Test
- override fun testTranslateWindowLayoutInfo_filterRemovesUnknownFeature() {
- val bounds = Rect(WINDOW_BOUNDS.left, 0, WINDOW_BOUNDS.right, 0)
- val foldFeature: ExtensionDisplayFeature =
- ExtensionFoldingFeature(
- bounds,
- 0 /* unknown */, STATE_FLAT
- )
- val extensionDisplayFeatures = listOf(foldFeature)
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- extensionDisplayFeatures
- )
- val mockActivity = mock<Activity>()
- val adapter = ExtensionAdapter(windowBoundsCalculator)
- val actual = adapter.translate(mockActivity, windowLayoutInfo)
- assertTrue(
- "Remove fold feature not spanning full dimension",
- actual.displayFeatures.isEmpty()
- )
- }
-
- private companion object {
- private val WINDOW_BOUNDS = Rect(0, 0, 50, 100)
- }
-}
diff --git a/window/window/src/androidTest/java/androidx/window/layout/ExtensionCompatDeviceTest.kt b/window/window/src/androidTest/java/androidx/window/layout/ExtensionCompatDeviceTest.kt
deleted file mode 100644
index 4b0611f..0000000
--- a/window/window/src/androidTest/java/androidx/window/layout/ExtensionCompatDeviceTest.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.window.layout
-
-import android.content.Context
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.window.WindowTestBase
-import androidx.window.core.Version
-import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
-import com.nhaarman.mockitokotlin2.any
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.verify
-import org.junit.Assert.assertNotNull
-import org.junit.Assume
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Tests for [ExtensionCompat] implementation of [ExtensionInterfaceCompat] that are
- * executed with Extension implementation provided on the device (and only if one is available).
- */
-@LargeTest
-@RunWith(AndroidJUnit4::class)
-public class ExtensionCompatDeviceTest : WindowTestBase(), CompatDeviceTestInterface {
-
- private lateinit var extensionCompat: ExtensionCompat
-
- @Before
- public fun setUp() {
- assumeExtensionV1_0()
- extensionCompat = ExtensionCompat(ApplicationProvider.getApplicationContext() as Context)
- }
-
- @Test
- override fun testWindowLayoutCallback() {
- activityTestRule.scenario.onActivity { activity ->
- val windowToken = getActivityWindowToken(activity)
- assertNotNull(windowToken)
- val callbackInterface = mock<ExtensionCallbackInterface>()
- extensionCompat.setExtensionCallback(callbackInterface)
- extensionCompat.onWindowLayoutChangeListenerAdded(activity)
- verify(callbackInterface).onWindowLayoutChanged(any(), any())
- }
- }
-
- private fun assumeExtensionV1_0() {
- val extensionVersion = ExtensionCompat.extensionVersion
- Assume.assumeTrue(
- extensionVersion != null && Version.VERSION_1_0 <= extensionVersion
- )
- }
-}
diff --git a/window/window/src/androidTest/java/androidx/window/layout/ExtensionCompatTest.kt b/window/window/src/androidTest/java/androidx/window/layout/ExtensionCompatTest.kt
deleted file mode 100644
index 5bc656f..0000000
--- a/window/window/src/androidTest/java/androidx/window/layout/ExtensionCompatTest.kt
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.window.layout
-
-import android.app.Activity
-import android.graphics.Rect
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.window.WindowTestBase
-import androidx.window.extensions.ExtensionDisplayFeature
-import androidx.window.extensions.ExtensionFoldingFeature
-import androidx.window.extensions.ExtensionInterface
-import androidx.window.extensions.ExtensionInterface.ExtensionCallback
-import androidx.window.extensions.ExtensionWindowLayoutInfo
-import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
-import androidx.window.layout.TestFoldingFeatureUtil.invalidFoldBounds
-import androidx.window.layout.TestFoldingFeatureUtil.validFoldBound
-import com.nhaarman.mockitokotlin2.any
-import com.nhaarman.mockitokotlin2.argThat
-import com.nhaarman.mockitokotlin2.argumentCaptor
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.verify
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Tests for [ExtensionCompat] implementation of [ExtensionInterfaceCompat]. This
- * class uses a mocked Extension to verify the behavior of the implementation on any hardware.
- *
- * Because this class extends [ExtensionCompatDeviceTest], it will also run the mocked
- * versions of methods defined in [CompatDeviceTestInterface].
- */
-@LargeTest
-@RunWith(AndroidJUnit4::class)
-public class ExtensionCompatTest : WindowTestBase(), CompatTestInterface {
-
- private lateinit var extensionCompat: ExtensionCompat
- private lateinit var activity: Activity
- private lateinit var extensionAdapter: ExtensionAdapter
-
- @Before
- public fun setUp() {
- val windowMetricsCalculator = TestWindowMetricsCalculator()
- windowMetricsCalculator.setCurrentBounds(WINDOW_BOUNDS)
- extensionAdapter = ExtensionAdapter(windowMetricsCalculator)
- extensionCompat = ExtensionCompat(mock(), extensionAdapter)
- activity = mock()
- }
-
- @Test
- override fun testGetWindowLayout() {
- val fakeExtensionImp = FakeExtensionImp()
- val compat = ExtensionCompat(fakeExtensionImp, extensionAdapter)
- val mockCallback = mock<ExtensionCallbackInterface>()
- compat.setExtensionCallback(mockCallback)
- compat.onWindowLayoutChangeListenerAdded(mock())
- fakeExtensionImp.triggerValidSignal()
- verify(mockCallback).onWindowLayoutChanged(
- any(),
- argThat { windowLayoutInfo: WindowLayoutInfo ->
- windowLayoutInfo.displayFeatures.isNotEmpty()
- }
- )
- }
-
- @Test
- override fun testSetExtensionCallback() {
- val extensionCallbackCaptor = argumentCaptor<ExtensionCallback>()
-
- // Verify that the extension got the callback set
- val callback = mock<ExtensionCallbackInterface>()
- extensionCompat.setExtensionCallback(callback)
- verify(extensionCompat.windowExtension!!).setExtensionCallback(
- extensionCallbackCaptor.capture()
- )
-
- // Verify that the callback set for extension propagates the window layout callback when
- // a listener has been registered.
- extensionCompat.onWindowLayoutChangeListenerAdded(activity)
- val bounds = Rect(WINDOW_BOUNDS.left, WINDOW_BOUNDS.top, WINDOW_BOUNDS.width(), 1)
- val extensionDisplayFeature: ExtensionDisplayFeature =
- ExtensionFoldingFeature(
- bounds,
- ExtensionFoldingFeature.TYPE_HINGE,
- ExtensionFoldingFeature.STATE_HALF_OPENED
- )
- val displayFeatures = listOf(extensionDisplayFeature)
- val extensionWindowLayoutInfo =
- ExtensionWindowLayoutInfo(
- displayFeatures
- )
- extensionCallbackCaptor.firstValue.onWindowLayoutChanged(
- activity,
- extensionWindowLayoutInfo
- )
- val windowLayoutInfoCaptor = argumentCaptor<WindowLayoutInfo>()
- verify(callback)
- .onWindowLayoutChanged(eq(activity), windowLayoutInfoCaptor.capture())
- val capturedLayout = windowLayoutInfoCaptor.firstValue
- assertEquals(1, capturedLayout.displayFeatures.size.toLong())
- val capturedDisplayFeature = capturedLayout.displayFeatures[0]
- val foldingFeature = capturedDisplayFeature as FoldingFeature
- assertNotNull(foldingFeature)
- assertEquals(bounds, capturedDisplayFeature.bounds)
- }
-
- override fun testExtensionCallback_filterRemovesInvalidValues() {
- val fakeExtensionImp = FakeExtensionImp()
- val compat = ExtensionCompat(fakeExtensionImp, extensionAdapter)
- val mockCallback = mock<ExtensionCallbackInterface>()
- compat.setExtensionCallback(mockCallback)
- compat.onWindowLayoutChangeListenerAdded(mock())
- fakeExtensionImp.triggerMalformedSignal()
- verify(mockCallback).onWindowLayoutChanged(
- any(),
- argThat { windowLayoutInfo: WindowLayoutInfo ->
- windowLayoutInfo.displayFeatures.isEmpty()
- }
- )
- }
-
- @Test
- override fun testOnWindowLayoutChangeListenerAdded() {
- extensionCompat.onWindowLayoutChangeListenerAdded(activity)
- verify(extensionCompat.windowExtension!!).onWindowLayoutChangeListenerAdded(
- eq(activity)
- )
- }
-
- @Test
- override fun testOnWindowLayoutChangeListenerRemoved() {
- extensionCompat.onWindowLayoutChangeListenerRemoved(activity)
- verify(extensionCompat.windowExtension!!)
- .onWindowLayoutChangeListenerRemoved(eq(activity))
- }
-
- @Test
- public fun testValidateExtensionInterface() {
- assertTrue(extensionCompat.validateExtensionInterface())
- }
-
- private class FakeExtensionImp : ExtensionInterface {
- private var callback: ExtensionCallback
- private val activities = mutableListOf<Activity>()
- override fun setExtensionCallback(callback: ExtensionCallback) {
- this.callback = callback
- }
-
- override fun onWindowLayoutChangeListenerAdded(activity: Activity) {
- activities.add(activity)
- }
-
- override fun onWindowLayoutChangeListenerRemoved(activity: Activity) {
- activities.remove(activity)
- }
-
- fun triggerMalformedSignal() {
- triggerSignal(malformedWindowLayoutInfo())
- }
-
- fun triggerValidSignal() {
- triggerSignal(validWindowLayoutInfo())
- }
-
- fun triggerSignal(info: ExtensionWindowLayoutInfo?) {
- activities.forEach { activity ->
- callback.onWindowLayoutChanged(activity, info!!)
- }
- }
-
- private fun malformedWindowLayoutInfo(): ExtensionWindowLayoutInfo {
- val malformedFeatures = mutableListOf<ExtensionDisplayFeature>()
- for (malformedBound in invalidFoldBounds(WINDOW_BOUNDS)) {
- malformedFeatures.add(
- ExtensionFoldingFeature(
- malformedBound,
- ExtensionFoldingFeature.TYPE_FOLD,
- ExtensionFoldingFeature.STATE_FLAT
- )
- )
- }
- for (malformedBound in invalidFoldBounds(WINDOW_BOUNDS)) {
- malformedFeatures.add(
- ExtensionFoldingFeature(
- malformedBound,
- ExtensionFoldingFeature.TYPE_HINGE,
- ExtensionFoldingFeature.STATE_FLAT
- )
- )
- }
- return ExtensionWindowLayoutInfo(
- malformedFeatures
- )
- }
-
- private fun validWindowLayoutInfo(): ExtensionWindowLayoutInfo {
- val validFeatures = listOf(
- ExtensionFoldingFeature(
- validFoldBound(WINDOW_BOUNDS),
- ExtensionFoldingFeature.TYPE_FOLD,
- ExtensionFoldingFeature.STATE_FLAT
- )
- )
- return ExtensionWindowLayoutInfo(
- validFeatures
- )
- }
-
- init {
- callback = ExtensionCallback { _, _ -> }
- }
- }
-
- private companion object {
- private val WINDOW_BOUNDS = Rect(0, 0, 50, 100)
- }
-}
diff --git a/window/window/src/androidTest/java/androidx/window/layout/ExtensionTest.kt b/window/window/src/androidTest/java/androidx/window/layout/ExtensionTest.kt
index 7cc3ae1..77efd39 100644
--- a/window/window/src/androidTest/java/androidx/window/layout/ExtensionTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/layout/ExtensionTest.kt
@@ -31,7 +31,7 @@
import androidx.window.TestConfigChangeHandlingActivity
import androidx.window.WindowTestBase
import androidx.window.core.Version
-import androidx.window.extensions.ExtensionFoldingFeature
+import androidx.window.extensions.layout.FoldingFeature
import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.argThat
@@ -76,7 +76,7 @@
val type = 1
val state = 1
val displayFeature =
- ExtensionFoldingFeature(
+ FoldingFeature(
rect,
type,
state
@@ -198,16 +198,11 @@
if (version != null) {
assertEquals(Version.VERSION_0_1, version)
}
- version = ExtensionCompat.extensionVersion
- if (version != null) {
- assertEquals(Version.VERSION_1_0, version)
- }
}
private fun assumeExtensionV10_V01() {
Assume.assumeTrue(
- Version.VERSION_1_0 == ExtensionCompat.extensionVersion ||
- Version.VERSION_0_1 == SidecarCompat.sidecarVersion
+ Version.VERSION_0_1 == SidecarCompat.sidecarVersion
)
}
diff --git a/window/window/src/androidTest/java/androidx/window/layout/ExtensionTranslatingCallbackTest.kt b/window/window/src/androidTest/java/androidx/window/layout/ExtensionTranslatingCallbackTest.kt
deleted file mode 100644
index 6639942..0000000
--- a/window/window/src/androidTest/java/androidx/window/layout/ExtensionTranslatingCallbackTest.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.window.layout
-
-import android.app.Activity
-import android.graphics.Rect
-import androidx.window.core.Bounds
-import androidx.window.extensions.ExtensionDisplayFeature
-import androidx.window.extensions.ExtensionFoldingFeature
-import androidx.window.extensions.ExtensionFoldingFeature.STATE_FLAT
-import androidx.window.extensions.ExtensionFoldingFeature.TYPE_HINGE
-import androidx.window.extensions.ExtensionWindowLayoutInfo
-import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
-import androidx.window.layout.FoldingFeature.State.Companion.FLAT
-import androidx.window.layout.HardwareFoldingFeature.Type.Companion.FOLD
-import com.nhaarman.mockitokotlin2.argThat
-import com.nhaarman.mockitokotlin2.argumentCaptor
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.verify
-import org.junit.Assert.assertEquals
-import org.junit.Before
-import org.junit.Test
-
-public class ExtensionTranslatingCallbackTest {
-
- private lateinit var extensionAdapter: ExtensionAdapter
-
- @Before
- public fun setUp() {
- val windowMetricsCalculator = TestWindowMetricsCalculator()
- windowMetricsCalculator.setCurrentBounds(WINDOW_BOUNDS)
- extensionAdapter = ExtensionAdapter(windowMetricsCalculator)
- }
-
- @Test
- public fun testOnWindowLayoutChange_validFeature() {
- val mockActivity = mock<Activity>()
- val bounds = Rect(WINDOW_BOUNDS.left, 0, WINDOW_BOUNDS.right, 0)
- val foldFeature: ExtensionDisplayFeature =
- ExtensionFoldingFeature(
- bounds,
- ExtensionFoldingFeature.TYPE_FOLD,
- STATE_FLAT
- )
- val extensionDisplayFeatures = listOf(foldFeature)
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- extensionDisplayFeatures
- )
- val expectedFeatures = listOf(
- HardwareFoldingFeature(Bounds(foldFeature.bounds), FOLD, FLAT)
- )
- val expected = WindowLayoutInfo(expectedFeatures)
- val mockCallback = mock<ExtensionCallbackInterface>()
- val extensionTranslatingCallback =
- ExtensionTranslatingCallback(mockCallback, extensionAdapter)
- extensionTranslatingCallback.onWindowLayoutChanged(mockActivity, windowLayoutInfo)
- val captor = argumentCaptor<WindowLayoutInfo>()
- verify(mockCallback)
- .onWindowLayoutChanged(eq(mockActivity), captor.capture())
- assertEquals(expected, captor.firstValue)
- }
-
- @Test
- public fun testOnWindowLayoutChange_filterRemovesHingeFeatureNotSpanningFullDimension() {
- val fullWidthBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top,
- WINDOW_BOUNDS.right / 2, 2
- )
- val fullHeightBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top, 2,
- WINDOW_BOUNDS.bottom / 2
- )
- val extensionDisplayFeatures = listOf(
- ExtensionFoldingFeature(
- fullWidthBounds,
- TYPE_HINGE,
- STATE_FLAT
- ),
- ExtensionFoldingFeature(
- fullHeightBounds,
- TYPE_HINGE,
- STATE_FLAT
- )
- )
- val mockCallback = mock<ExtensionCallbackInterface>()
- val extensionTranslatingCallback =
- ExtensionTranslatingCallback(mockCallback, extensionAdapter)
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- extensionDisplayFeatures
- )
- val mockActivity = mock<Activity>()
- extensionTranslatingCallback.onWindowLayoutChanged(mockActivity, windowLayoutInfo)
- verify(mockCallback).onWindowLayoutChanged(
- eq(mockActivity),
- argThat { layoutInfo -> layoutInfo.displayFeatures.isEmpty() }
- )
- }
-
- @Test
- public fun testOnWindowLayoutChange_filterRemovesFoldFeatureNotSpanningFullDimension() {
- val fullWidthBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top,
- WINDOW_BOUNDS.right / 2, WINDOW_BOUNDS.top
- )
- val fullHeightBounds = Rect(
- WINDOW_BOUNDS.left, WINDOW_BOUNDS.top, WINDOW_BOUNDS.left,
- WINDOW_BOUNDS.bottom / 2
- )
- val extensionDisplayFeatures = listOf(
- ExtensionFoldingFeature(
- fullWidthBounds,
- TYPE_HINGE, STATE_FLAT
- ),
- ExtensionFoldingFeature(
- fullHeightBounds,
- TYPE_HINGE, STATE_FLAT
- )
- )
- val mockCallback = mock<ExtensionCallbackInterface>()
- val extensionTranslatingCallback =
- ExtensionTranslatingCallback(mockCallback, extensionAdapter)
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- extensionDisplayFeatures
- )
- val mockActivity = mock<Activity>()
- extensionTranslatingCallback.onWindowLayoutChanged(mockActivity, windowLayoutInfo)
- verify(mockCallback).onWindowLayoutChanged(
- eq(mockActivity),
- argThat { layoutInfo -> layoutInfo.displayFeatures.isEmpty() }
- )
- }
-
- internal companion object {
- private val WINDOW_BOUNDS = Rect(0, 0, 50, 100)
- }
-}
diff --git a/window/window/src/androidTest/java/androidx/window/layout/ExtensionWindowBackendTest.kt b/window/window/src/androidTest/java/androidx/window/layout/ExtensionWindowBackendTest.kt
index 06d6fd7..52f2bfb 100644
--- a/window/window/src/androidTest/java/androidx/window/layout/ExtensionWindowBackendTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/layout/ExtensionWindowBackendTest.kt
@@ -61,17 +61,6 @@
}
@Test
- public fun testInitAndVerifyExtension() {
- val extensionVersion = ExtensionCompat.extensionVersion
- assumeTrue(extensionVersion != null)
- assertTrue(ExtensionWindowBackend.isExtensionVersionSupported(extensionVersion))
- val extension = ExtensionWindowBackend.initAndVerifyExtension(context)
- assertNotNull(extension)
- assertTrue(extension is ExtensionCompat)
- assertTrue(extension!!.validateExtensionInterface())
- }
-
- @Test
public fun testInitAndVerifySidecar() {
val sidecarVersion = SidecarCompat.sidecarVersion
assumeTrue(sidecarVersion != null)
diff --git a/window/window/src/main/java/androidx/window/layout/ExtensionAdapter.kt b/window/window/src/main/java/androidx/window/layout/ExtensionAdapter.kt
deleted file mode 100644
index a7c6e53..0000000
--- a/window/window/src/main/java/androidx/window/layout/ExtensionAdapter.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.window.layout
-
-import android.app.Activity
-import android.graphics.Rect
-import android.util.Log
-import androidx.window.core.Bounds
-import androidx.window.extensions.ExtensionDisplayFeature
-import androidx.window.extensions.ExtensionFoldingFeature
-import androidx.window.extensions.ExtensionWindowLayoutInfo
-
-/**
- * A class for translating Extension data classes
- */
-internal class ExtensionAdapter(private val windowMetricsCalculator: WindowMetricsCalculator) {
- /**
- * Perform the translation from [ExtensionWindowLayoutInfo] to [WindowLayoutInfo].
- * Translates a valid [ExtensionDisplayFeature] into a valid [DisplayFeature]. If
- * a feature is not valid it is removed
- *
- * @param activity An [android.app.Activity].
- * @param layoutInfo The source [ExtensionWindowLayoutInfo] to be converted
- * @return [WindowLayoutInfo] containing the valid [DisplayFeature]
- */
- fun translate(
- activity: Activity,
- layoutInfo: ExtensionWindowLayoutInfo
- ): WindowLayoutInfo {
- val featureList = layoutInfo.displayFeatures.mapNotNull { translate(activity, it) }
- return WindowLayoutInfo(featureList)
- }
-
- fun translate(activity: Activity, displayFeature: ExtensionDisplayFeature): DisplayFeature? {
- if (displayFeature !is ExtensionFoldingFeature) {
- return null
- }
- val windowMetrics = windowMetricsCalculator.computeCurrentWindowMetrics(activity)
- return translateFoldFeature(windowMetrics.bounds, displayFeature)
- }
-
- companion object {
- private const val TAG = "ExtensionAdapter"
- internal fun translateFoldFeature(
- windowBounds: Rect,
- feature: ExtensionFoldingFeature
- ): DisplayFeature? {
- if (!isValid(windowBounds, feature)) {
- return null
- }
- val type = when (feature.type) {
- ExtensionFoldingFeature.TYPE_FOLD -> HardwareFoldingFeature.Type.FOLD
- ExtensionFoldingFeature.TYPE_HINGE -> HardwareFoldingFeature.Type.HINGE
- else -> {
- if (ExtensionCompat.DEBUG) {
- Log.d(TAG, "Unknown feature type: ${feature.type}, skipping feature.")
- }
- return null
- }
- }
- val state = when (feature.state) {
- ExtensionFoldingFeature.STATE_FLAT -> FoldingFeature.State.FLAT
- ExtensionFoldingFeature.STATE_HALF_OPENED -> FoldingFeature.State.HALF_OPENED
- else -> {
- if (ExtensionCompat.DEBUG) {
- Log.d(TAG, "Unknown feature state: ${feature.state}, skipping feature.")
- }
- return null
- }
- }
- return HardwareFoldingFeature(Bounds(feature.bounds), type, state)
- }
-
- private fun isValid(windowBounds: Rect, feature: ExtensionFoldingFeature): Boolean {
- if (feature.bounds.width() == 0 && feature.bounds.height() == 0) {
- return false
- }
- if (feature.type == ExtensionFoldingFeature.TYPE_FOLD && !feature.bounds.isEmpty) {
- return false
- }
- return if (feature.type != ExtensionFoldingFeature.TYPE_FOLD &&
- feature.type != ExtensionFoldingFeature.TYPE_HINGE
- ) {
- false
- } else hasMatchingDimension(
- feature.bounds,
- windowBounds
- )
- }
-
- private fun hasMatchingDimension(lhs: Rect, rhs: Rect): Boolean {
- val matchesWidth = lhs.left == rhs.left && lhs.right == rhs.right
- val matchesHeight = lhs.top == rhs.top && lhs.bottom == rhs.bottom
- return matchesWidth || matchesHeight
- }
- }
-}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/layout/ExtensionCompat.kt b/window/window/src/main/java/androidx/window/layout/ExtensionCompat.kt
deleted file mode 100644
index 8acfb4b..0000000
--- a/window/window/src/main/java/androidx/window/layout/ExtensionCompat.kt
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.window.layout
-
-import android.app.Activity
-import android.content.Context
-import android.graphics.Rect
-import android.text.TextUtils
-import android.util.Log
-import androidx.annotation.VisibleForTesting
-import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
-import androidx.window.core.Version
-import androidx.window.core.Version.Companion.parse
-import androidx.window.extensions.ExtensionFoldingFeature
-import androidx.window.extensions.ExtensionInterface
-import androidx.window.extensions.ExtensionInterface.ExtensionCallback
-import androidx.window.extensions.ExtensionProvider
-import androidx.window.extensions.ExtensionWindowLayoutInfo
-import java.util.ArrayList
-
-/** Compatibility wrapper for extension versions v1.0+. */
-internal class ExtensionCompat @VisibleForTesting constructor(
- @field:VisibleForTesting val windowExtension: ExtensionInterface?,
- private val adapter: ExtensionAdapter
-) : ExtensionInterfaceCompat {
- constructor(context: Context) : this(
- ExtensionProvider.getExtensionImpl(context),
- ExtensionAdapter(WindowMetricsCalculatorCompat)
- ) {
- requireNotNull(windowExtension) { "Extension provider returned null" }
- }
-
- override fun setExtensionCallback(extensionCallback: ExtensionCallbackInterface) {
- val translatingCallback = ExtensionTranslatingCallback(extensionCallback, adapter)
- windowExtension?.setExtensionCallback(translatingCallback)
- }
-
- override fun onWindowLayoutChangeListenerAdded(activity: Activity) {
- windowExtension?.onWindowLayoutChangeListenerAdded(activity)
- }
-
- override fun onWindowLayoutChangeListenerRemoved(activity: Activity) {
- windowExtension?.onWindowLayoutChangeListenerRemoved(activity)
- }
-
- /** Verifies that extension implementation corresponds to the interface of the version. */
- override fun validateExtensionInterface(): Boolean {
- return try {
- // extension.setExtensionCallback(ExtensionInterface.ExtensionCallback);
- val methodSetExtensionCallback = windowExtension?.javaClass?.getMethod(
- "setExtensionCallback", ExtensionCallback::class.java
- )
- val rSetExtensionCallback = methodSetExtensionCallback?.returnType
- if (rSetExtensionCallback != Void.TYPE) {
- throw NoSuchMethodException(
- "Illegal return type for 'setExtensionCallback': $rSetExtensionCallback"
- )
- }
-
- // extension.onWindowLayoutChangeListenerAdded(Activity);
- val methodRegisterWindowLayoutChangeListener = windowExtension?.javaClass
- ?.getMethod("onWindowLayoutChangeListenerAdded", Activity::class.java)
- val rtRegisterWindowLayoutChangeListener =
- methodRegisterWindowLayoutChangeListener?.returnType
- if (rtRegisterWindowLayoutChangeListener != Void.TYPE) {
- throw NoSuchMethodException(
- "Illegal return type for 'onWindowLayoutChangeListenerAdded': " +
- "$rtRegisterWindowLayoutChangeListener"
- )
- }
-
- // extension.onWindowLayoutChangeListenerRemoved(Activity);
- val methodUnregisterWindowLayoutChangeListener = windowExtension?.javaClass
- ?.getMethod("onWindowLayoutChangeListenerRemoved", Activity::class.java)
- val rtUnregisterWindowLayoutChangeListener =
- methodUnregisterWindowLayoutChangeListener?.returnType
- if (rtUnregisterWindowLayoutChangeListener != Void.TYPE) {
- throw NoSuchMethodException(
- "Illegal return type for 'onWindowLayoutChangeListenerRemoved': " +
- "$rtUnregisterWindowLayoutChangeListener"
- )
- }
-
- // {@link ExtensionFoldingFeature} constructor
- val displayFoldingFeature =
- ExtensionFoldingFeature(
- Rect(0, 0, 100, 0),
- ExtensionFoldingFeature.TYPE_FOLD,
- ExtensionFoldingFeature.STATE_FLAT
- )
-
- // displayFoldFeature.getBounds()
- @Suppress("UNUSED_VARIABLE") val tmpRect = displayFoldingFeature.bounds
-
- // displayFoldFeature.getState()
- @Suppress("UNUSED_VARIABLE") val tmpState = displayFoldingFeature.state
-
- // displayFoldFeature.getType()
- @Suppress("UNUSED_VARIABLE") val tmpType = displayFoldingFeature.type
-
- // ExtensionWindowLayoutInfo constructor
- val windowLayoutInfo =
- ExtensionWindowLayoutInfo(
- ArrayList()
- )
-
- // windowLayoutInfo.getDisplayFeatures()
- @Suppress("UNUSED_VARIABLE") val tmpDisplayFeatures = windowLayoutInfo.displayFeatures
- true
- } catch (t: Throwable) {
- if (DEBUG) {
- Log.e(
- TAG,
- "Extension implementation doesn't conform to interface version " +
- "$extensionVersion, error: $t"
- )
- }
- false
- }
- }
-
- companion object {
- const val DEBUG = false
- private const val TAG = "ExtensionVersionCompat"
- val extensionVersion: Version?
- get() = try {
- val vendorVersion = ExtensionProvider.getApiVersion()
- if (!TextUtils.isEmpty(vendorVersion)) parse(vendorVersion) else null
- } catch (e: NoClassDefFoundError) {
- if (DEBUG) {
- Log.d(TAG, "Extension version not found")
- }
- null
- } catch (e: UnsupportedOperationException) {
- if (DEBUG) {
- Log.d(TAG, "Stub Extension")
- }
- null
- }
- }
-}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/layout/ExtensionTranslatingCallback.kt b/window/window/src/main/java/androidx/window/layout/ExtensionTranslatingCallback.kt
deleted file mode 100644
index 17b32b7..0000000
--- a/window/window/src/main/java/androidx/window/layout/ExtensionTranslatingCallback.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.window.layout
-
-import android.app.Activity
-import androidx.window.extensions.ExtensionInterface.ExtensionCallback
-import androidx.window.extensions.ExtensionWindowLayoutInfo
-import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
-
-/**
- * A class to adapt from [ExtensionWindowLayoutInfo] to the local classes.
- */
-internal class ExtensionTranslatingCallback(
- private val callback: ExtensionCallbackInterface,
- private val adapter: ExtensionAdapter
-) : ExtensionCallback {
-
- override fun onWindowLayoutChanged(
- activity: Activity,
- newLayout: ExtensionWindowLayoutInfo
- ) {
- callback.onWindowLayoutChanged(activity, adapter.translate(activity, newLayout))
- }
-}
diff --git a/window/window/src/main/java/androidx/window/layout/ExtensionWindowBackend.kt b/window/window/src/main/java/androidx/window/layout/ExtensionWindowBackend.kt
index 2e3877c..44e54e7 100644
--- a/window/window/src/main/java/androidx/window/layout/ExtensionWindowBackend.kt
+++ b/window/window/src/main/java/androidx/window/layout/ExtensionWindowBackend.kt
@@ -24,7 +24,6 @@
import androidx.core.util.Consumer
import androidx.window.core.Version
import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
-import java.util.ArrayList
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.Executor
import java.util.concurrent.locks.ReentrantLock
@@ -59,7 +58,7 @@
globalLock.withLock {
val windowExtension = windowExtension
if (windowExtension == null) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.v(TAG, "Extension not loaded, skipping callback registration.")
}
callback.accept(WindowLayoutInfo(emptyList()))
@@ -95,7 +94,7 @@
override fun unregisterLayoutChangeCallback(callback: Consumer<WindowLayoutInfo>) {
synchronized(globalLock) {
if (windowExtension == null) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.v(TAG, "Extension not loaded, skipping callback un-registration.")
}
return
@@ -167,6 +166,8 @@
}
companion object {
+ const val DEBUG = false
+
@Volatile
private var globalInstance: ExtensionWindowBackend? = null
private val globalLock = ReentrantLock()
@@ -194,43 +195,25 @@
*/
fun initAndVerifyExtension(context: Context): ExtensionInterfaceCompat? {
var impl: ExtensionInterfaceCompat? = null
+ // Falling back to Sidecar
try {
- if (isExtensionVersionSupported(ExtensionCompat.extensionVersion)) {
- impl = ExtensionCompat(context)
+ if (isExtensionVersionSupported(SidecarCompat.sidecarVersion)) {
+ impl = SidecarCompat(context)
if (!impl.validateExtensionInterface()) {
- if (ExtensionCompat.DEBUG) {
- Log.d(TAG, "Loaded extension doesn't match the interface version")
+ if (DEBUG) {
+ Log.d(TAG, "Loaded Sidecar doesn't match the interface version")
}
impl = null
}
}
} catch (t: Throwable) {
- if (ExtensionCompat.DEBUG) {
- Log.d(TAG, "Failed to load extension: $t")
+ if (DEBUG) {
+ Log.d(TAG, "Failed to load sidecar: $t")
}
impl = null
}
if (impl == null) {
- // Falling back to Sidecar
- try {
- if (isExtensionVersionSupported(SidecarCompat.sidecarVersion)) {
- impl = SidecarCompat(context)
- if (!impl.validateExtensionInterface()) {
- if (ExtensionCompat.DEBUG) {
- Log.d(TAG, "Loaded Sidecar doesn't match the interface version")
- }
- impl = null
- }
- }
- } catch (t: Throwable) {
- if (ExtensionCompat.DEBUG) {
- Log.d(TAG, "Failed to load sidecar: $t")
- }
- impl = null
- }
- }
- if (impl == null) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(TAG, "No supported extension or sidecar found")
}
}
@@ -246,11 +229,7 @@
if (extensionVersion == null) {
return false
}
- return if (extensionVersion.major == 1) {
- // Disable androidx.window.extensions support in release builds of the library
- // until the extensions API is finalized.
- ExtensionCompat.DEBUG
- } else Version.CURRENT.major >= extensionVersion.major
+ return Version.VERSION_0_1 == extensionVersion
}
/**
diff --git a/window/window/src/main/java/androidx/window/layout/SidecarAdapter.kt b/window/window/src/main/java/androidx/window/layout/SidecarAdapter.kt
index 061fa99..827a481 100644
--- a/window/window/src/main/java/androidx/window/layout/SidecarAdapter.kt
+++ b/window/window/src/main/java/androidx/window/layout/SidecarAdapter.kt
@@ -21,6 +21,7 @@
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.window.core.Bounds
+import androidx.window.layout.ExtensionWindowBackend.Companion.DEBUG
import androidx.window.sidecar.SidecarDeviceState
import androidx.window.sidecar.SidecarDisplayFeature
import androidx.window.sidecar.SidecarWindowLayoutInfo
@@ -157,15 +158,15 @@
@Suppress("UNCHECKED_CAST")
return methodGetFeatures.invoke(info) as List<SidecarDisplayFeature>
} catch (e: NoSuchMethodException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: IllegalAccessException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: InvocationTargetException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
}
@@ -189,15 +190,15 @@
)
methodSetFeatures.invoke(info, displayFeatures)
} catch (e: NoSuchMethodException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: IllegalAccessException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: InvocationTargetException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
}
@@ -226,15 +227,15 @@
val methodGetPosture = SidecarDeviceState::class.java.getMethod("getPosture")
return methodGetPosture.invoke(sidecarDeviceState) as Int
} catch (e: NoSuchMethodException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: IllegalAccessException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: InvocationTargetException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
}
@@ -256,15 +257,15 @@
)
methodSetPosture.invoke(sidecarDeviceState, posture)
} catch (e: NoSuchMethodException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: IllegalAccessException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
} catch (e: InvocationTargetException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
e.printStackTrace()
}
}
@@ -281,7 +282,7 @@
): DisplayFeature? {
val bounds = feature.rect
if (bounds.width() == 0 && bounds.height() == 0) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(TAG, "Passed a display feature with empty rect, skipping: $feature")
}
return null
@@ -290,7 +291,7 @@
if (bounds.width() != 0 && bounds.height() != 0) {
// Bounds for fold types are expected to be zero-wide or zero-high.
// See DisplayFeature#getBounds().
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(
TAG,
"Passed a non-zero area display feature expected to be zero-area, " +
@@ -312,7 +313,7 @@
) {
// Bounds for fold and hinge types are expected to span the entire window space.
// See DisplayFeature#getBounds().
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(
TAG,
"Passed a display feature expected to span the entire window but " +
@@ -326,7 +327,7 @@
SidecarDisplayFeature.TYPE_FOLD -> HardwareFoldingFeature.Type.FOLD
SidecarDisplayFeature.TYPE_HINGE -> HardwareFoldingFeature.Type.HINGE
else -> {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(TAG, "Unknown feature type: ${feature.type}, skipping feature.")
}
return null
diff --git a/window/window/src/main/java/androidx/window/layout/SidecarCompat.kt b/window/window/src/main/java/androidx/window/layout/SidecarCompat.kt
index 4f60697..d961d90 100644
--- a/window/window/src/main/java/androidx/window/layout/SidecarCompat.kt
+++ b/window/window/src/main/java/androidx/window/layout/SidecarCompat.kt
@@ -32,6 +32,7 @@
import androidx.window.core.Version
import androidx.window.core.Version.Companion.parse
import androidx.window.layout.ExtensionInterfaceCompat.ExtensionCallbackInterface
+import androidx.window.layout.ExtensionWindowBackend.Companion.DEBUG
import androidx.window.sidecar.SidecarDeviceState
import androidx.window.sidecar.SidecarDisplayFeature
import androidx.window.sidecar.SidecarInterface
@@ -216,7 +217,7 @@
try {
tmpDeviceState.posture = SidecarDeviceState.POSTURE_OPENED
} catch (error: NoSuchFieldError) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.w(
TAG,
"Sidecar implementation doesn't conform to primary interface version, " +
@@ -257,7 +258,7 @@
val tmpDisplayFeatures = windowLayoutInfo.displayFeatures
// TODO(b/172620880): Workaround for Sidecar API implementation issue.
} catch (error: NoSuchFieldError) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.w(
TAG,
"Sidecar implementation doesn't conform to primary interface version, " +
@@ -283,7 +284,7 @@
}
true
} catch (t: Throwable) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.e(
TAG,
"Sidecar implementation doesn't conform to interface version " +
@@ -308,13 +309,13 @@
val activity = activityWeakReference.get()
val token = getActivityWindowToken(activity)
if (activity == null) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(TAG, "Unable to register activity since activity is missing")
}
return
}
if (token == null) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.w(TAG, "Unable to register activity since the window token is missing")
}
return
@@ -444,12 +445,12 @@
val vendorVersion = SidecarProvider.getApiVersion()
if (!TextUtils.isEmpty(vendorVersion)) parse(vendorVersion) else null
} catch (e: NoClassDefFoundError) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(TAG, "Sidecar version not found")
}
null
} catch (e: UnsupportedOperationException) {
- if (ExtensionCompat.DEBUG) {
+ if (DEBUG) {
Log.d(TAG, "Stub Sidecar")
}
null
diff --git a/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculatorCompat.kt b/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculatorCompat.kt
index 647e015..dd3a8a7 100644
--- a/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculatorCompat.kt
+++ b/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculatorCompat.kt
@@ -83,7 +83,7 @@
}
/** Computes the window bounds for [Build.VERSION_CODES.Q]. */
- @SuppressLint("BanUncheckedReflection")
+ @SuppressLint("BanUncheckedReflection", "BlockedPrivateApi")
@RequiresApi(VERSION_CODES.Q)
internal fun computeWindowBoundsQ(activity: Activity): Rect {
var bounds: Rect
@@ -122,7 +122,7 @@
* the window.
*
*/
- @SuppressLint("BanUncheckedReflection")
+ @SuppressLint("BanUncheckedReflection", "BlockedPrivateApi")
@RequiresApi(VERSION_CODES.P)
internal fun computeWindowBoundsP(activity: Activity): Rect {
val bounds = Rect()
diff --git a/work/integration-tests/testapp/build.gradle b/work/integration-tests/testapp/build.gradle
index 9ee4ee9..df18201 100644
--- a/work/integration-tests/testapp/build.gradle
+++ b/work/integration-tests/testapp/build.gradle
@@ -34,6 +34,8 @@
}
}
defaultConfig {
+ // This is necessary because "S" is a pre-release SDK.
+ targetSdkVersion "S"
javaCompileOptions {
annotationProcessorOptions {
arguments = [
diff --git a/work/integration-tests/testapp/src/main/AndroidManifest.xml b/work/integration-tests/testapp/src/main/AndroidManifest.xml
index 17f5540..c6d608d 100644
--- a/work/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/work/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -25,6 +25,7 @@
<activity android:name=".sherlockholmes.AnalyzeSherlockHolmesActivity" />
<activity
android:name="androidx.work.integration.testapp.MainActivity"
+ android:exported="true"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -32,8 +33,9 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name=".imageprocessing.ImageProcessingActivity" />
- <activity android:name=".RetryActivity">
+ <activity android:name=".imageprocessing.ImageProcessingActivity"
+ android:exported="false" />
+ <activity android:name=".RetryActivity" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
diff --git a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/ForegroundWorker.kt b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/ForegroundWorker.kt
index 1bc08db..3a561f2 100644
--- a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/ForegroundWorker.kt
+++ b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/ForegroundWorker.kt
@@ -23,6 +23,7 @@
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
+import androidx.core.os.BuildCompat
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.ForegroundInfo
@@ -41,18 +42,27 @@
override suspend fun doWork(): Result {
val notificationId = inputData.getInt(InputNotificationId, NotificationId)
val delayTime = inputData.getLong(InputDelayTime, Delay)
- // Run in the context of a Foreground service
- setForeground(getForegroundInfo(notificationId))
val range = 20
for (i in 1..range) {
delay(delayTime)
progress = workDataOf(Progress to i * (100 / range))
setProgress(progress)
- setForeground(getForegroundInfo(notificationId))
+ if (!BuildCompat.isAtLeastS()) {
+ // No need for notifications starting S.
+ notificationManager.notify(
+ notificationId,
+ getForegroundInfo(notificationId).notification
+ )
+ }
}
return Result.success()
}
+ override suspend fun getForegroundInfo(): ForegroundInfo {
+ val notificationId = inputData.getInt(InputNotificationId, NotificationId)
+ return getForegroundInfo(notificationId)
+ }
+
private fun getForegroundInfo(notificationId: Int): ForegroundInfo {
val percent = progress.getInt(Progress, 0)
val id = applicationContext.getString(R.string.channel_id)
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 f65cae7..78f913c 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
@@ -46,6 +46,7 @@
import androidx.work.ExistingWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
+import androidx.work.OutOfQuotaPolicy;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkContinuation;
import androidx.work.WorkInfo;
@@ -413,6 +414,7 @@
OneTimeWorkRequest request =
new OneTimeWorkRequest.Builder(ForegroundWorker.class)
.setInputData(inputData)
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.setConstraints(new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED).build()
).build();
diff --git a/work/workmanager-gcm/api/2.6.0-beta02.txt b/work/workmanager-gcm/api/2.6.0-beta02.txt
deleted file mode 100644
index e6f50d0..0000000
--- a/work/workmanager-gcm/api/2.6.0-beta02.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 4.0
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/work/workmanager-gcm/api/2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-gcm/api/2.6.0-beta01.txt
rename to work/workmanager-gcm/api/2.7.0-beta01.txt
diff --git a/work/workmanager-gcm/api/public_plus_experimental_2.6.0-beta01.txt b/work/workmanager-gcm/api/public_plus_experimental_2.6.0-beta01.txt
deleted file mode 100644
index e6f50d0..0000000
--- a/work/workmanager-gcm/api/public_plus_experimental_2.6.0-beta01.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 4.0
diff --git a/work/workmanager-gcm/api/public_plus_experimental_2.6.0-beta02.txt b/work/workmanager-gcm/api/public_plus_experimental_2.6.0-beta02.txt
deleted file mode 100644
index e6f50d0..0000000
--- a/work/workmanager-gcm/api/public_plus_experimental_2.6.0-beta02.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 4.0
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/work/workmanager-gcm/api/public_plus_experimental_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to work/workmanager-gcm/api/public_plus_experimental_2.7.0-beta01.txt
diff --git a/work/workmanager-gcm/api/res-2.6.0-beta01.txt b/work/workmanager-gcm/api/res-2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-gcm/api/res-2.6.0-beta01.txt
rename to work/workmanager-gcm/api/res-2.7.0-beta01.txt
diff --git a/work/workmanager-gcm/api/restricted_2.6.0-beta01.txt b/work/workmanager-gcm/api/restricted_2.6.0-beta01.txt
deleted file mode 100644
index e6f50d0..0000000
--- a/work/workmanager-gcm/api/restricted_2.6.0-beta01.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 4.0
diff --git a/work/workmanager-gcm/api/restricted_2.6.0-beta02.txt b/work/workmanager-gcm/api/restricted_2.6.0-beta02.txt
deleted file mode 100644
index e6f50d0..0000000
--- a/work/workmanager-gcm/api/restricted_2.6.0-beta02.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 4.0
diff --git a/work/workmanager-gcm/api/2.6.0-beta01.txt b/work/workmanager-gcm/api/restricted_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-gcm/api/2.6.0-beta01.txt
copy to work/workmanager-gcm/api/restricted_2.7.0-beta01.txt
diff --git a/work/workmanager-ktx/api/2.6.0-beta01.txt b/work/workmanager-ktx/api/2.6.0-beta01.txt
deleted file mode 100644
index 2c5f419..0000000
--- a/work/workmanager-ktx/api/2.6.0-beta01.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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> p);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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 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 final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
- }
-
- 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);
- }
-
-}
-
diff --git a/work/workmanager-ktx/api/2.6.0-beta02.txt b/work/workmanager-ktx/api/2.6.0-beta02.txt
deleted file mode 100644
index 2c5f419..0000000
--- a/work/workmanager-ktx/api/2.6.0-beta02.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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> p);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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 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 final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
- }
-
- 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);
- }
-
-}
-
diff --git a/work/workmanager-ktx/api/2.7.0-beta01.txt b/work/workmanager-ktx/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..8535d65
--- /dev/null
+++ b/work/workmanager-ktx/api/2.7.0-beta01.txt
@@ -0,0 +1,42 @@
+// 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> p);
+ method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo> p);
+ 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> p);
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+ 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 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 final class OperationKt {
+ method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
+ }
+
+ 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);
+ }
+
+}
+
diff --git a/work/workmanager-ktx/api/current.txt b/work/workmanager-ktx/api/current.txt
index 2c5f419..8535d65 100644
--- a/work/workmanager-ktx/api/current.txt
+++ b/work/workmanager-ktx/api/current.txt
@@ -5,6 +5,8 @@
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> p);
method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo> p);
+ 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> p);
method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
diff --git a/work/workmanager-ktx/api/public_plus_experimental_2.6.0-beta01.txt b/work/workmanager-ktx/api/public_plus_experimental_2.6.0-beta01.txt
deleted file mode 100644
index 2c5f419..0000000
--- a/work/workmanager-ktx/api/public_plus_experimental_2.6.0-beta01.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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> p);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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 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 final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
- }
-
- 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);
- }
-
-}
-
diff --git a/work/workmanager-ktx/api/public_plus_experimental_2.6.0-beta02.txt b/work/workmanager-ktx/api/public_plus_experimental_2.6.0-beta02.txt
deleted file mode 100644
index 2c5f419..0000000
--- a/work/workmanager-ktx/api/public_plus_experimental_2.6.0-beta02.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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> p);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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 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 final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
- }
-
- 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);
- }
-
-}
-
diff --git a/work/workmanager-ktx/api/public_plus_experimental_2.7.0-beta01.txt b/work/workmanager-ktx/api/public_plus_experimental_2.7.0-beta01.txt
new file mode 100644
index 0000000..8535d65
--- /dev/null
+++ b/work/workmanager-ktx/api/public_plus_experimental_2.7.0-beta01.txt
@@ -0,0 +1,42 @@
+// 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> p);
+ method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo> p);
+ 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> p);
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+ 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 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 final class OperationKt {
+ method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
+ }
+
+ 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);
+ }
+
+}
+
diff --git a/work/workmanager-ktx/api/public_plus_experimental_current.txt b/work/workmanager-ktx/api/public_plus_experimental_current.txt
index 2c5f419..8535d65 100644
--- a/work/workmanager-ktx/api/public_plus_experimental_current.txt
+++ b/work/workmanager-ktx/api/public_plus_experimental_current.txt
@@ -5,6 +5,8 @@
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> p);
method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo> p);
+ 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> p);
method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
diff --git a/work/workmanager-ktx/api/res-2.6.0-beta02.txt b/work/workmanager-ktx/api/res-2.6.0-beta02.txt
deleted file mode 100644
index e69de29..0000000
--- a/work/workmanager-ktx/api/res-2.6.0-beta02.txt
+++ /dev/null
diff --git a/work/workmanager-ktx/api/res-2.6.0-beta01.txt b/work/workmanager-ktx/api/res-2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-ktx/api/res-2.6.0-beta01.txt
rename to work/workmanager-ktx/api/res-2.7.0-beta01.txt
diff --git a/work/workmanager-ktx/api/restricted_2.6.0-beta01.txt b/work/workmanager-ktx/api/restricted_2.6.0-beta01.txt
deleted file mode 100644
index 2c5f419..0000000
--- a/work/workmanager-ktx/api/restricted_2.6.0-beta01.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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> p);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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 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 final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
- }
-
- 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);
- }
-
-}
-
diff --git a/work/workmanager-ktx/api/restricted_2.6.0-beta02.txt b/work/workmanager-ktx/api/restricted_2.6.0-beta02.txt
deleted file mode 100644
index 2c5f419..0000000
--- a/work/workmanager-ktx/api/restricted_2.6.0-beta02.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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> p);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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 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 final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
- }
-
- 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);
- }
-
-}
-
diff --git a/work/workmanager-ktx/api/restricted_2.7.0-beta01.txt b/work/workmanager-ktx/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..8535d65
--- /dev/null
+++ b/work/workmanager-ktx/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,42 @@
+// 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> p);
+ method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo> p);
+ 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> p);
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+ 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 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 final class OperationKt {
+ method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS> p);
+ }
+
+ 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);
+ }
+
+}
+
diff --git a/work/workmanager-ktx/api/restricted_current.txt b/work/workmanager-ktx/api/restricted_current.txt
index 2c5f419..8535d65 100644
--- a/work/workmanager-ktx/api/restricted_current.txt
+++ b/work/workmanager-ktx/api/restricted_current.txt
@@ -5,6 +5,8 @@
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> p);
method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo> p);
+ 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> p);
method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
diff --git a/work/workmanager-ktx/src/main/java/androidx/work/CoroutineWorker.kt b/work/workmanager-ktx/src/main/java/androidx/work/CoroutineWorker.kt
index 81d2a56..128ba4a 100644
--- a/work/workmanager-ktx/src/main/java/androidx/work/CoroutineWorker.kt
+++ b/work/workmanager-ktx/src/main/java/androidx/work/CoroutineWorker.kt
@@ -62,7 +62,6 @@
@Suppress("DEPRECATION")
public final override fun startWork(): ListenableFuture<Result> {
-
val coroutineScope = CoroutineScope(coroutineContext + job)
coroutineScope.launch {
try {
@@ -72,7 +71,6 @@
future.setException(t)
}
}
-
return future
}
@@ -93,6 +91,16 @@
public abstract suspend fun doWork(): Result
/**
+ * @return The [ForegroundInfo] instance if the [WorkRequest] is marked as expedited.
+ *
+ * @throws [IllegalStateException] when not overridden. Override this method when the
+ * corresponding [WorkRequest] is marked expedited.
+ */
+ public open suspend fun getForegroundInfo(): ForegroundInfo {
+ throw IllegalStateException("Not implemented")
+ }
+
+ /**
* Updates the progress for the [CoroutineWorker]. This is a suspending function unlike the
* [setProgressAsync] API which returns a [ListenableFuture].
*
@@ -107,14 +115,29 @@
* is a suspending function unlike the [setForegroundAsync] API which returns a
* [ListenableFuture].
*
+ * Calling [setForeground] will throw an [IllegalStateException] if the process is subject to
+ * foreground service restrictions. Consider using [WorkRequest.Builder.setExpedited]
+ * and [getForegroundInfo] instead.
+ *
* @param foregroundInfo The [ForegroundInfo]
*/
public suspend fun setForeground(foregroundInfo: ForegroundInfo) {
setForegroundAsync(foregroundInfo).await()
}
+ @Suppress("DEPRECATION")
+ public final override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
+ val job = Job()
+ val scope = CoroutineScope(coroutineContext + job)
+ val jobFuture = JobListenableFuture<ForegroundInfo>(job)
+ scope.launch {
+ jobFuture.complete(getForegroundInfo())
+ }
+ return jobFuture
+ }
+
public final override fun onStopped() {
super.onStopped()
future.cancel(false)
}
-}
\ No newline at end of file
+}
diff --git a/work/workmanager-ktx/src/main/java/androidx/work/ListenableFuture.kt b/work/workmanager-ktx/src/main/java/androidx/work/ListenableFuture.kt
index de621e3..6ae7f33 100644
--- a/work/workmanager-ktx/src/main/java/androidx/work/ListenableFuture.kt
+++ b/work/workmanager-ktx/src/main/java/androidx/work/ListenableFuture.kt
@@ -19,7 +19,9 @@
package androidx.work
import androidx.annotation.RestrictTo
+import androidx.work.impl.utils.futures.SettableFuture
import com.google.common.util.concurrent.ListenableFuture
+import kotlinx.coroutines.Job
import kotlinx.coroutines.suspendCancellableCoroutine
import java.util.concurrent.CancellationException
import java.util.concurrent.ExecutionException
@@ -60,3 +62,26 @@
)
}
}
+
+/**
+ * A special [Job] to [ListenableFuture] wrapper.
+ */
+internal class JobListenableFuture<R>(
+ private val job: Job,
+ private val underlying: SettableFuture<R> = SettableFuture.create()
+) : ListenableFuture<R> by underlying {
+
+ public fun complete(result: R) {
+ underlying.set(result)
+ }
+
+ init {
+ job.invokeOnCompletion { throwable: Throwable? ->
+ when (throwable) {
+ null -> require(underlying.isDone)
+ is CancellationException -> underlying.cancel(true)
+ else -> underlying.setException(throwable.cause ?: throwable)
+ }
+ }
+ }
+}
diff --git a/work/workmanager-multiprocess/api/2.6.0-beta02.txt b/work/workmanager-multiprocess/api/2.6.0-beta02.txt
deleted file mode 100644
index e033a49..0000000
--- a/work/workmanager-multiprocess/api/2.6.0-beta02.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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> p);
- method public final void onStopped();
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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/workmanager-multiprocess/api/2.6.0-beta01.txt b/work/workmanager-multiprocess/api/2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-multiprocess/api/2.6.0-beta01.txt
rename to work/workmanager-multiprocess/api/2.7.0-beta01.txt
diff --git a/work/workmanager-multiprocess/api/public_plus_experimental_2.6.0-beta01.txt b/work/workmanager-multiprocess/api/public_plus_experimental_2.6.0-beta01.txt
deleted file mode 100644
index e033a49..0000000
--- a/work/workmanager-multiprocess/api/public_plus_experimental_2.6.0-beta01.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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> p);
- method public final void onStopped();
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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/workmanager-multiprocess/api/public_plus_experimental_2.6.0-beta02.txt b/work/workmanager-multiprocess/api/public_plus_experimental_2.6.0-beta02.txt
deleted file mode 100644
index e033a49..0000000
--- a/work/workmanager-multiprocess/api/public_plus_experimental_2.6.0-beta02.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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> p);
- method public final void onStopped();
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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/workmanager-multiprocess/api/2.6.0-beta01.txt b/work/workmanager-multiprocess/api/public_plus_experimental_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-multiprocess/api/2.6.0-beta01.txt
copy to work/workmanager-multiprocess/api/public_plus_experimental_2.7.0-beta01.txt
diff --git a/work/workmanager-multiprocess/api/res-2.6.0-beta01.txt b/work/workmanager-multiprocess/api/res-2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-multiprocess/api/res-2.6.0-beta01.txt
rename to work/workmanager-multiprocess/api/res-2.7.0-beta01.txt
diff --git a/work/workmanager-multiprocess/api/restricted_2.6.0-beta01.txt b/work/workmanager-multiprocess/api/restricted_2.6.0-beta01.txt
deleted file mode 100644
index e033a49..0000000
--- a/work/workmanager-multiprocess/api/restricted_2.6.0-beta01.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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> p);
- method public final void onStopped();
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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/workmanager-multiprocess/api/restricted_2.6.0-beta02.txt b/work/workmanager-multiprocess/api/restricted_2.6.0-beta02.txt
deleted file mode 100644
index e033a49..0000000
--- a/work/workmanager-multiprocess/api/restricted_2.6.0-beta02.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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> p);
- method public final void onStopped();
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
- 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/workmanager-multiprocess/api/2.6.0-beta01.txt b/work/workmanager-multiprocess/api/restricted_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-multiprocess/api/2.6.0-beta01.txt
copy to work/workmanager-multiprocess/api/restricted_2.7.0-beta01.txt
diff --git a/work/workmanager-multiprocess/src/androidTest/java/androidx/work/multiprocess/ParcelableWorkRequestConvertersTest.kt b/work/workmanager-multiprocess/src/androidTest/java/androidx/work/multiprocess/ParcelableWorkRequestConvertersTest.kt
index d98d45f..ea7ed12 100644
--- a/work/workmanager-multiprocess/src/androidTest/java/androidx/work/multiprocess/ParcelableWorkRequestConvertersTest.kt
+++ b/work/workmanager-multiprocess/src/androidTest/java/androidx/work/multiprocess/ParcelableWorkRequestConvertersTest.kt
@@ -25,6 +25,7 @@
import androidx.work.Data
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
+import androidx.work.OutOfQuotaPolicy
import androidx.work.WorkRequest
import androidx.work.multiprocess.parcelable.ParcelConverters
import androidx.work.multiprocess.parcelable.ParcelableWorkRequest
@@ -120,6 +121,7 @@
requests += OneTimeWorkRequest.Builder(TestWorker::class.java)
.addTag("Test Worker")
.keepResultsForAtLeast(1, TimeUnit.DAYS)
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
}
assertOn(requests)
diff --git a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/parcelable/ParcelableWorkRequest.java b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/parcelable/ParcelableWorkRequest.java
index e784b12..4923b28 100644
--- a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/parcelable/ParcelableWorkRequest.java
+++ b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/parcelable/ParcelableWorkRequest.java
@@ -18,8 +18,12 @@
import static androidx.work.impl.model.WorkTypeConverters.backoffPolicyToInt;
import static androidx.work.impl.model.WorkTypeConverters.intToBackoffPolicy;
+import static androidx.work.impl.model.WorkTypeConverters.intToOutOfQuotaPolicy;
import static androidx.work.impl.model.WorkTypeConverters.intToState;
+import static androidx.work.impl.model.WorkTypeConverters.outOfQuotaPolicyToInt;
import static androidx.work.impl.model.WorkTypeConverters.stateToInt;
+import static androidx.work.multiprocess.parcelable.ParcelUtils.readBooleanValue;
+import static androidx.work.multiprocess.parcelable.ParcelUtils.writeBooleanValue;
import android.annotation.SuppressLint;
import android.os.Parcel;
@@ -89,6 +93,10 @@
workSpec.minimumRetentionDuration = in.readLong();
// scheduleRequestedAt
workSpec.scheduleRequestedAt = in.readLong();
+ // expedited
+ workSpec.expedited = readBooleanValue(in);
+ // fallback
+ workSpec.outOfQuotaPolicy = intToOutOfQuotaPolicy(in.readInt());
mWorkRequest = new WorkRequestHolder(UUID.fromString(id), workSpec, tagsSet);
}
@@ -149,6 +157,10 @@
parcel.writeLong(workSpec.minimumRetentionDuration);
// scheduleRequestedAt
parcel.writeLong(workSpec.scheduleRequestedAt);
+ // expedited
+ writeBooleanValue(parcel, workSpec.expedited);
+ // fallback
+ parcel.writeInt(outOfQuotaPolicyToInt(workSpec.outOfQuotaPolicy));
}
@NonNull
diff --git a/work/workmanager-rxjava2/api/2.6.0-beta02.txt b/work/workmanager-rxjava2/api/2.6.0-beta02.txt
deleted file mode 100644
index 2d667ee..0000000
--- a/work/workmanager-rxjava2/api/2.6.0-beta02.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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 final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
- 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/workmanager-rxjava2/api/2.6.0-beta01.txt b/work/workmanager-rxjava2/api/2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-rxjava2/api/2.6.0-beta01.txt
rename to work/workmanager-rxjava2/api/2.7.0-beta01.txt
diff --git a/work/workmanager-rxjava2/api/public_plus_experimental_2.6.0-beta01.txt b/work/workmanager-rxjava2/api/public_plus_experimental_2.6.0-beta01.txt
deleted file mode 100644
index 2d667ee..0000000
--- a/work/workmanager-rxjava2/api/public_plus_experimental_2.6.0-beta01.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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 final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
- 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/workmanager-rxjava2/api/public_plus_experimental_2.6.0-beta02.txt b/work/workmanager-rxjava2/api/public_plus_experimental_2.6.0-beta02.txt
deleted file mode 100644
index 2d667ee..0000000
--- a/work/workmanager-rxjava2/api/public_plus_experimental_2.6.0-beta02.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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 final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
- 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/workmanager-rxjava2/api/2.6.0-beta01.txt b/work/workmanager-rxjava2/api/public_plus_experimental_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-rxjava2/api/2.6.0-beta01.txt
copy to work/workmanager-rxjava2/api/public_plus_experimental_2.7.0-beta01.txt
diff --git a/work/workmanager-rxjava2/api/res-2.6.0-beta02.txt b/work/workmanager-rxjava2/api/res-2.6.0-beta02.txt
deleted file mode 100644
index e69de29..0000000
--- a/work/workmanager-rxjava2/api/res-2.6.0-beta02.txt
+++ /dev/null
diff --git a/work/workmanager-rxjava2/api/res-2.6.0-beta01.txt b/work/workmanager-rxjava2/api/res-2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-rxjava2/api/res-2.6.0-beta01.txt
rename to work/workmanager-rxjava2/api/res-2.7.0-beta01.txt
diff --git a/work/workmanager-rxjava2/api/restricted_2.6.0-beta01.txt b/work/workmanager-rxjava2/api/restricted_2.6.0-beta01.txt
deleted file mode 100644
index 2d667ee..0000000
--- a/work/workmanager-rxjava2/api/restricted_2.6.0-beta01.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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 final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
- 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/workmanager-rxjava2/api/restricted_2.6.0-beta02.txt b/work/workmanager-rxjava2/api/restricted_2.6.0-beta02.txt
deleted file mode 100644
index 2d667ee..0000000
--- a/work/workmanager-rxjava2/api/restricted_2.6.0-beta02.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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 final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
- 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/workmanager-rxjava2/api/2.6.0-beta01.txt b/work/workmanager-rxjava2/api/restricted_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-rxjava2/api/2.6.0-beta01.txt
copy to work/workmanager-rxjava2/api/restricted_2.7.0-beta01.txt
diff --git a/work/workmanager-rxjava3/api/2.6.0-beta02.txt b/work/workmanager-rxjava3/api/2.6.0-beta02.txt
deleted file mode 100644
index 9293340..0000000
--- a/work/workmanager-rxjava3/api/2.6.0-beta02.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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 final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
- }
-
-}
-
diff --git a/work/workmanager-rxjava3/api/2.6.0-beta01.txt b/work/workmanager-rxjava3/api/2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-rxjava3/api/2.6.0-beta01.txt
rename to work/workmanager-rxjava3/api/2.7.0-beta01.txt
diff --git a/work/workmanager-rxjava3/api/public_plus_experimental_2.6.0-beta01.txt b/work/workmanager-rxjava3/api/public_plus_experimental_2.6.0-beta01.txt
deleted file mode 100644
index 9293340..0000000
--- a/work/workmanager-rxjava3/api/public_plus_experimental_2.6.0-beta01.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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 final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
- }
-
-}
-
diff --git a/work/workmanager-rxjava3/api/public_plus_experimental_2.6.0-beta02.txt b/work/workmanager-rxjava3/api/public_plus_experimental_2.6.0-beta02.txt
deleted file mode 100644
index 9293340..0000000
--- a/work/workmanager-rxjava3/api/public_plus_experimental_2.6.0-beta02.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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 final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
- }
-
-}
-
diff --git a/work/workmanager-rxjava3/api/2.6.0-beta01.txt b/work/workmanager-rxjava3/api/public_plus_experimental_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-rxjava3/api/2.6.0-beta01.txt
copy to work/workmanager-rxjava3/api/public_plus_experimental_2.7.0-beta01.txt
diff --git a/work/workmanager-rxjava3/api/res-2.6.0-beta02.txt b/work/workmanager-rxjava3/api/res-2.6.0-beta02.txt
deleted file mode 100644
index e69de29..0000000
--- a/work/workmanager-rxjava3/api/res-2.6.0-beta02.txt
+++ /dev/null
diff --git a/work/workmanager-rxjava3/api/res-2.6.0-beta01.txt b/work/workmanager-rxjava3/api/res-2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-rxjava3/api/res-2.6.0-beta01.txt
rename to work/workmanager-rxjava3/api/res-2.7.0-beta01.txt
diff --git a/work/workmanager-rxjava3/api/restricted_2.6.0-beta01.txt b/work/workmanager-rxjava3/api/restricted_2.6.0-beta01.txt
deleted file mode 100644
index 9293340..0000000
--- a/work/workmanager-rxjava3/api/restricted_2.6.0-beta01.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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 final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
- }
-
-}
-
diff --git a/work/workmanager-rxjava3/api/restricted_2.6.0-beta02.txt b/work/workmanager-rxjava3/api/restricted_2.6.0-beta02.txt
deleted file mode 100644
index 9293340..0000000
--- a/work/workmanager-rxjava3/api/restricted_2.6.0-beta02.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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 final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
- }
-
-}
-
diff --git a/work/workmanager-rxjava3/api/2.6.0-beta01.txt b/work/workmanager-rxjava3/api/restricted_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-rxjava3/api/2.6.0-beta01.txt
copy to work/workmanager-rxjava3/api/restricted_2.7.0-beta01.txt
diff --git a/work/workmanager-testing/api/2.6.0-beta02.txt b/work/workmanager-testing/api/2.6.0-beta02.txt
deleted file mode 100644
index f3f3fe2..0000000
--- a/work/workmanager-testing/api/2.6.0-beta02.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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/workmanager-testing/api/2.6.0-beta01.txt b/work/workmanager-testing/api/2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-testing/api/2.6.0-beta01.txt
rename to work/workmanager-testing/api/2.7.0-beta01.txt
diff --git a/work/workmanager-testing/api/public_plus_experimental_2.6.0-beta01.txt b/work/workmanager-testing/api/public_plus_experimental_2.6.0-beta01.txt
deleted file mode 100644
index f3f3fe2..0000000
--- a/work/workmanager-testing/api/public_plus_experimental_2.6.0-beta01.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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/workmanager-testing/api/public_plus_experimental_2.6.0-beta02.txt b/work/workmanager-testing/api/public_plus_experimental_2.6.0-beta02.txt
deleted file mode 100644
index f3f3fe2..0000000
--- a/work/workmanager-testing/api/public_plus_experimental_2.6.0-beta02.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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/workmanager-testing/api/2.6.0-beta01.txt b/work/workmanager-testing/api/public_plus_experimental_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-testing/api/2.6.0-beta01.txt
copy to work/workmanager-testing/api/public_plus_experimental_2.7.0-beta01.txt
diff --git a/work/workmanager-testing/api/res-2.6.0-beta02.txt b/work/workmanager-testing/api/res-2.6.0-beta02.txt
deleted file mode 100644
index e69de29..0000000
--- a/work/workmanager-testing/api/res-2.6.0-beta02.txt
+++ /dev/null
diff --git a/work/workmanager-testing/api/res-2.6.0-beta01.txt b/work/workmanager-testing/api/res-2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager-testing/api/res-2.6.0-beta01.txt
rename to work/workmanager-testing/api/res-2.7.0-beta01.txt
diff --git a/work/workmanager-testing/api/restricted_2.6.0-beta01.txt b/work/workmanager-testing/api/restricted_2.6.0-beta01.txt
deleted file mode 100644
index f3f3fe2..0000000
--- a/work/workmanager-testing/api/restricted_2.6.0-beta01.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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/workmanager-testing/api/restricted_2.6.0-beta02.txt b/work/workmanager-testing/api/restricted_2.6.0-beta02.txt
deleted file mode 100644
index f3f3fe2..0000000
--- a/work/workmanager-testing/api/restricted_2.6.0-beta02.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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/workmanager-testing/api/2.6.0-beta01.txt b/work/workmanager-testing/api/restricted_2.7.0-beta01.txt
similarity index 100%
copy from work/workmanager-testing/api/2.6.0-beta01.txt
copy to work/workmanager-testing/api/restricted_2.7.0-beta01.txt
diff --git a/work/workmanager/api/2.6.0-beta01.txt b/work/workmanager/api/2.6.0-beta01.txt
deleted file mode 100644
index 54713f5..0000000
--- a/work/workmanager/api/2.6.0-beta01.txt
+++ /dev/null
@@ -1,400 +0,0 @@
-// 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!>);
- }
-
- public enum BackoffPolicy {
- 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.InputMergerFactory getInputMergerFactory();
- method public int getMaxJobSchedulerId();
- method public int getMinJobSchedulerId();
- method public androidx.work.RunnableScheduler getRunnableScheduler();
- 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 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 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(androidx.work.Constraints);
- method public androidx.work.NetworkType getRequiredNetworkType();
- method public boolean requiresBatteryNotLow();
- method public boolean requiresCharging();
- method @RequiresApi(23) public boolean requiresDeviceIdle();
- method public boolean requiresStorageNotLow();
- 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, boolean);
- method public androidx.work.Constraints build();
- method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
- method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
- method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
- method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
- method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
- }
-
- 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 {
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
- }
-
- public enum ExistingWorkPolicy {
- 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 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 @Keep public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
- method public final android.content.Context getApplicationContext();
- 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 {
- 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>);
- method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
- }
-
- 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>);
- method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 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 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>, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
- ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
- }
-
- 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 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 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 @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 abstract androidx.work.Operation pruneWork();
- }
-
- 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 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();
- 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<?, ?>, W extends androidx.work.WorkRequest> {
- method public final B addTag(String);
- method public final W build();
- method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
- method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
- method public final B setConstraints(androidx.work.Constraints);
- method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
- method public final B setInputData(androidx.work.Data);
- }
-
- public abstract class Worker extends androidx.work.ListenableWorker {
- ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
- method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
- 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 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/workmanager/api/2.6.0-beta02.txt b/work/workmanager/api/2.6.0-beta02.txt
deleted file mode 100644
index 54713f5..0000000
--- a/work/workmanager/api/2.6.0-beta02.txt
+++ /dev/null
@@ -1,400 +0,0 @@
-// 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!>);
- }
-
- public enum BackoffPolicy {
- 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.InputMergerFactory getInputMergerFactory();
- method public int getMaxJobSchedulerId();
- method public int getMinJobSchedulerId();
- method public androidx.work.RunnableScheduler getRunnableScheduler();
- 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 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 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(androidx.work.Constraints);
- method public androidx.work.NetworkType getRequiredNetworkType();
- method public boolean requiresBatteryNotLow();
- method public boolean requiresCharging();
- method @RequiresApi(23) public boolean requiresDeviceIdle();
- method public boolean requiresStorageNotLow();
- 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, boolean);
- method public androidx.work.Constraints build();
- method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
- method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
- method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
- method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
- method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
- }
-
- 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 {
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
- }
-
- public enum ExistingWorkPolicy {
- 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 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 @Keep public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
- method public final android.content.Context getApplicationContext();
- 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 {
- 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>);
- method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
- }
-
- 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>);
- method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 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 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>, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
- ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
- }
-
- 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 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 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 @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 abstract androidx.work.Operation pruneWork();
- }
-
- 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 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();
- 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<?, ?>, W extends androidx.work.WorkRequest> {
- method public final B addTag(String);
- method public final W build();
- method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
- method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
- method public final B setConstraints(androidx.work.Constraints);
- method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
- method public final B setInputData(androidx.work.Data);
- }
-
- public abstract class Worker extends androidx.work.ListenableWorker {
- ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
- method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
- 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 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/workmanager/api/2.7.0-beta01.txt b/work/workmanager/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..a6de624
--- /dev/null
+++ b/work/workmanager/api/2.7.0-beta01.txt
@@ -0,0 +1,407 @@
+// 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!>);
+ }
+
+ public enum BackoffPolicy {
+ 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.InputMergerFactory getInputMergerFactory();
+ method public int getMaxJobSchedulerId();
+ method public int getMinJobSchedulerId();
+ method public androidx.work.RunnableScheduler getRunnableScheduler();
+ 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 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 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(androidx.work.Constraints);
+ method public androidx.work.NetworkType getRequiredNetworkType();
+ method public boolean requiresBatteryNotLow();
+ method public boolean requiresCharging();
+ method @RequiresApi(23) public boolean requiresDeviceIdle();
+ method public boolean requiresStorageNotLow();
+ 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, boolean);
+ method public androidx.work.Constraints build();
+ method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
+ method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
+ method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
+ method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
+ method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
+ }
+
+ 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 {
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
+ }
+
+ public enum ExistingWorkPolicy {
+ 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 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 @Keep 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 {
+ 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>);
+ method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
+ }
+
+ 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>);
+ method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 {
+ 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 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>, long, java.util.concurrent.TimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
+ }
+
+ 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 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 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 @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 abstract androidx.work.Operation pruneWork();
+ }
+
+ 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 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();
+ 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<?, ?>, W extends androidx.work.WorkRequest> {
+ method public final B addTag(String);
+ method public final W build();
+ method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
+ method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
+ method public final B setConstraints(androidx.work.Constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy);
+ method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
+ method public final B setInputData(androidx.work.Data);
+ }
+
+ public abstract class Worker extends androidx.work.ListenableWorker {
+ ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
+ method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
+ 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 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/workmanager/api/current.txt b/work/workmanager/api/current.txt
index 54713f5..a6de624 100644
--- a/work/workmanager/api/current.txt
+++ b/work/workmanager/api/current.txt
@@ -154,6 +154,7 @@
public abstract class ListenableWorker {
ctor @Keep 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();
@@ -215,6 +216,11 @@
public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
}
+ public enum OutOfQuotaPolicy {
+ 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!>);
@@ -341,6 +347,7 @@
method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
method public final B setConstraints(androidx.work.Constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy);
method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
method public final B setInputData(androidx.work.Data);
diff --git a/work/workmanager/api/public_plus_experimental_2.6.0-beta01.txt b/work/workmanager/api/public_plus_experimental_2.6.0-beta01.txt
deleted file mode 100644
index 54713f5..0000000
--- a/work/workmanager/api/public_plus_experimental_2.6.0-beta01.txt
+++ /dev/null
@@ -1,400 +0,0 @@
-// 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!>);
- }
-
- public enum BackoffPolicy {
- 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.InputMergerFactory getInputMergerFactory();
- method public int getMaxJobSchedulerId();
- method public int getMinJobSchedulerId();
- method public androidx.work.RunnableScheduler getRunnableScheduler();
- 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 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 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(androidx.work.Constraints);
- method public androidx.work.NetworkType getRequiredNetworkType();
- method public boolean requiresBatteryNotLow();
- method public boolean requiresCharging();
- method @RequiresApi(23) public boolean requiresDeviceIdle();
- method public boolean requiresStorageNotLow();
- 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, boolean);
- method public androidx.work.Constraints build();
- method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
- method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
- method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
- method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
- method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
- }
-
- 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 {
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
- }
-
- public enum ExistingWorkPolicy {
- 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 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 @Keep public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
- method public final android.content.Context getApplicationContext();
- 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 {
- 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>);
- method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
- }
-
- 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>);
- method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 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 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>, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
- ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
- }
-
- 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 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 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 @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 abstract androidx.work.Operation pruneWork();
- }
-
- 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 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();
- 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<?, ?>, W extends androidx.work.WorkRequest> {
- method public final B addTag(String);
- method public final W build();
- method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
- method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
- method public final B setConstraints(androidx.work.Constraints);
- method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
- method public final B setInputData(androidx.work.Data);
- }
-
- public abstract class Worker extends androidx.work.ListenableWorker {
- ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
- method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
- 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 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/workmanager/api/public_plus_experimental_2.6.0-beta02.txt b/work/workmanager/api/public_plus_experimental_2.6.0-beta02.txt
deleted file mode 100644
index 54713f5..0000000
--- a/work/workmanager/api/public_plus_experimental_2.6.0-beta02.txt
+++ /dev/null
@@ -1,400 +0,0 @@
-// 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!>);
- }
-
- public enum BackoffPolicy {
- 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.InputMergerFactory getInputMergerFactory();
- method public int getMaxJobSchedulerId();
- method public int getMinJobSchedulerId();
- method public androidx.work.RunnableScheduler getRunnableScheduler();
- 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 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 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(androidx.work.Constraints);
- method public androidx.work.NetworkType getRequiredNetworkType();
- method public boolean requiresBatteryNotLow();
- method public boolean requiresCharging();
- method @RequiresApi(23) public boolean requiresDeviceIdle();
- method public boolean requiresStorageNotLow();
- 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, boolean);
- method public androidx.work.Constraints build();
- method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
- method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
- method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
- method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
- method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
- }
-
- 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 {
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
- }
-
- public enum ExistingWorkPolicy {
- 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 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 @Keep public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
- method public final android.content.Context getApplicationContext();
- 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 {
- 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>);
- method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
- }
-
- 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>);
- method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 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 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>, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
- ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
- }
-
- 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 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 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 @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 abstract androidx.work.Operation pruneWork();
- }
-
- 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 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();
- 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<?, ?>, W extends androidx.work.WorkRequest> {
- method public final B addTag(String);
- method public final W build();
- method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
- method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
- method public final B setConstraints(androidx.work.Constraints);
- method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
- method public final B setInputData(androidx.work.Data);
- }
-
- public abstract class Worker extends androidx.work.ListenableWorker {
- ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
- method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
- 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 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/workmanager/api/public_plus_experimental_2.7.0-beta01.txt b/work/workmanager/api/public_plus_experimental_2.7.0-beta01.txt
new file mode 100644
index 0000000..a6de624
--- /dev/null
+++ b/work/workmanager/api/public_plus_experimental_2.7.0-beta01.txt
@@ -0,0 +1,407 @@
+// 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!>);
+ }
+
+ public enum BackoffPolicy {
+ 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.InputMergerFactory getInputMergerFactory();
+ method public int getMaxJobSchedulerId();
+ method public int getMinJobSchedulerId();
+ method public androidx.work.RunnableScheduler getRunnableScheduler();
+ 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 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 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(androidx.work.Constraints);
+ method public androidx.work.NetworkType getRequiredNetworkType();
+ method public boolean requiresBatteryNotLow();
+ method public boolean requiresCharging();
+ method @RequiresApi(23) public boolean requiresDeviceIdle();
+ method public boolean requiresStorageNotLow();
+ 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, boolean);
+ method public androidx.work.Constraints build();
+ method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
+ method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
+ method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
+ method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
+ method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
+ }
+
+ 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 {
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
+ }
+
+ public enum ExistingWorkPolicy {
+ 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 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 @Keep 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 {
+ 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>);
+ method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
+ }
+
+ 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>);
+ method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 {
+ 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 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>, long, java.util.concurrent.TimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
+ }
+
+ 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 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 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 @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 abstract androidx.work.Operation pruneWork();
+ }
+
+ 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 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();
+ 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<?, ?>, W extends androidx.work.WorkRequest> {
+ method public final B addTag(String);
+ method public final W build();
+ method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
+ method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
+ method public final B setConstraints(androidx.work.Constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy);
+ method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
+ method public final B setInputData(androidx.work.Data);
+ }
+
+ public abstract class Worker extends androidx.work.ListenableWorker {
+ ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
+ method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
+ 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 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/workmanager/api/public_plus_experimental_current.txt b/work/workmanager/api/public_plus_experimental_current.txt
index 54713f5..a6de624 100644
--- a/work/workmanager/api/public_plus_experimental_current.txt
+++ b/work/workmanager/api/public_plus_experimental_current.txt
@@ -154,6 +154,7 @@
public abstract class ListenableWorker {
ctor @Keep 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();
@@ -215,6 +216,11 @@
public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
}
+ public enum OutOfQuotaPolicy {
+ 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!>);
@@ -341,6 +347,7 @@
method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
method public final B setConstraints(androidx.work.Constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy);
method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
method public final B setInputData(androidx.work.Data);
diff --git a/work/workmanager/api/res-2.6.0-beta02.txt b/work/workmanager/api/res-2.6.0-beta02.txt
deleted file mode 100644
index e69de29..0000000
--- a/work/workmanager/api/res-2.6.0-beta02.txt
+++ /dev/null
diff --git a/work/workmanager/api/res-2.6.0-beta01.txt b/work/workmanager/api/res-2.7.0-beta01.txt
similarity index 100%
rename from work/workmanager/api/res-2.6.0-beta01.txt
rename to work/workmanager/api/res-2.7.0-beta01.txt
diff --git a/work/workmanager/api/restricted_2.6.0-beta01.txt b/work/workmanager/api/restricted_2.6.0-beta01.txt
deleted file mode 100644
index 54713f5..0000000
--- a/work/workmanager/api/restricted_2.6.0-beta01.txt
+++ /dev/null
@@ -1,400 +0,0 @@
-// 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!>);
- }
-
- public enum BackoffPolicy {
- 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.InputMergerFactory getInputMergerFactory();
- method public int getMaxJobSchedulerId();
- method public int getMinJobSchedulerId();
- method public androidx.work.RunnableScheduler getRunnableScheduler();
- 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 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 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(androidx.work.Constraints);
- method public androidx.work.NetworkType getRequiredNetworkType();
- method public boolean requiresBatteryNotLow();
- method public boolean requiresCharging();
- method @RequiresApi(23) public boolean requiresDeviceIdle();
- method public boolean requiresStorageNotLow();
- 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, boolean);
- method public androidx.work.Constraints build();
- method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
- method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
- method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
- method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
- method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
- }
-
- 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 {
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
- }
-
- public enum ExistingWorkPolicy {
- 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 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 @Keep public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
- method public final android.content.Context getApplicationContext();
- 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 {
- 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>);
- method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
- }
-
- 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>);
- method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 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 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>, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
- ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
- }
-
- 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 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 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 @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 abstract androidx.work.Operation pruneWork();
- }
-
- 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 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();
- 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<?, ?>, W extends androidx.work.WorkRequest> {
- method public final B addTag(String);
- method public final W build();
- method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
- method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
- method public final B setConstraints(androidx.work.Constraints);
- method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
- method public final B setInputData(androidx.work.Data);
- }
-
- public abstract class Worker extends androidx.work.ListenableWorker {
- ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
- method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
- 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 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/workmanager/api/restricted_2.6.0-beta02.txt b/work/workmanager/api/restricted_2.6.0-beta02.txt
deleted file mode 100644
index 54713f5..0000000
--- a/work/workmanager/api/restricted_2.6.0-beta02.txt
+++ /dev/null
@@ -1,400 +0,0 @@
-// 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!>);
- }
-
- public enum BackoffPolicy {
- 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.InputMergerFactory getInputMergerFactory();
- method public int getMaxJobSchedulerId();
- method public int getMinJobSchedulerId();
- method public androidx.work.RunnableScheduler getRunnableScheduler();
- 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 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 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(androidx.work.Constraints);
- method public androidx.work.NetworkType getRequiredNetworkType();
- method public boolean requiresBatteryNotLow();
- method public boolean requiresCharging();
- method @RequiresApi(23) public boolean requiresDeviceIdle();
- method public boolean requiresStorageNotLow();
- 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, boolean);
- method public androidx.work.Constraints build();
- method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
- method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
- method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
- method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
- method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
- method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
- }
-
- 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 {
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
- enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
- }
-
- public enum ExistingWorkPolicy {
- 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 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 @Keep public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
- method public final android.content.Context getApplicationContext();
- 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 {
- 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>);
- method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
- }
-
- 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>);
- method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 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 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>, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
- ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
- ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
- }
-
- 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 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 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 @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 abstract androidx.work.Operation pruneWork();
- }
-
- 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 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();
- 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<?, ?>, W extends androidx.work.WorkRequest> {
- method public final B addTag(String);
- method public final W build();
- method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
- method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
- method public final B setConstraints(androidx.work.Constraints);
- method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
- method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
- method public final B setInputData(androidx.work.Data);
- }
-
- public abstract class Worker extends androidx.work.ListenableWorker {
- ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
- method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
- 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 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/workmanager/api/restricted_2.7.0-beta01.txt b/work/workmanager/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..a6de624
--- /dev/null
+++ b/work/workmanager/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,407 @@
+// 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!>);
+ }
+
+ public enum BackoffPolicy {
+ 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.InputMergerFactory getInputMergerFactory();
+ method public int getMaxJobSchedulerId();
+ method public int getMinJobSchedulerId();
+ method public androidx.work.RunnableScheduler getRunnableScheduler();
+ 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 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 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(androidx.work.Constraints);
+ method public androidx.work.NetworkType getRequiredNetworkType();
+ method public boolean requiresBatteryNotLow();
+ method public boolean requiresCharging();
+ method @RequiresApi(23) public boolean requiresDeviceIdle();
+ method public boolean requiresStorageNotLow();
+ 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, boolean);
+ method public androidx.work.Constraints build();
+ method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType);
+ method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean);
+ method public androidx.work.Constraints.Builder setRequiresCharging(boolean);
+ method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean);
+ method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration!);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration!);
+ }
+
+ 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 {
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
+ }
+
+ public enum ExistingWorkPolicy {
+ 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 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 @Keep 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 {
+ 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>);
+ method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
+ }
+
+ 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>);
+ method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.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 {
+ 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 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>, long, java.util.concurrent.TimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
+ }
+
+ 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 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 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 @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 abstract androidx.work.Operation pruneWork();
+ }
+
+ 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 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();
+ 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<?, ?>, W extends androidx.work.WorkRequest> {
+ method public final B addTag(String);
+ method public final W build();
+ method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
+ method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
+ method public final B setConstraints(androidx.work.Constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy);
+ method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
+ method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
+ method public final B setInputData(androidx.work.Data);
+ }
+
+ public abstract class Worker extends androidx.work.ListenableWorker {
+ ctor @Keep public Worker(android.content.Context, androidx.work.WorkerParameters);
+ method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
+ 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 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/workmanager/api/restricted_current.txt b/work/workmanager/api/restricted_current.txt
index 54713f5..a6de624 100644
--- a/work/workmanager/api/restricted_current.txt
+++ b/work/workmanager/api/restricted_current.txt
@@ -154,6 +154,7 @@
public abstract class ListenableWorker {
ctor @Keep 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();
@@ -215,6 +216,11 @@
public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
}
+ public enum OutOfQuotaPolicy {
+ 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!>);
@@ -341,6 +347,7 @@
method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
method public final B setConstraints(androidx.work.Constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy);
method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
method public final B setInputData(androidx.work.Data);
diff --git a/work/workmanager/build.gradle b/work/workmanager/build.gradle
index d3576af..f6c9f47 100644
--- a/work/workmanager/build.gradle
+++ b/work/workmanager/build.gradle
@@ -49,11 +49,13 @@
}
dependencies {
+ implementation("androidx.core:core:1.5.0-beta01")
annotationProcessor("androidx.room:room-compiler:2.2.5")
implementation("androidx.room:room-runtime:2.2.5")
androidTestImplementation("androidx.room:room-testing:2.2.5")
implementation("androidx.sqlite:sqlite:2.1.0")
implementation("androidx.sqlite:sqlite-framework:2.1.0")
+ api("androidx.annotation:annotation-experimental:1.0.0")
api(libs.guavaListenableFuture)
api("androidx.lifecycle:lifecycle-livedata:2.1.0")
api("androidx.startup:startup-runtime:1.0.0")
diff --git a/work/workmanager/lint-baseline.xml b/work/workmanager/lint-baseline.xml
index a4fedbb..27ddc53 100644
--- a/work/workmanager/lint-baseline.xml
+++ b/work/workmanager/lint-baseline.xml
@@ -206,7 +206,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/Constraints.java"
- line="408"
+ line="429"
column="51"/>
</issue>
@@ -217,18 +217,40 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/Constraints.java"
- line="443"
+ line="464"
column="48"/>
</issue>
<issue
id="ClassVerificationFailure"
+ message="This call references a method added in API level 30; however, the containing class androidx.work.impl.utils.ForceStopRunnable is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" activityManager.getHistoricalProcessExitReasons("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/work/impl/utils/ForceStopRunnable.java"
+ line="171"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 30; however, the containing class androidx.work.impl.utils.ForceStopRunnable is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" if (info.getReason() == REASON_USER_REQUESTED) {"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/work/impl/utils/ForceStopRunnable.java"
+ line="180"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
message="This call references a method added in API level 19; however, the containing class androidx.work.impl.utils.ForceStopRunnable is reachable from earlier API levels and will fail run-time class verification."
errorLine1=" alarmManager.setExact(RTC_WAKEUP, triggerAt, pendingIntent);"
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/utils/ForceStopRunnable.java"
- line="303"
+ line="339"
column="30"/>
</issue>
@@ -349,7 +371,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="104"
+ line="106"
column="25"/>
</issue>
@@ -360,7 +382,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="111"
+ line="113"
column="25"/>
</issue>
@@ -371,7 +393,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="113"
+ line="115"
column="21"/>
</issue>
@@ -382,7 +404,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="114"
+ line="116"
column="21"/>
</issue>
@@ -393,7 +415,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="121"
+ line="123"
column="21"/>
</issue>
@@ -404,7 +426,18 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="122"
+ line="124"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="ClassVerificationFailure"
+ message="This call references a method added in API level 31; however, the containing class androidx.work.impl.background.systemjob.SystemJobInfoConverter is reachable from earlier API levels and will fail run-time class verification."
+ errorLine1=" builder.setExpedited(true);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
+ line="130"
column="21"/>
</issue>
@@ -415,7 +448,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="132"
+ line="140"
column="16"/>
</issue>
@@ -426,7 +459,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java"
- line="150"
+ line="158"
column="21"/>
</issue>
@@ -503,7 +536,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/WorkManagerImpl.java"
- line="761"
+ line="767"
column="71"/>
</issue>
@@ -514,7 +547,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/WorkRequest.java"
- line="174"
+ line="175"
column="56"/>
</issue>
@@ -525,7 +558,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/WorkRequest.java"
- line="251"
+ line="252"
column="59"/>
</issue>
@@ -536,7 +569,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/WorkRequest.java"
- line="283"
+ line="284"
column="47"/>
</issue>
@@ -618,11 +651,11 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="178"
+ line="188"
column="20"/>
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="191"
+ line="201"
column="17"
message="Setter here"/>
</issue>
@@ -931,7 +964,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/Constraints.java"
- line="407"
+ line="428"
column="53"/>
</issue>
@@ -942,7 +975,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/Constraints.java"
- line="442"
+ line="463"
column="50"/>
</issue>
@@ -1712,7 +1745,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java"
- line="77"
+ line="78"
column="13"/>
</issue>
@@ -1723,7 +1756,7 @@
errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java"
- line="78"
+ line="79"
column="13"/>
</issue>
@@ -1734,7 +1767,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java"
- line="79"
+ line="80"
column="13"/>
</issue>
@@ -1745,7 +1778,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java"
- line="80"
+ line="81"
column="13"/>
</issue>
@@ -1756,7 +1789,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java"
- line="180"
+ line="181"
column="34"/>
</issue>
@@ -1954,7 +1987,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="76"
+ line="77"
column="12"/>
</issue>
@@ -1965,7 +1998,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="365"
+ line="377"
column="16"/>
</issue>
@@ -1976,7 +2009,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="368"
+ line="380"
column="16"/>
</issue>
@@ -1987,7 +2020,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="395"
+ line="407"
column="16"/>
</issue>
@@ -1998,7 +2031,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="398"
+ line="410"
column="16"/>
</issue>
@@ -2009,7 +2042,7 @@
errorLine2=" ~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="401"
+ line="413"
column="16"/>
</issue>
@@ -2020,7 +2053,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="411"
+ line="423"
column="16"/>
</issue>
@@ -2031,7 +2064,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkSpec.java"
- line="420"
+ line="432"
column="16"/>
</issue>
@@ -2097,7 +2130,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="90"
+ line="100"
column="34"/>
</issue>
@@ -2108,7 +2141,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="123"
+ line="133"
column="19"/>
</issue>
@@ -2119,7 +2152,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="156"
+ line="166"
column="42"/>
</issue>
@@ -2130,7 +2163,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="177"
+ line="187"
column="19"/>
</issue>
@@ -2141,7 +2174,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="198"
+ line="208"
column="40"/>
</issue>
@@ -2152,7 +2185,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="233"
+ line="243"
column="19"/>
</issue>
@@ -2163,7 +2196,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="266"
+ line="315"
column="19"/>
</issue>
@@ -2174,7 +2207,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="266"
+ line="315"
column="56"/>
</issue>
@@ -2185,7 +2218,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="305"
+ line="354"
column="19"/>
</issue>
@@ -2196,7 +2229,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/androidx/work/impl/model/WorkTypeConverters.java"
- line="305"
+ line="354"
column="68"/>
</issue>
@@ -2211,15 +2244,4 @@
column="16"/>
</issue>
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" public WorkerWrapper build() {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/work/impl/WorkerWrapper.java"
- line="684"
- column="16"/>
- </issue>
-
</issues>
diff --git a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
index 4ecbbe1..a593404 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
@@ -19,6 +19,7 @@
import static android.content.Context.MODE_PRIVATE;
import static android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL;
+import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_11_12;
import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_3_4;
import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_4_5;
import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_6_7;
@@ -27,6 +28,7 @@
import static androidx.work.impl.WorkDatabaseMigrations.VERSION_1;
import static androidx.work.impl.WorkDatabaseMigrations.VERSION_10;
import static androidx.work.impl.WorkDatabaseMigrations.VERSION_11;
+import static androidx.work.impl.WorkDatabaseMigrations.VERSION_12;
import static androidx.work.impl.WorkDatabaseMigrations.VERSION_2;
import static androidx.work.impl.WorkDatabaseMigrations.VERSION_3;
import static androidx.work.impl.WorkDatabaseMigrations.VERSION_4;
@@ -85,6 +87,7 @@
private static final String COLUMN_SYSTEM_ID = "system_id";
private static final String COLUMN_ALARM_ID = "alarm_id";
private static final String COLUMN_RUN_IN_FOREGROUND = "run_in_foreground";
+ private static final String COLUMN_OUT_OF_QUOTA_POLICY = "out_of_quota_policy";
// Queries
private static final String INSERT_ALARM_INFO = "INSERT INTO alarmInfo VALUES (?, ?)";
@@ -436,6 +439,22 @@
database.close();
}
+ @Test
+ @MediumTest
+ public void testMigrationVersion11To12() throws IOException {
+ SupportSQLiteDatabase database =
+ mMigrationTestHelper.createDatabase(TEST_DATABASE, VERSION_11);
+ database = mMigrationTestHelper.runMigrationsAndValidate(
+ TEST_DATABASE,
+ VERSION_12,
+ VALIDATE_DROPPED_TABLES,
+ MIGRATION_11_12);
+
+ assertThat(checkColumnExists(database, TABLE_WORKSPEC, COLUMN_OUT_OF_QUOTA_POLICY),
+ is(true));
+ database.close();
+ }
+
@NonNull
private ContentValues contentValues(String workSpecId) {
ContentValues contentValues = new ContentValues();
diff --git a/work/workmanager/src/androidTest/java/androidx/work/WorkForegroundRunnableTest.kt b/work/workmanager/src/androidTest/java/androidx/work/WorkForegroundRunnableTest.kt
new file mode 100644
index 0000000..8babf02
--- /dev/null
+++ b/work/workmanager/src/androidTest/java/androidx/work/WorkForegroundRunnableTest.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work
+
+import android.app.Notification
+import android.content.Context
+import android.util.Log
+import androidx.core.os.BuildCompat
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.work.impl.utils.SynchronousExecutor
+import androidx.work.impl.utils.WorkForegroundRunnable
+import androidx.work.impl.utils.futures.SettableFuture
+import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor
+import androidx.work.impl.utils.taskexecutor.TaskExecutor
+import androidx.work.worker.TestWorker
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import java.util.UUID
+import java.util.concurrent.Executor
+
+@RunWith(AndroidJUnit4::class)
+public class WorkForegroundRunnableTest : DatabaseTest() {
+ private lateinit var context: Context
+ private lateinit var configuration: Configuration
+ private lateinit var executor: Executor
+ private lateinit var progressUpdater: ProgressUpdater
+ private lateinit var foregroundUpdater: ForegroundUpdater
+ private lateinit var taskExecutor: TaskExecutor
+
+ @Before
+ public fun setUp() {
+ context = InstrumentationRegistry.getInstrumentation().targetContext
+ executor = SynchronousExecutor()
+ configuration = Configuration.Builder()
+ .setMinimumLoggingLevel(Log.DEBUG)
+ .setExecutor(executor)
+ .build()
+ progressUpdater = mock(ProgressUpdater::class.java)
+ foregroundUpdater = mock(ForegroundUpdater::class.java)
+ taskExecutor = InstantWorkTaskExecutor()
+ }
+
+ @Test
+ @MediumTest
+ @SdkSuppress(maxSdkVersion = 30)
+ public fun doesNothing_forRegularWorkRequests() {
+ val work = OneTimeWorkRequest.Builder(TestWorker::class.java)
+ .build()
+
+ insertWork(work)
+ val worker = spy(
+ configuration.mWorkerFactory.createWorkerWithDefaultFallback(
+ context,
+ work.workSpec.workerClassName,
+ newWorkerParams(work)
+ )!!
+ )
+ val runnable = WorkForegroundRunnable(
+ context,
+ work.workSpec,
+ worker,
+ foregroundUpdater,
+ taskExecutor
+ )
+ runnable.run()
+ assertThat(runnable.future.isDone, `is`(equalTo(true)))
+ verifyNoMoreInteractions(foregroundUpdater)
+ }
+
+ @Test
+ @MediumTest
+ public fun callGetForeground_forExpeditedWork1() {
+ if (BuildCompat.isAtLeastS()) {
+ return
+ }
+
+ val work = OneTimeWorkRequest.Builder(TestWorker::class.java)
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .build()
+
+ insertWork(work)
+ val worker = spy(
+ configuration.mWorkerFactory.createWorkerWithDefaultFallback(
+ context,
+ work.workSpec.workerClassName,
+ newWorkerParams(work)
+ )!!
+ )
+ val runnable = WorkForegroundRunnable(
+ context,
+ work.workSpec,
+ worker,
+ foregroundUpdater,
+ taskExecutor
+ )
+ runnable.run()
+ verify(worker).foregroundInfoAsync
+ assertThat(runnable.future.isDone, `is`(equalTo(true)))
+ }
+
+ @Test
+ @SmallTest
+ public fun callGetForeground_forExpeditedWork2() {
+ if (BuildCompat.isAtLeastS()) {
+ return
+ }
+
+ val work = OneTimeWorkRequest.Builder(TestWorker::class.java)
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .build()
+
+ insertWork(work)
+ val worker = spy(
+ configuration.mWorkerFactory.createWorkerWithDefaultFallback(
+ context,
+ work.workSpec.workerClassName,
+ newWorkerParams(work)
+ )!!
+ )
+
+ val notification = mock(Notification::class.java)
+ val id = 10
+ val foregroundInfo = ForegroundInfo(id, notification)
+ val foregroundFuture = SettableFuture.create<ForegroundInfo>()
+ foregroundFuture.set(foregroundInfo)
+ `when`(worker.foregroundInfoAsync).thenReturn(foregroundFuture)
+ val runnable = WorkForegroundRunnable(
+ context,
+ work.workSpec,
+ worker,
+ foregroundUpdater,
+ taskExecutor
+ )
+ runnable.run()
+ verify(worker).foregroundInfoAsync
+ verify(foregroundUpdater).setForegroundAsync(context, work.id, foregroundInfo)
+ assertThat(runnable.future.isDone, `is`(equalTo(true)))
+ }
+
+ private fun newWorkerParams(workRequest: WorkRequest) = WorkerParameters(
+ UUID.fromString(workRequest.stringId),
+ Data.EMPTY,
+ listOf<String>(),
+ WorkerParameters.RuntimeExtras(),
+ 1,
+ executor,
+ taskExecutor,
+ configuration.mWorkerFactory,
+ progressUpdater,
+ foregroundUpdater
+ )
+}
diff --git a/work/workmanager/src/androidTest/java/androidx/work/WorkTest.java b/work/workmanager/src/androidTest/java/androidx/work/WorkTest.java
index 5237099..4c526d8 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/WorkTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/WorkTest.java
@@ -16,11 +16,15 @@
package androidx.work;
+import static androidx.work.NetworkType.METERED;
+import static androidx.work.NetworkType.NOT_REQUIRED;
+
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import androidx.core.os.BuildCompat;
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import androidx.work.impl.model.WorkSpec;
@@ -139,4 +143,97 @@
.setInitialDelay(Long.MAX_VALUE - now, TimeUnit.MILLISECONDS)
.build();
}
+
+ @Test
+ public void testBuild_expedited_noConstraints() {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
+
+ OneTimeWorkRequest request = mBuilder
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .build();
+ WorkSpec workSpec = request.getWorkSpec();
+ Constraints constraints = workSpec.constraints;
+ assertThat(constraints.getRequiredNetworkType(), is(NOT_REQUIRED));
+ }
+
+ @Test
+ public void testBuild_expedited_networkConstraints() {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
+
+ OneTimeWorkRequest request = mBuilder
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .setConstraints(new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.METERED)
+ .build()
+ )
+ .build();
+ WorkSpec workSpec = request.getWorkSpec();
+ Constraints constraints = workSpec.constraints;
+ assertThat(constraints.getRequiredNetworkType(), is(METERED));
+ }
+
+ @Test
+ public void testBuild_expedited_networkStorageConstraints() {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
+
+ OneTimeWorkRequest request = mBuilder
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .setConstraints(new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.METERED)
+ .setRequiresStorageNotLow(true)
+ .build()
+ )
+ .build();
+ WorkSpec workSpec = request.getWorkSpec();
+ Constraints constraints = workSpec.constraints;
+ assertThat(constraints.getRequiredNetworkType(), is(METERED));
+ }
+
+ @Test
+ public void testBuild_expedited_withUnspportedConstraints() {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
+
+ mThrown.expect(IllegalArgumentException.class);
+ OneTimeWorkRequest request = mBuilder
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .setConstraints(new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.METERED)
+ .setRequiresStorageNotLow(true)
+ .setRequiresCharging(true)
+ .build()
+ )
+ .build();
+ WorkSpec workSpec = request.getWorkSpec();
+ Constraints constraints = workSpec.constraints;
+ assertThat(constraints.getRequiredNetworkType(), is(METERED));
+ }
+
+ @Test
+ public void testBuild_expedited_withUnspportedConstraints2() {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
+
+ mThrown.expect(IllegalArgumentException.class);
+ OneTimeWorkRequest request = mBuilder
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .setConstraints(new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.METERED)
+ .setRequiresStorageNotLow(true)
+ .setRequiresDeviceIdle(true)
+ .build()
+ )
+ .build();
+ WorkSpec workSpec = request.getWorkSpec();
+ Constraints constraints = workSpec.constraints;
+ assertThat(constraints.getRequiredNetworkType(), is(METERED));
+ }
}
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java
index 32786ae..64a2074 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java
@@ -35,6 +35,7 @@
import android.net.Uri;
import android.os.Build;
+import androidx.core.os.BuildCompat;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
@@ -241,6 +242,33 @@
assertThat(jobInfo.isImportantWhileForeground(), is(false));
}
+ @Test
+ @SmallTest
+ public void testConvert_expedited() {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
+
+ WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
+ workSpec.expedited = true;
+ JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
+ assertThat(jobInfo.isExpedited(), is(true));
+ }
+
+ @Test
+ @SmallTest
+ public void testConvertExpeditedJobs_retriesAreNotExpedited() {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
+
+ WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
+ workSpec.expedited = true;
+ workSpec.runAttemptCount = 1; // retry
+ JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
+ assertThat(jobInfo.isExpedited(), is(false));
+ }
+
private void convertWithRequiredNetworkType(NetworkType networkType,
int jobInfoNetworkType,
int minSdkVersion) {
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/utils/WorkForegroundUpdaterTest.kt b/work/workmanager/src/androidTest/java/androidx/work/impl/utils/WorkForegroundUpdaterTest.kt
index 9d10994..b9373a0 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/utils/WorkForegroundUpdaterTest.kt
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/utils/WorkForegroundUpdaterTest.kt
@@ -21,25 +21,30 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.filters.SdkSuppress
+import androidx.work.Constraints
import androidx.work.ForegroundInfo
+import androidx.work.NetworkType
+import androidx.work.OneTimeWorkRequest
import androidx.work.WorkInfo
import androidx.work.impl.WorkDatabase
import androidx.work.impl.foreground.ForegroundProcessor
import androidx.work.impl.model.WorkSpecDao
import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor
import androidx.work.impl.utils.taskexecutor.TaskExecutor
+import androidx.work.worker.TestWorker
+import org.junit.Assert.assertNotNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock
import java.util.UUID
@RunWith(AndroidJUnit4::class)
-// Mockito tries to class load android.os.CancellationSignal which is only available on API >= 16
-@SdkSuppress(minSdkVersion = 16)
-class WorkForegroundUpdaterTest {
+
+public class WorkForegroundUpdaterTest {
private lateinit var mContext: Context
private lateinit var mDatabase: WorkDatabase
@@ -49,7 +54,7 @@
private lateinit var mForegroundInfo: ForegroundInfo
@Before
- fun setUp() {
+ public fun setUp() {
mContext = mock(Context::class.java)
mDatabase = mock(WorkDatabase::class.java)
mWorkSpecDao = mock(WorkSpecDao::class.java)
@@ -62,7 +67,9 @@
@Test(expected = IllegalStateException::class)
@MediumTest
- fun setForeground_whenWorkReplaced() {
+ // Mockito tries to class load android.os.CancellationSignal which is only available on API >= 16
+ @SdkSuppress(minSdkVersion = 16, maxSdkVersion = 29)
+ public fun setForeground_whenWorkReplaced() {
val foregroundUpdater =
WorkForegroundUpdater(mDatabase, mForegroundProcessor, mTaskExecutor)
val uuid = UUID.randomUUID()
@@ -75,7 +82,9 @@
@Test(expected = IllegalStateException::class)
@MediumTest
- fun setForeground_whenWorkFinished() {
+ // Mockito tries to class load android.os.CancellationSignal which is only available on API >= 16
+ @SdkSuppress(minSdkVersion = 16, maxSdkVersion = 29)
+ public fun setForeground_whenWorkFinished() {
`when`(mWorkSpecDao.getState(anyString())).thenReturn(WorkInfo.State.SUCCEEDED)
val foregroundUpdater =
WorkForegroundUpdater(mDatabase, mForegroundProcessor, mTaskExecutor)
@@ -86,4 +95,29 @@
throw exception.cause ?: exception
}
}
+
+ @Test
+ @MediumTest
+ public fun setForeground_throwsException() {
+ `when`(mWorkSpecDao.getState(anyString())).thenReturn(WorkInfo.State.RUNNING)
+ `when`(mForegroundProcessor.startForeground(anyString(), ArgumentMatchers.any()))
+ .thenThrow(IllegalStateException("Subject to foreground service restrictions."))
+ val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
+ .setConstraints(
+ Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
+ ).build()
+ val notificationId = 1
+ val notification = mock(Notification::class.java)
+ val metadata = ForegroundInfo(notificationId, notification)
+ val foregroundUpdater =
+ WorkForegroundUpdater(mDatabase, mForegroundProcessor, mTaskExecutor)
+ var exception: Throwable? = null
+ try {
+ val future = foregroundUpdater.setForegroundAsync(mContext, request.id, metadata)
+ future.get()
+ } catch (throwable: Throwable) {
+ exception = throwable
+ }
+ assertNotNull("Exception cannot be null", exception)
+ }
}
diff --git a/work/workmanager/src/androidTest/java/androidx/work/worker/StopAwareForegroundWorker.kt b/work/workmanager/src/androidTest/java/androidx/work/worker/StopAwareForegroundWorker.kt
index 9197f1d..0c12308 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/worker/StopAwareForegroundWorker.kt
+++ b/work/workmanager/src/androidTest/java/androidx/work/worker/StopAwareForegroundWorker.kt
@@ -21,6 +21,8 @@
import androidx.work.ForegroundInfo
import androidx.work.Worker
import androidx.work.WorkerParameters
+import androidx.work.impl.utils.futures.SettableFuture
+import com.google.common.util.concurrent.ListenableFuture
public open class StopAwareForegroundWorker(
private val context: Context,
@@ -29,13 +31,18 @@
Worker(context, parameters) {
override fun doWork(): Result {
- setForegroundAsync(getNotification())
while (!isStopped) {
// Do nothing
}
return Result.success()
}
+ override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
+ val future = SettableFuture.create<ForegroundInfo>()
+ future.set(getNotification())
+ return future
+ }
+
private fun getNotification(): ForegroundInfo {
val notification = NotificationCompat.Builder(context, ChannelId)
.setOngoing(true)
diff --git a/work/workmanager/src/androidTest/java/androidx/work/worker/TestForegroundWorker.kt b/work/workmanager/src/androidTest/java/androidx/work/worker/TestForegroundWorker.kt
index d75a5ec..2968cf7 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/worker/TestForegroundWorker.kt
+++ b/work/workmanager/src/androidTest/java/androidx/work/worker/TestForegroundWorker.kt
@@ -21,6 +21,8 @@
import androidx.work.ForegroundInfo
import androidx.work.Worker
import androidx.work.WorkerParameters
+import androidx.work.impl.utils.futures.SettableFuture
+import com.google.common.util.concurrent.ListenableFuture
public open class TestForegroundWorker(
private val context: Context,
@@ -29,10 +31,15 @@
Worker(context, parameters) {
override fun doWork(): Result {
- setForegroundAsync(getNotification()).get()
return Result.success()
}
+ override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
+ val future = SettableFuture.create<ForegroundInfo>()
+ future.set(getNotification())
+ return future
+ }
+
private fun getNotification(): ForegroundInfo {
val notification = NotificationCompat.Builder(context, ChannelId)
.setOngoing(true)
diff --git a/work/workmanager/src/main/java/androidx/work/Constraints.java b/work/workmanager/src/main/java/androidx/work/Constraints.java
index ad6d5d0..ffca8e3 100644
--- a/work/workmanager/src/main/java/androidx/work/Constraints.java
+++ b/work/workmanager/src/main/java/androidx/work/Constraints.java
@@ -290,6 +290,27 @@
long mTriggerContentMaxDelay = -1;
ContentUriTriggers mContentUriTriggers = new ContentUriTriggers();
+ public Builder() {
+ // default public constructor
+ }
+
+ /**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public Builder(@NonNull Constraints constraints) {
+ mRequiresCharging = constraints.requiresCharging();
+ mRequiresDeviceIdle = Build.VERSION.SDK_INT >= 23 && constraints.requiresDeviceIdle();
+ mRequiredNetworkType = constraints.getRequiredNetworkType();
+ mRequiresBatteryNotLow = constraints.requiresBatteryNotLow();
+ mRequiresStorageNotLow = constraints.requiresStorageNotLow();
+ if (Build.VERSION.SDK_INT >= 24) {
+ mTriggerContentUpdateDelay = constraints.getTriggerContentUpdateDelay();
+ mTriggerContentMaxDelay = constraints.getTriggerMaxContentDelay();
+ mContentUriTriggers = constraints.getContentUriTriggers();
+ }
+ }
+
/**
* Sets whether device should be charging for the {@link WorkRequest} to run. The
* default value is {@code false}.
diff --git a/work/workmanager/src/main/java/androidx/work/ListenableWorker.java b/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
index f57c3e6..a249348 100644
--- a/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
+++ b/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
@@ -28,6 +28,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
+import androidx.work.impl.utils.futures.SettableFuture;
import androidx.work.impl.utils.taskexecutor.TaskExecutor;
import com.google.common.util.concurrent.ListenableFuture;
@@ -216,6 +217,12 @@
* Under the hood, WorkManager manages and runs a foreground service on your behalf to
* execute this WorkRequest, showing the notification provided in
* {@link ForegroundInfo}.
+ * <p>
+ * Calling {@code setForegroundAsync} will fail with an
+ * {@link IllegalStateException} when the process is subject to foreground
+ * service restrictions. Consider using
+ * {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)} and
+ * {@link ListenableWorker#getForegroundInfoAsync()} instead.
*
* @param foregroundInfo The {@link ForegroundInfo}
* @return A {@link ListenableFuture} which resolves after the {@link ListenableWorker}
@@ -229,11 +236,35 @@
}
/**
+ * Return an instance of {@link ForegroundInfo} if the {@link WorkRequest} is important to
+ * the user. In this case, WorkManager provides a signal to the OS that the process should
+ * be kept alive while this work is executing.
+ * <p>
+ * Prior to Android S, WorkManager manages and runs a foreground service on your behalf to
+ * execute the WorkRequest, showing the notification provided in the {@link ForegroundInfo}.
+ * To update this notification subsequently, the application can use
+ * {@link android.app.NotificationManager}.
+ * <p>
+ * Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job.
+ *
+ * @return A {@link ListenableFuture} of {@link ForegroundInfo} instance if the WorkRequest
+ * is marked immediate. For more information look at
+ * {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)}.
+ */
+ @NonNull
+ public ListenableFuture<ForegroundInfo> getForegroundInfoAsync() {
+ SettableFuture<ForegroundInfo> future = SettableFuture.create();
+ future.setException(new IllegalStateException("Not implemented"));
+ return future;
+ }
+
+ /**
* Returns {@code true} if this Worker has been told to stop. This could be because of an
* explicit cancellation signal by the user, or because the system has decided to preempt the
* task. In these cases, the results of the work will be ignored by WorkManager and it is safe
* to stop the computation. WorkManager will retry the work at a later time if necessary.
*
+ *
* @return {@code true} if the work operation has been interrupted
*/
public final boolean isStopped() {
@@ -297,6 +328,14 @@
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public void setRunInForeground(boolean runInForeground) {
+ mRunInForeground = runInForeground;
+ }
+
+ /**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public @NonNull Executor getBackgroundExecutor() {
return mWorkerParams.getBackgroundExecutor();
}
diff --git a/work/workmanager/src/main/java/androidx/work/OneTimeWorkRequest.java b/work/workmanager/src/main/java/androidx/work/OneTimeWorkRequest.java
index 51ba3e6..d33851e 100644
--- a/work/workmanager/src/main/java/androidx/work/OneTimeWorkRequest.java
+++ b/work/workmanager/src/main/java/androidx/work/OneTimeWorkRequest.java
@@ -107,12 +107,6 @@
throw new IllegalArgumentException(
"Cannot set backoff criteria on an idle mode job");
}
- if (mWorkSpec.runInForeground
- && Build.VERSION.SDK_INT >= 23
- && mWorkSpec.constraints.requiresDeviceIdle()) {
- throw new IllegalArgumentException(
- "Cannot run in foreground with an idle mode constraint");
- }
return new OneTimeWorkRequest(this);
}
diff --git a/work/workmanager/src/main/java/androidx/work/OutOfQuotaPolicy.java b/work/workmanager/src/main/java/androidx/work/OutOfQuotaPolicy.java
new file mode 100644
index 0000000..c82568a
--- /dev/null
+++ b/work/workmanager/src/main/java/androidx/work/OutOfQuotaPolicy.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work;
+
+/**
+ * An enumeration of policies that help determine out of quota behavior for expedited jobs.
+ */
+public enum OutOfQuotaPolicy {
+
+ /**
+ * When the app does not have any expedited job quota, the expedited work request will
+ * fallback to a regular work request.
+ */
+ RUN_AS_NON_EXPEDITED_WORK_REQUEST,
+
+ /**
+ * When the app does not have any expedited job quota, the expedited work request will
+ * we dropped and no work requests are enqueued.
+ */
+ DROP_WORK_REQUEST;
+}
diff --git a/work/workmanager/src/main/java/androidx/work/PeriodicWorkRequest.java b/work/workmanager/src/main/java/androidx/work/PeriodicWorkRequest.java
index 6fd553a..fb44604 100644
--- a/work/workmanager/src/main/java/androidx/work/PeriodicWorkRequest.java
+++ b/work/workmanager/src/main/java/androidx/work/PeriodicWorkRequest.java
@@ -189,12 +189,6 @@
throw new IllegalArgumentException(
"Cannot set backoff criteria on an idle mode job");
}
- if (mWorkSpec.runInForeground
- && Build.VERSION.SDK_INT >= 23
- && mWorkSpec.constraints.requiresDeviceIdle()) {
- throw new IllegalArgumentException(
- "Cannot run in foreground with an idle mode constraint");
- }
return new PeriodicWorkRequest(this);
}
diff --git a/work/workmanager/src/main/java/androidx/work/WorkRequest.java b/work/workmanager/src/main/java/androidx/work/WorkRequest.java
index 25fed73..f54f2f4 100644
--- a/work/workmanager/src/main/java/androidx/work/WorkRequest.java
+++ b/work/workmanager/src/main/java/androidx/work/WorkRequest.java
@@ -16,6 +16,7 @@
package androidx.work;
import android.annotation.SuppressLint;
+import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
@@ -289,12 +290,37 @@
}
/**
+ * Marks the {@link WorkRequest} as important to the user. In this case, WorkManager
+ * provides an additional signal to the OS that this work is important.
+ *
+ * @param policy The {@link OutOfQuotaPolicy} to be used.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull B setExpedited(@NonNull OutOfQuotaPolicy policy) {
+ mWorkSpec.expedited = true;
+ mWorkSpec.outOfQuotaPolicy = policy;
+ return getThis();
+ }
+
+ /**
* Builds a {@link WorkRequest} based on this {@link Builder}.
*
* @return A {@link WorkRequest} based on this {@link Builder}
*/
public final @NonNull W build() {
W returnValue = buildInternal();
+ Constraints constraints = mWorkSpec.constraints;
+ // Check for unsupported constraints.
+ boolean hasUnsupportedConstraints =
+ (Build.VERSION.SDK_INT >= 24 && constraints.hasContentUriTriggers())
+ || constraints.requiresBatteryNotLow()
+ || constraints.requiresCharging()
+ || (Build.VERSION.SDK_INT >= 23 && constraints.requiresDeviceIdle());
+
+ if (mWorkSpec.expedited && hasUnsupportedConstraints) {
+ throw new IllegalArgumentException(
+ "Expedited jobs only support network and storage constraints");
+ }
// Create a new id and WorkSpec so this WorkRequest.Builder can be used multiple times.
mId = UUID.randomUUID();
mWorkSpec = new WorkSpec(mWorkSpec);
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
index cccc41a..5073e66 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
@@ -75,7 +75,7 @@
WorkName.class,
WorkProgress.class,
Preference.class},
- version = 11)
+ version = 12)
@TypeConverters(value = {Data.class, WorkTypeConverters.class})
public abstract class WorkDatabase extends RoomDatabase {
// Delete rows in the workspec table that...
@@ -150,6 +150,7 @@
.addMigrations(
new WorkDatabaseMigrations.RescheduleMigration(context, VERSION_10,
VERSION_11))
+ .addMigrations(WorkDatabaseMigrations.MIGRATION_11_12)
.fallbackToDestructiveMigration()
.build();
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java
index 9261f37..7a1d045 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java
@@ -59,6 +59,7 @@
public static final int VERSION_9 = 9;
public static final int VERSION_10 = 10;
public static final int VERSION_11 = 11;
+ public static final int VERSION_12 = 12;
private static final String CREATE_SYSTEM_ID_INFO =
"CREATE TABLE IF NOT EXISTS `SystemIdInfo` (`work_spec_id` TEXT NOT NULL, `system_id`"
@@ -106,6 +107,9 @@
"CREATE TABLE IF NOT EXISTS `Preference` (`key` TEXT NOT NULL, `long_value` INTEGER, "
+ "PRIMARY KEY(`key`))";
+ private static final String CREATE_OUT_OF_QUOTA_POLICY =
+ "ALTER TABLE workspec ADD COLUMN `out_of_quota_policy` INTEGER NOT NULL DEFAULT 0";
+
/**
* Removes the {@code alarmInfo} table and substitutes it for a more general
* {@code SystemIdInfo} table.
@@ -228,4 +232,15 @@
IdGenerator.migrateLegacyIdGenerator(mContext, database);
}
}
+
+ /**
+ * Adds a notification_provider to the {@link WorkSpec}.
+ */
+ @NonNull
+ public static Migration MIGRATION_11_12 = new Migration(VERSION_11, VERSION_12) {
+ @Override
+ public void migrate(@NonNull SupportSQLiteDatabase database) {
+ database.execSQL(CREATE_OUT_OF_QUOTA_POLICY);
+ }
+ };
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java b/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
index 7328ba6..ed8718c 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
@@ -16,6 +16,7 @@
package androidx.work.impl;
+import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.text.TextUtils.isEmpty;
@@ -31,6 +32,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.arch.core.util.Function;
+import androidx.core.os.BuildCompat;
import androidx.lifecycle.LiveData;
import androidx.work.Configuration;
import androidx.work.ExistingPeriodicWorkPolicy;
@@ -475,7 +477,11 @@
@Override
public PendingIntent createCancelPendingIntent(@NonNull UUID id) {
Intent intent = createCancelWorkIntent(mContext, id.toString());
- return PendingIntent.getService(mContext, 0, intent, FLAG_UPDATE_CURRENT);
+ int flags = FLAG_UPDATE_CURRENT;
+ if (BuildCompat.isAtLeastS()) {
+ flags |= FLAG_MUTABLE;
+ }
+ return PendingIntent.getService(mContext, 0, intent, flags);
}
@Override
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
index 26654a4..12b8eee 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
@@ -48,6 +48,7 @@
import androidx.work.impl.model.WorkSpecDao;
import androidx.work.impl.model.WorkTagDao;
import androidx.work.impl.utils.PackageManagerHelper;
+import androidx.work.impl.utils.WorkForegroundRunnable;
import androidx.work.impl.utils.WorkForegroundUpdater;
import androidx.work.impl.utils.WorkProgressUpdater;
import androidx.work.impl.utils.futures.SettableFuture;
@@ -82,13 +83,13 @@
// Avoid Synthetic accessor
WorkSpec mWorkSpec;
ListenableWorker mWorker;
+ TaskExecutor mWorkTaskExecutor;
// Package-private for synthetic accessor.
@NonNull
ListenableWorker.Result mResult = ListenableWorker.Result.failure();
private Configuration mConfiguration;
- private TaskExecutor mWorkTaskExecutor;
private ForegroundProcessor mForegroundProcessor;
private WorkDatabase mWorkDatabase;
private WorkSpecDao mWorkSpecDao;
@@ -226,7 +227,7 @@
input = inputMerger.merge(inputs);
}
- WorkerParameters params = new WorkerParameters(
+ final WorkerParameters params = new WorkerParameters(
UUID.fromString(mWorkSpecId),
input,
mTags,
@@ -272,22 +273,32 @@
}
final SettableFuture<ListenableWorker.Result> future = SettableFuture.create();
- // Call mWorker.startWork() on the main thread.
- mWorkTaskExecutor.getMainThreadExecutor()
- .execute(new Runnable() {
- @Override
- public void run() {
- try {
- Logger.get().debug(TAG, String.format("Starting work for %s",
- mWorkSpec.workerClassName));
- mInnerFuture = mWorker.startWork();
- future.setFuture(mInnerFuture);
- } catch (Throwable e) {
- future.setException(e);
- }
+ final WorkForegroundRunnable foregroundRunnable =
+ new WorkForegroundRunnable(
+ mAppContext,
+ mWorkSpec,
+ mWorker,
+ params.getForegroundUpdater(),
+ mWorkTaskExecutor
+ );
+ mWorkTaskExecutor.getMainThreadExecutor().execute(foregroundRunnable);
- }
- });
+ final ListenableFuture<Void> runExpedited = foregroundRunnable.getFuture();
+ runExpedited.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ runExpedited.get();
+ Logger.get().debug(TAG,
+ String.format("Starting work for %s", mWorkSpec.workerClassName));
+ // Call mWorker.startWork() on the main thread.
+ mInnerFuture = mWorker.startWork();
+ future.setFuture(mInnerFuture);
+ } catch (Throwable e) {
+ future.setException(e);
+ }
+ }
+ }, mWorkTaskExecutor.getMainThreadExecutor());
// Avoid synthetic accessors.
final String workDescription = mWorkDescription;
@@ -681,6 +692,7 @@
/**
* @return The instance of {@link WorkerWrapper}.
*/
+ @NonNull
public WorkerWrapper build() {
return new WorkerWrapper(this);
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java b/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java
index 2541438..02df55e 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java
@@ -30,6 +30,7 @@
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
+import androidx.core.os.BuildCompat;
import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
import androidx.work.ContentUriTriggers;
@@ -65,7 +66,7 @@
* Note: All {@link JobInfo} are set to persist on reboot.
*
* @param workSpec The {@link WorkSpec} to convert
- * @param jobId The {@code jobId} to use. This is useful when de-duping jobs on reschedule.
+ * @param jobId The {@code jobId} to use. This is useful when de-duping jobs on reschedule.
* @return The {@link JobInfo} representing the same information as the {@link WorkSpec}
*/
JobInfo convert(WorkSpec workSpec, int jobId) {
@@ -96,11 +97,12 @@
// always setMinimumLatency to make sure we have at least one constraint.
// See aosp/5434530 & b/6771687
builder.setMinimumLatency(offset);
- } else {
+ } else {
if (offset > 0) {
// Only set a minimum latency when applicable.
builder.setMinimumLatency(offset);
- } else {
+ } else if (!workSpec.expedited) {
+ // Only set this if the workSpec is not expedited.
builder.setImportantWhileForeground(true);
}
}
@@ -121,6 +123,12 @@
builder.setRequiresBatteryNotLow(constraints.requiresBatteryNotLow());
builder.setRequiresStorageNotLow(constraints.requiresStorageNotLow());
}
+ // Retries cannot be expedited jobs, given they will occur at some point in the future.
+ boolean isRetry = workSpec.runAttemptCount > 0;
+ if (BuildCompat.isAtLeastS() && workSpec.expedited && !isRetry) {
+ //noinspection NewApi
+ builder.setExpedited(true);
+ }
return builder.build();
}
@@ -161,7 +169,7 @@
*/
@SuppressWarnings("MissingCasesInEnumSwitch")
static int convertNetworkType(NetworkType networkType) {
- switch(networkType) {
+ switch (networkType) {
case NOT_REQUIRED:
return JobInfo.NETWORK_TYPE_NONE;
case CONNECTED:
diff --git a/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java b/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java
index 6e39078..dcbb0d5e 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java
@@ -17,6 +17,7 @@
import static android.content.Context.JOB_SCHEDULER_SERVICE;
+import static androidx.work.OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST;
import static androidx.work.impl.background.systemjob.SystemJobInfoConverter.EXTRA_WORK_SPEC_ID;
import static androidx.work.impl.model.WorkSpec.SCHEDULE_NOT_REQUESTED_YET;
@@ -183,7 +184,20 @@
TAG,
String.format("Scheduling work ID %s Job ID %s", workSpec.id, jobId));
try {
- mJobScheduler.schedule(jobInfo);
+ int result = mJobScheduler.schedule(jobInfo);
+ if (result == JobScheduler.RESULT_FAILURE) {
+ Logger.get()
+ .warning(TAG, String.format("Unable to schedule work ID %s", workSpec.id));
+ if (workSpec.expedited
+ && workSpec.outOfQuotaPolicy == RUN_AS_NON_EXPEDITED_WORK_REQUEST) {
+ // Falling back to a non-expedited job.
+ workSpec.expedited = false;
+ String message = String.format(
+ "Scheduling a non-expedited job (work ID %s)", workSpec.id);
+ Logger.get().debug(TAG, message);
+ scheduleInternal(workSpec, jobId);
+ }
+ }
} catch (IllegalStateException e) {
// This only gets thrown if we exceed 100 jobs. Let's figure out if WorkManager is
// responsible for all these jobs.
diff --git a/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java b/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java
index 86bfa80..245f432 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java
@@ -36,6 +36,7 @@
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.Logger;
+import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkInfo;
import androidx.work.WorkRequest;
@@ -129,10 +130,19 @@
public long scheduleRequestedAt = SCHEDULE_NOT_REQUESTED_YET;
/**
- * This is {@code true} when the WorkSpec needs to be hosted by a foreground service.
+ * This is {@code true} when the WorkSpec needs to be hosted by a foreground service or a
+ * high priority job.
*/
@ColumnInfo(name = "run_in_foreground")
- public boolean runInForeground;
+ public boolean expedited;
+
+ /**
+ * When set to <code>true</code> this {@link WorkSpec} falls back to a regular job when
+ * an application runs out of expedited job quota.
+ */
+ @NonNull
+ @ColumnInfo(name = "out_of_quota_policy")
+ public OutOfQuotaPolicy outOfQuotaPolicy = OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST;
public WorkSpec(@NonNull String id, @NonNull String workerClassName) {
this.id = id;
@@ -156,7 +166,8 @@
periodStartTime = other.periodStartTime;
minimumRetentionDuration = other.minimumRetentionDuration;
scheduleRequestedAt = other.scheduleRequestedAt;
- runInForeground = other.runInForeground;
+ expedited = other.expedited;
+ outOfQuotaPolicy = other.outOfQuotaPolicy;
}
/**
@@ -174,7 +185,6 @@
this.backoffDelayDuration = backoffDelayDuration;
}
-
public boolean isPeriodic() {
return intervalDuration != 0L;
}
@@ -301,7 +311,7 @@
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (!(o instanceof WorkSpec)) return false;
+ if (o == null || getClass() != o.getClass()) return false;
WorkSpec workSpec = (WorkSpec) o;
@@ -313,7 +323,7 @@
if (periodStartTime != workSpec.periodStartTime) return false;
if (minimumRetentionDuration != workSpec.minimumRetentionDuration) return false;
if (scheduleRequestedAt != workSpec.scheduleRequestedAt) return false;
- if (runInForeground != workSpec.runInForeground) return false;
+ if (expedited != workSpec.expedited) return false;
if (!id.equals(workSpec.id)) return false;
if (state != workSpec.state) return false;
if (!workerClassName.equals(workSpec.workerClassName)) return false;
@@ -325,7 +335,8 @@
if (!input.equals(workSpec.input)) return false;
if (!output.equals(workSpec.output)) return false;
if (!constraints.equals(workSpec.constraints)) return false;
- return backoffPolicy == workSpec.backoffPolicy;
+ if (backoffPolicy != workSpec.backoffPolicy) return false;
+ return outOfQuotaPolicy == workSpec.outOfQuotaPolicy;
}
@Override
@@ -346,7 +357,8 @@
result = 31 * result + (int) (periodStartTime ^ (periodStartTime >>> 32));
result = 31 * result + (int) (minimumRetentionDuration ^ (minimumRetentionDuration >>> 32));
result = 31 * result + (int) (scheduleRequestedAt ^ (scheduleRequestedAt >>> 32));
- result = 31 * result + (runInForeground ? 1 : 0);
+ result = 31 * result + (expedited ? 1 : 0);
+ result = 31 * result + outOfQuotaPolicy.hashCode();
return result;
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/model/WorkTypeConverters.java b/work/workmanager/src/main/java/androidx/work/impl/model/WorkTypeConverters.java
index fb15ba8..f60ac02 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/model/WorkTypeConverters.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/model/WorkTypeConverters.java
@@ -28,10 +28,12 @@
import android.net.Uri;
import android.os.Build;
+import androidx.annotation.NonNull;
import androidx.room.TypeConverter;
import androidx.work.BackoffPolicy;
import androidx.work.ContentUriTriggers;
import androidx.work.NetworkType;
+import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkInfo;
import java.io.ByteArrayInputStream;
@@ -81,6 +83,14 @@
}
/**
+ * Integer identifiers that map to {@link OutOfQuotaPolicy}.
+ */
+ public interface OutOfPolicyIds {
+ int RUN_AS_NON_EXPEDITED_WORK_REQUEST = 0;
+ int DROP_WORK_REQUEST = 1;
+ }
+
+ /**
* TypeConverter for a State to an int.
*
* @param state The input State
@@ -257,6 +267,45 @@
}
/**
+ * Converts a {@link OutOfQuotaPolicy} to an int.
+ *
+ * @param policy The {@link OutOfQuotaPolicy} policy being used
+ * @return the corresponding int representation.
+ */
+ @TypeConverter
+ public static int outOfQuotaPolicyToInt(@NonNull OutOfQuotaPolicy policy) {
+ switch (policy) {
+ case RUN_AS_NON_EXPEDITED_WORK_REQUEST:
+ return OutOfPolicyIds.RUN_AS_NON_EXPEDITED_WORK_REQUEST;
+ case DROP_WORK_REQUEST:
+ return OutOfPolicyIds.DROP_WORK_REQUEST;
+ default:
+ throw new IllegalArgumentException(
+ "Could not convert " + policy + " to int");
+ }
+ }
+
+ /**
+ * Converter from an int to a {@link OutOfQuotaPolicy}.
+ *
+ * @param value The input integer
+ * @return An {@link OutOfQuotaPolicy}
+ */
+ @TypeConverter
+ @NonNull
+ public static OutOfQuotaPolicy intToOutOfQuotaPolicy(int value) {
+ switch (value) {
+ case OutOfPolicyIds.RUN_AS_NON_EXPEDITED_WORK_REQUEST:
+ return OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST;
+ case OutOfPolicyIds.DROP_WORK_REQUEST:
+ return OutOfQuotaPolicy.DROP_WORK_REQUEST;
+ default:
+ throw new IllegalArgumentException(
+ "Could not convert " + value + " to OutOfQuotaPolicy");
+ }
+ }
+
+ /**
* Converts a list of {@link ContentUriTriggers.Trigger}s to byte array representation
* @param triggers the list of {@link ContentUriTriggers.Trigger}s to convert
* @return corresponding byte array representation
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java b/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
index 4a31178..fb6517f 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
@@ -17,13 +17,18 @@
package androidx.work.impl.utils;
import static android.app.AlarmManager.RTC_WAKEUP;
+import static android.app.ApplicationExitInfo.REASON_USER_REQUESTED;
+import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_NO_CREATE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static androidx.work.WorkInfo.State.ENQUEUED;
import static androidx.work.impl.model.WorkSpec.SCHEDULE_NOT_REQUESTED_YET;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.ApplicationExitInfo;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -35,11 +40,13 @@
import android.database.sqlite.SQLiteDatabaseLockedException;
import android.database.sqlite.SQLiteTableLockedException;
import android.os.Build;
+import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
+import androidx.core.os.BuildCompat;
import androidx.work.Configuration;
import androidx.work.InitializationExceptionHandler;
import androidx.work.Logger;
@@ -149,24 +156,53 @@
* @return {@code true} If the application was force stopped.
*/
@VisibleForTesting
+ @SuppressLint("ClassVerificationFailure")
public boolean isForceStopped() {
// Alarms get cancelled when an app is force-stopped starting at Eclair MR1.
// Cancelling of Jobs on force-stop was introduced in N-MR1 (SDK 25).
// Even though API 23, 24 are probably safe, OEMs may choose to do
// something different.
try {
- PendingIntent pendingIntent = getPendingIntent(mContext, FLAG_NO_CREATE);
- if (pendingIntent == null) {
+ int flags = FLAG_NO_CREATE;
+ if (BuildCompat.isAtLeastS()) {
+ flags |= FLAG_MUTABLE;
+ }
+ PendingIntent pendingIntent = getPendingIntent(mContext, flags);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ // We no longer need the alarm.
+ if (pendingIntent != null) {
+ pendingIntent.cancel();
+ }
+ ActivityManager activityManager =
+ (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ List<ApplicationExitInfo> exitInfoList =
+ activityManager.getHistoricalProcessExitReasons(
+ null /* match caller uid */,
+ 0, // ignore
+ 0 // ignore
+ );
+
+ if (exitInfoList != null && !exitInfoList.isEmpty()) {
+ for (int i = 0; i < exitInfoList.size(); i++) {
+ ApplicationExitInfo info = exitInfoList.get(i);
+ if (info.getReason() == REASON_USER_REQUESTED) {
+ return true;
+ }
+ }
+ }
+ } else if (pendingIntent == null) {
setAlarm(mContext);
return true;
- } else {
- return false;
}
- } catch (SecurityException exception) {
+ return false;
+ } catch (SecurityException | IllegalArgumentException exception) {
+ // b/189975360 Some Samsung Devices seem to throw an IllegalArgumentException :( on
+ // API 30.
+
// Setting Alarms on some devices fails due to OEM introduced bugs in AlarmManager.
// When this happens, there is not much WorkManager can do, other can reschedule
// everything.
- Logger.get().warning(TAG, "Ignoring security exception", exception);
+ Logger.get().warning(TAG, "Ignoring exception", exception);
return true;
}
}
@@ -202,6 +238,7 @@
*
* @return {@code true} if there are WorkSpecs that need rescheduling.
*/
+ @SuppressWarnings("deprecation")
@VisibleForTesting
public boolean cleanUp() {
boolean needsReconciling = false;
@@ -258,6 +295,14 @@
// But ForceStopRunnable causes a lot of multi-process contention on the underlying
// SQLite datastore. Therefore we only initialize WorkManager in the default app-process.
Configuration configuration = mWorkManager.getConfiguration();
+ // Check if the application specified a default process name. If they did not, we want to
+ // run ForceStopRunnable in every app process. This is safer for apps with multiple
+ // processes. There is risk of SQLite contention and that might result in a crash, but an
+ // actual crash is better than decreased throughput for WorkRequests.
+ if (TextUtils.isEmpty(configuration.getDefaultProcessName())) {
+ Logger.get().debug(TAG, "The default process name was not specified.");
+ return true;
+ }
boolean isDefaultProcess = ProcessUtils.isDefaultProcess(mContext, configuration);
Logger.get().debug(TAG, String.format("Is default app process = %s", isDefaultProcess));
return isDefaultProcess;
@@ -296,10 +341,15 @@
return intent;
}
+ @SuppressLint("ClassVerificationFailure")
static void setAlarm(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Using FLAG_UPDATE_CURRENT, because we only ever want once instance of this alarm.
- PendingIntent pendingIntent = getPendingIntent(context, FLAG_UPDATE_CURRENT);
+ int flags = FLAG_UPDATE_CURRENT;
+ if (BuildCompat.isAtLeastS()) {
+ flags |= FLAG_MUTABLE;
+ }
+ PendingIntent pendingIntent = getPendingIntent(context, flags);
long triggerAt = System.currentTimeMillis() + TEN_YEARS;
if (alarmManager != null) {
if (Build.VERSION.SDK_INT >= 19) {
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/WorkForegroundRunnable.java b/work/workmanager/src/main/java/androidx/work/impl/utils/WorkForegroundRunnable.java
new file mode 100644
index 0000000..dad9d9d
--- /dev/null
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/WorkForegroundRunnable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work.impl.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.os.BuildCompat;
+import androidx.work.ForegroundInfo;
+import androidx.work.ForegroundUpdater;
+import androidx.work.ListenableWorker;
+import androidx.work.Logger;
+import androidx.work.impl.model.WorkSpec;
+import androidx.work.impl.utils.futures.SettableFuture;
+import androidx.work.impl.utils.taskexecutor.TaskExecutor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class WorkForegroundRunnable implements Runnable {
+
+ // Synthetic access
+ static final String TAG = Logger.tagWithPrefix("WorkForegroundRunnable");
+
+ final SettableFuture<Void> mFuture;
+
+ final Context mContext;
+ final WorkSpec mWorkSpec;
+ final ListenableWorker mWorker;
+ final ForegroundUpdater mForegroundUpdater;
+ final TaskExecutor mTaskExecutor;
+
+ @SuppressLint("LambdaLast")
+ public WorkForegroundRunnable(
+ @NonNull Context context,
+ @NonNull WorkSpec workSpec,
+ @NonNull ListenableWorker worker,
+ @NonNull ForegroundUpdater foregroundUpdater,
+ @NonNull TaskExecutor taskExecutor) {
+
+ mFuture = SettableFuture.create();
+ mContext = context;
+ mWorkSpec = workSpec;
+ mWorker = worker;
+ mForegroundUpdater = foregroundUpdater;
+ mTaskExecutor = taskExecutor;
+ }
+
+ @NonNull
+ public ListenableFuture<Void> getFuture() {
+ return mFuture;
+ }
+
+ @Override
+ @SuppressLint("UnsafeExperimentalUsageError")
+ public void run() {
+ if (!mWorkSpec.expedited || BuildCompat.isAtLeastS()) {
+ mFuture.set(null);
+ return;
+ }
+
+ final SettableFuture<ForegroundInfo> foregroundFuture = SettableFuture.create();
+ mTaskExecutor.getMainThreadExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ foregroundFuture.setFuture(mWorker.getForegroundInfoAsync());
+ }
+ });
+
+ foregroundFuture.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ ForegroundInfo foregroundInfo = foregroundFuture.get();
+ if (foregroundInfo == null) {
+ String message =
+ String.format("Worker was marked important (%s) but did not "
+ + "provide ForegroundInfo", mWorkSpec.workerClassName);
+ throw new IllegalStateException(message);
+ }
+ Logger.get().debug(TAG, String.format("Updating notification for %s",
+ mWorkSpec.workerClassName));
+ // Mark as running in the foreground
+ mWorker.setRunInForeground(true);
+ mFuture.setFuture(
+ mForegroundUpdater.setForegroundAsync(
+ mContext, mWorker.getId(), foregroundInfo));
+ } catch (Throwable throwable) {
+ mFuture.setException(throwable);
+ }
+ }
+ }, mTaskExecutor.getMainThreadExecutor());
+ }
+}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/WorkForegroundUpdater.java b/work/workmanager/src/main/java/androidx/work/impl/utils/WorkForegroundUpdater.java
index 8e0ac60..743ae88 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/utils/WorkForegroundUpdater.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/WorkForegroundUpdater.java
@@ -25,6 +25,7 @@
import androidx.annotation.RestrictTo;
import androidx.work.ForegroundInfo;
import androidx.work.ForegroundUpdater;
+import androidx.work.Logger;
import androidx.work.WorkInfo;
import androidx.work.impl.WorkDatabase;
import androidx.work.impl.foreground.ForegroundProcessor;
@@ -46,6 +47,8 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class WorkForegroundUpdater implements ForegroundUpdater {
+ private static final String TAG = Logger.tagWithPrefix("WMFgUpdater");
+
private final TaskExecutor mTaskExecutor;
// Synthetic access
@@ -92,6 +95,8 @@
}
// startForeground() is idempotent
+ // NOTE: This will fail when the process is subject to foreground service
+ // restrictions. Propagate the exception to the caller.
mForegroundProcessor.startForeground(workSpecId, foregroundInfo);
Intent intent = createNotifyIntent(context, workSpecId, foregroundInfo);
context.startService(intent);
diff --git a/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/12.json b/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/12.json
new file mode 100644
index 0000000..dc1d4dd
--- /dev/null
+++ b/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/12.json
@@ -0,0 +1,460 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 12,
+ "identityHash": "c103703e120ae8cc73c9248622f3cd1e",
+ "entities": [
+ {
+ "tableName": "Dependency",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`work_spec_id` TEXT NOT NULL, `prerequisite_id` TEXT NOT NULL, PRIMARY KEY(`work_spec_id`, `prerequisite_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`prerequisite_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "prerequisiteId",
+ "columnName": "prerequisite_id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "work_spec_id",
+ "prerequisite_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_Dependency_work_spec_id",
+ "unique": false,
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_Dependency_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)"
+ },
+ {
+ "name": "index_Dependency_prerequisite_id",
+ "unique": false,
+ "columnNames": [
+ "prerequisite_id"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_Dependency_prerequisite_id` ON `${TABLE_NAME}` (`prerequisite_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "prerequisite_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "WorkSpec",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `state` INTEGER NOT NULL, `worker_class_name` TEXT NOT NULL, `input_merger_class_name` TEXT, `input` BLOB NOT NULL, `output` BLOB NOT NULL, `initial_delay` INTEGER NOT NULL, `interval_duration` INTEGER NOT NULL, `flex_duration` INTEGER NOT NULL, `run_attempt_count` INTEGER NOT NULL, `backoff_policy` INTEGER NOT NULL, `backoff_delay_duration` INTEGER NOT NULL, `period_start_time` INTEGER NOT NULL, `minimum_retention_duration` INTEGER NOT NULL, `schedule_requested_at` INTEGER NOT NULL, `run_in_foreground` INTEGER NOT NULL, `out_of_quota_policy` INTEGER NOT NULL, `required_network_type` INTEGER, `requires_charging` INTEGER NOT NULL, `requires_device_idle` INTEGER NOT NULL, `requires_battery_not_low` INTEGER NOT NULL, `requires_storage_not_low` INTEGER NOT NULL, `trigger_content_update_delay` INTEGER NOT NULL, `trigger_max_content_delay` INTEGER NOT NULL, `content_uri_triggers` BLOB, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "state",
+ "columnName": "state",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "workerClassName",
+ "columnName": "worker_class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "inputMergerClassName",
+ "columnName": "input_merger_class_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "input",
+ "columnName": "input",
+ "affinity": "BLOB",
+ "notNull": true
+ },
+ {
+ "fieldPath": "output",
+ "columnName": "output",
+ "affinity": "BLOB",
+ "notNull": true
+ },
+ {
+ "fieldPath": "initialDelay",
+ "columnName": "initial_delay",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "intervalDuration",
+ "columnName": "interval_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "flexDuration",
+ "columnName": "flex_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "runAttemptCount",
+ "columnName": "run_attempt_count",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "backoffPolicy",
+ "columnName": "backoff_policy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "backoffDelayDuration",
+ "columnName": "backoff_delay_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "periodStartTime",
+ "columnName": "period_start_time",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "minimumRetentionDuration",
+ "columnName": "minimum_retention_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "scheduleRequestedAt",
+ "columnName": "schedule_requested_at",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expedited",
+ "columnName": "run_in_foreground",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "outOfQuotaPolicy",
+ "columnName": "out_of_quota_policy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiredNetworkType",
+ "columnName": "required_network_type",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "constraints.mRequiresCharging",
+ "columnName": "requires_charging",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiresDeviceIdle",
+ "columnName": "requires_device_idle",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiresBatteryNotLow",
+ "columnName": "requires_battery_not_low",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiresStorageNotLow",
+ "columnName": "requires_storage_not_low",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mTriggerContentUpdateDelay",
+ "columnName": "trigger_content_update_delay",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mTriggerMaxContentDelay",
+ "columnName": "trigger_max_content_delay",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mContentUriTriggers",
+ "columnName": "content_uri_triggers",
+ "affinity": "BLOB",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_WorkSpec_schedule_requested_at",
+ "unique": false,
+ "columnNames": [
+ "schedule_requested_at"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_WorkSpec_schedule_requested_at` ON `${TABLE_NAME}` (`schedule_requested_at`)"
+ },
+ {
+ "name": "index_WorkSpec_period_start_time",
+ "unique": false,
+ "columnNames": [
+ "period_start_time"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_WorkSpec_period_start_time` ON `${TABLE_NAME}` (`period_start_time`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "WorkTag",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `work_spec_id` TEXT NOT NULL, PRIMARY KEY(`tag`, `work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "tag",
+ "work_spec_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_WorkTag_work_spec_id",
+ "unique": false,
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_WorkTag_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "SystemIdInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`work_spec_id` TEXT NOT NULL, `system_id` INTEGER NOT NULL, PRIMARY KEY(`work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "systemId",
+ "columnName": "system_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "WorkName",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `work_spec_id` TEXT NOT NULL, PRIMARY KEY(`name`, `work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "name",
+ "work_spec_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_WorkName_work_spec_id",
+ "unique": false,
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_WorkName_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "WorkProgress",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`work_spec_id` TEXT NOT NULL, `progress` BLOB NOT NULL, PRIMARY KEY(`work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "mWorkSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mProgress",
+ "columnName": "progress",
+ "affinity": "BLOB",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "Preference",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `long_value` INTEGER, PRIMARY KEY(`key`))",
+ "fields": [
+ {
+ "fieldPath": "mKey",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mValue",
+ "columnName": "long_value",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "key"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c103703e120ae8cc73c9248622f3cd1e')"
+ ]
+ }
+}
\ No newline at end of file